blob: 48153bd5ffbb8a9b0c8bf09124c6f885f74587e9 [file] [log] [blame]
Tom Rinif739fcd2018-05-07 17:02:21 -04001// SPDX-License-Identifier: GPL-2.0+
Rob Clark9975fe92017-09-13 18:05:38 -04002/*
Heinrich Schuchardte1fec152018-10-18 21:51:38 +02003 * EFI boot manager
Rob Clark9975fe92017-09-13 18:05:38 -04004 *
5 * Copyright (c) 2017 Rob Clark
Rob Clark9975fe92017-09-13 18:05:38 -04006 */
7
Heinrich Schuchardt7a373e52020-05-31 10:07:31 +02008#define LOG_CATEGORY LOGC_EFI
9
Masahisa Kojimad7d07a82023-11-10 13:25:40 +090010#include <blk.h>
11#include <blkmap.h>
Rob Clark9975fe92017-09-13 18:05:38 -040012#include <common.h>
13#include <charset.h>
Masahisa Kojimad7d07a82023-11-10 13:25:40 +090014#include <dm.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060015#include <log.h>
Rob Clark9975fe92017-09-13 18:05:38 -040016#include <malloc.h>
Masahisa Kojimad7d07a82023-11-10 13:25:40 +090017#include <net.h>
AKASHI Takahiro4e65ca02022-04-28 17:09:39 +090018#include <efi_default_filename.h>
Rob Clark9975fe92017-09-13 18:05:38 -040019#include <efi_loader.h>
Heinrich Schuchardtdda8c712020-06-24 19:09:18 +020020#include <efi_variable.h>
AKASHI Takahiro1a82b342018-11-05 18:06:41 +090021#include <asm/unaligned.h>
Rob Clark9975fe92017-09-13 18:05:38 -040022
23static const struct efi_boot_services *bs;
24static const struct efi_runtime_services *rs;
25
Masahisa Kojimad7d07a82023-11-10 13:25:40 +090026/**
27 * struct uridp_context - uri device path resource
28 *
29 * @image_size: image size
30 * @image_addr: image address
31 * @loaded_dp: pointer to loaded device path
32 * @ramdisk_blk_dev: pointer to the ramdisk blk device
33 * @mem_handle: efi_handle to the loaded PE-COFF image
34 */
35struct uridp_context {
36 ulong image_size;
37 ulong image_addr;
38 struct efi_device_path *loaded_dp;
39 struct udevice *ramdisk_blk_dev;
40 efi_handle_t mem_handle;
41};
42
Masahisa Kojima87d79142022-09-12 17:33:50 +090043const efi_guid_t efi_guid_bootmenu_auto_generated =
44 EFICONFIG_AUTO_GENERATED_ENTRY_GUID;
45
Rob Clark9975fe92017-09-13 18:05:38 -040046/*
47 * bootmgr implements the logic of trying to find a payload to boot
48 * based on the BootOrder + BootXXXX variables, and then loading it.
49 *
50 * TODO detecting a special key held (f9?) and displaying a boot menu
51 * like you would get on a PC would be clever.
52 *
53 * TODO if we had a way to write and persist variables after the OS
54 * has started, we'd also want to check OsIndications to see if we
55 * should do normal or recovery boot.
56 */
57
Heinrich Schuchardt1064d042020-08-07 17:47:13 +020058/**
AKASHI Takahiro4e65ca02022-04-28 17:09:39 +090059 * expand_media_path() - expand a device path for default file name
60 * @device_path: device path to check against
61 *
62 * If @device_path is a media or disk partition which houses a file
63 * system, this function returns a full device path which contains
64 * an architecture-specific default file name for removable media.
65 *
66 * Return: a newly allocated device path
67 */
68static
69struct efi_device_path *expand_media_path(struct efi_device_path *device_path)
70{
Heinrich Schuchardtc7c0ca32023-05-13 10:36:21 +020071 struct efi_device_path *rem, *full_path;
AKASHI Takahiro4e65ca02022-04-28 17:09:39 +090072 efi_handle_t handle;
AKASHI Takahiro4e65ca02022-04-28 17:09:39 +090073
74 if (!device_path)
75 return NULL;
76
77 /*
78 * If device_path is a (removable) media or partition which provides
79 * simple file system protocol, append a default file name to support
80 * booting from removable media.
81 */
Heinrich Schuchardtc7c0ca32023-05-13 10:36:21 +020082 handle = efi_dp_find_obj(device_path,
83 &efi_simple_file_system_protocol_guid, &rem);
Heinrich Schuchardt72fa9cd2022-06-11 05:22:08 +000084 if (handle) {
Heinrich Schuchardt178667b2022-06-11 05:22:07 +000085 if (rem->type == DEVICE_PATH_TYPE_END) {
Heinrich Schuchardtc7c0ca32023-05-13 10:36:21 +020086 full_path = efi_dp_from_file(device_path,
87 "/EFI/BOOT/" BOOTEFI_NAME);
AKASHI Takahiro4e65ca02022-04-28 17:09:39 +090088 } else {
89 full_path = efi_dp_dup(device_path);
90 }
91 } else {
92 full_path = efi_dp_dup(device_path);
93 }
94
95 return full_path;
96}
97
98/**
AKASHI Takahiro57ad6242022-05-12 11:29:02 +090099 * try_load_from_file_path() - try to load a file
100 *
101 * Given a file media path iterate through a list of handles and try to
102 * to load the file from each of them until the first success.
103 *
104 * @fs_handles: array of handles with the simple file protocol
105 * @num: number of handles in fs_handles
106 * @fp: file path to open
107 * @handle: on return pointer to handle for loaded image
108 * @removable: if true only consider removable media, else only non-removable
109 */
110static efi_status_t try_load_from_file_path(efi_handle_t *fs_handles,
111 efi_uintn_t num,
112 struct efi_device_path *fp,
113 efi_handle_t *handle,
114 bool removable)
115{
116 struct efi_handler *handler;
117 struct efi_device_path *dp;
118 int i;
119 efi_status_t ret;
120
121 for (i = 0; i < num; i++) {
122 if (removable != efi_disk_is_removable(fs_handles[i]))
123 continue;
124
125 ret = efi_search_protocol(fs_handles[i], &efi_guid_device_path,
126 &handler);
127 if (ret != EFI_SUCCESS)
128 continue;
129
130 dp = handler->protocol_interface;
131 if (!dp)
132 continue;
133
134 dp = efi_dp_append(dp, fp);
135 if (!dp)
136 continue;
137
138 ret = EFI_CALL(efi_load_image(true, efi_root, dp, NULL, 0,
139 handle));
140 efi_free_pool(dp);
141 if (ret == EFI_SUCCESS)
142 return ret;
143 }
144
145 return EFI_NOT_FOUND;
146}
147
148/**
149 * try_load_from_short_path
150 * @fp: file path
151 * @handle: pointer to handle for newly installed image
152 *
153 * Enumerate all the devices which support file system operations,
154 * prepend its media device path to the file path, @fp, and
155 * try to load the file.
156 * This function should be called when handling a short-form path
157 * which is starting with a file device path.
158 *
159 * Return: status code
160 */
161static efi_status_t try_load_from_short_path(struct efi_device_path *fp,
162 efi_handle_t *handle)
163{
164 efi_handle_t *fs_handles;
165 efi_uintn_t num;
166 efi_status_t ret;
167
168 ret = EFI_CALL(efi_locate_handle_buffer(
169 BY_PROTOCOL,
170 &efi_simple_file_system_protocol_guid,
171 NULL,
172 &num, &fs_handles));
173 if (ret != EFI_SUCCESS)
174 return ret;
175 if (!num)
176 return EFI_NOT_FOUND;
177
178 /* removable media first */
179 ret = try_load_from_file_path(fs_handles, num, fp, handle, true);
180 if (ret == EFI_SUCCESS)
181 goto out;
182
183 /* fixed media */
184 ret = try_load_from_file_path(fs_handles, num, fp, handle, false);
185 if (ret == EFI_SUCCESS)
186 goto out;
187
188out:
189 return ret;
190}
191
192/**
Masahisa Kojimad7d07a82023-11-10 13:25:40 +0900193 * mount_image() - mount the image with blkmap
194 *
195 * @lo_label: u16 label string of load option
196 * @addr: image address
197 * @size: image size
198 * Return: pointer to the UCLASS_BLK udevice, NULL if failed
199 */
200static struct udevice *mount_image(u16 *lo_label, ulong addr, ulong size)
201{
202 int err;
203 struct blkmap *bm;
204 struct udevice *bm_dev;
205 char *label = NULL, *p;
206
207 label = efi_alloc(utf16_utf8_strlen(lo_label) + 1);
208 if (!label)
209 return NULL;
210
211 p = label;
212 utf16_utf8_strcpy(&p, lo_label);
213 err = blkmap_create_ramdisk(label, addr, size, &bm_dev);
214 if (err) {
215 efi_free_pool(label);
216 return NULL;
217 }
218 bm = dev_get_plat(bm_dev);
219
220 efi_free_pool(label);
221
222 return bm->blk;
223}
224
225/**
226 * search_default_file() - search default file
227 *
228 * @dev: pointer to the UCLASS_BLK or UCLASS_PARTITION udevice
229 * @loaded_dp: pointer to default file device path
230 * Return: status code
231 */
232static efi_status_t search_default_file(struct udevice *dev,
233 struct efi_device_path **loaded_dp)
234{
235 efi_status_t ret;
236 efi_handle_t handle;
237 u16 *default_file_name = NULL;
238 struct efi_file_handle *root, *f;
239 struct efi_device_path *dp = NULL, *fp = NULL;
240 struct efi_simple_file_system_protocol *file_system;
241 struct efi_device_path *device_path, *full_path = NULL;
242
243 if (dev_tag_get_ptr(dev, DM_TAG_EFI, (void **)&handle)) {
244 log_warning("DM_TAG_EFI not found\n");
245 return EFI_INVALID_PARAMETER;
246 }
247
248 ret = EFI_CALL(bs->open_protocol(handle, &efi_guid_device_path,
249 (void **)&device_path, efi_root, NULL,
250 EFI_OPEN_PROTOCOL_GET_PROTOCOL));
251 if (ret != EFI_SUCCESS)
252 return ret;
253
254 ret = EFI_CALL(bs->open_protocol(handle, &efi_simple_file_system_protocol_guid,
255 (void **)&file_system, efi_root, NULL,
256 EFI_OPEN_PROTOCOL_GET_PROTOCOL));
257 if (ret != EFI_SUCCESS)
258 return ret;
259
260 ret = EFI_CALL(file_system->open_volume(file_system, &root));
261 if (ret != EFI_SUCCESS)
262 return ret;
263
264 full_path = expand_media_path(device_path);
265 ret = efi_dp_split_file_path(full_path, &dp, &fp);
266 if (ret != EFI_SUCCESS)
267 goto err;
268
269 default_file_name = efi_dp_str(fp);
270 efi_free_pool(dp);
271 efi_free_pool(fp);
272 if (!default_file_name) {
273 ret = EFI_OUT_OF_RESOURCES;
274 goto err;
275 }
276
277 ret = EFI_CALL(root->open(root, &f, default_file_name,
278 EFI_FILE_MODE_READ, 0));
279 efi_free_pool(default_file_name);
280 if (ret != EFI_SUCCESS)
281 goto err;
282
283 EFI_CALL(f->close(f));
284 EFI_CALL(root->close(root));
285
286 *loaded_dp = full_path;
287
288 return EFI_SUCCESS;
289
290err:
291 EFI_CALL(root->close(root));
292 efi_free_pool(full_path);
293
294 return ret;
295}
296
297/**
298 * check_disk_has_default_file() - load the default file
299 *
300 * @blk: pointer to the UCLASS_BLK udevice
301 * @dp: pointer to default file device path
302 * Return: status code
303 */
304static efi_status_t check_disk_has_default_file(struct udevice *blk,
305 struct efi_device_path **dp)
306{
307 efi_status_t ret;
308 struct udevice *partition;
309
310 /* image that has no partition table but a file system */
311 ret = search_default_file(blk, dp);
312 if (ret == EFI_SUCCESS)
313 return ret;
314
315 /* try the partitions */
316 device_foreach_child(partition, blk) {
317 enum uclass_id id;
318
319 id = device_get_uclass_id(partition);
320 if (id != UCLASS_PARTITION)
321 continue;
322
323 ret = search_default_file(partition, dp);
324 if (ret == EFI_SUCCESS)
325 return ret;
326 }
327
328 return EFI_NOT_FOUND;
329}
330
331/**
332 * prepare_loaded_image() - prepare ramdisk for downloaded image
333 *
334 * @label: label of load option
335 * @addr: image address
336 * @size: image size
337 * @dp: pointer to default file device path
338 * @blk: pointer to created blk udevice
339 * Return: status code
340 */
341static efi_status_t prepare_loaded_image(u16 *label, ulong addr, ulong size,
342 struct efi_device_path **dp,
343 struct udevice **blk)
344{
345 efi_status_t ret;
346 struct udevice *ramdisk_blk;
347
348 ramdisk_blk = mount_image(label, addr, size);
349 if (!ramdisk_blk)
350 return EFI_LOAD_ERROR;
351
352 ret = check_disk_has_default_file(ramdisk_blk, dp);
353 if (ret != EFI_SUCCESS) {
354 log_info("Cannot boot from downloaded image\n");
355 goto err;
356 }
357
358 /*
359 * TODO: expose the ramdisk to OS.
360 * Need to pass the ramdisk information by the architecture-specific
361 * methods such as 'pmem' device-tree node.
362 */
363 ret = efi_add_memory_map(addr, size, EFI_RESERVED_MEMORY_TYPE);
364 if (ret != EFI_SUCCESS) {
365 log_err("Memory reservation failed\n");
366 goto err;
367 }
368
369 *blk = ramdisk_blk;
370
371 return EFI_SUCCESS;
372
373err:
374 if (blkmap_destroy(ramdisk_blk->parent))
375 log_err("Destroying blkmap failed\n");
376
377 return ret;
378}
379
380/**
381 * efi_bootmgr_release_uridp_resource() - cleanup uri device path resource
382 *
383 * @ctx: event context
384 * Return: status code
385 */
386efi_status_t efi_bootmgr_release_uridp_resource(struct uridp_context *ctx)
387{
388 efi_status_t ret = EFI_SUCCESS;
389
390 if (!ctx)
391 return ret;
392
393 /* cleanup for iso or img image */
394 if (ctx->ramdisk_blk_dev) {
395 ret = efi_add_memory_map(ctx->image_addr, ctx->image_size,
396 EFI_CONVENTIONAL_MEMORY);
397 if (ret != EFI_SUCCESS)
398 log_err("Reclaiming memory failed\n");
399
400 if (blkmap_destroy(ctx->ramdisk_blk_dev->parent)) {
401 log_err("Destroying blkmap failed\n");
402 ret = EFI_DEVICE_ERROR;
403 }
404 }
405
406 /* cleanup for PE-COFF image */
407 if (ctx->mem_handle) {
408 ret = efi_uninstall_multiple_protocol_interfaces(
409 ctx->mem_handle, &efi_guid_device_path, ctx->loaded_dp,
410 NULL);
411 if (ret != EFI_SUCCESS)
412 log_err("Uninstall device_path protocol failed\n");
413 }
414
415 efi_free_pool(ctx->loaded_dp);
416 free(ctx);
417
418 return ret;
419}
420
421/**
422 * efi_bootmgr_image_return_notify() - return to efibootmgr callback
423 *
424 * @event: the event for which this notification function is registered
425 * @context: event context
426 */
427static void EFIAPI efi_bootmgr_image_return_notify(struct efi_event *event,
428 void *context)
429{
430 efi_status_t ret;
431
432 EFI_ENTRY("%p, %p", event, context);
433 ret = efi_bootmgr_release_uridp_resource(context);
434 EFI_EXIT(ret);
435}
436
437/**
438 * try_load_from_uri_path() - Handle the URI device path
439 *
440 * @uridp: uri device path
441 * @lo_label: label of load option
442 * @handle: pointer to handle for newly installed image
443 * Return: status code
444 */
445static efi_status_t try_load_from_uri_path(struct efi_device_path_uri *uridp,
446 u16 *lo_label,
447 efi_handle_t *handle)
448{
449 char *s;
450 int err;
451 int uri_len;
452 efi_status_t ret;
453 void *source_buffer;
454 efi_uintn_t source_size;
455 struct uridp_context *ctx;
456 struct udevice *blk = NULL;
457 struct efi_event *event = NULL;
458 efi_handle_t mem_handle = NULL;
459 struct efi_device_path *loaded_dp;
460 static ulong image_size, image_addr;
461
462 ctx = calloc(1, sizeof(struct uridp_context));
463 if (!ctx)
464 return EFI_OUT_OF_RESOURCES;
465
466 s = env_get("loadaddr");
467 if (!s) {
468 log_err("Error: loadaddr is not set\n");
469 ret = EFI_INVALID_PARAMETER;
470 goto err;
471 }
472
473 image_addr = hextoul(s, NULL);
474 err = wget_with_dns(image_addr, uridp->uri);
475 if (err < 0) {
476 ret = EFI_INVALID_PARAMETER;
477 goto err;
478 }
479
480 image_size = env_get_hex("filesize", 0);
481 if (!image_size) {
482 ret = EFI_INVALID_PARAMETER;
483 goto err;
484 }
485
486 /*
487 * If the file extension is ".iso" or ".img", mount it and try to load
488 * the default file.
489 * If the file is PE-COFF image, load the downloaded file.
490 */
491 uri_len = strlen(uridp->uri);
492 if (!strncmp(&uridp->uri[uri_len - 4], ".iso", 4) ||
493 !strncmp(&uridp->uri[uri_len - 4], ".img", 4)) {
494 ret = prepare_loaded_image(lo_label, image_addr, image_size,
495 &loaded_dp, &blk);
496 if (ret != EFI_SUCCESS)
497 goto err;
498
499 source_buffer = NULL;
500 source_size = 0;
501 } else if (efi_check_pe((void *)image_addr, image_size, NULL) == EFI_SUCCESS) {
502 /*
503 * loaded_dp must exist until efi application returns,
504 * will be freed in return_to_efibootmgr event callback.
505 */
506 loaded_dp = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
507 (uintptr_t)image_addr, image_size);
508 ret = efi_install_multiple_protocol_interfaces(
509 &mem_handle, &efi_guid_device_path, loaded_dp, NULL);
510 if (ret != EFI_SUCCESS)
511 goto err;
512
513 source_buffer = (void *)image_addr;
514 source_size = image_size;
515 } else {
516 log_err("Error: file type is not supported\n");
517 ret = EFI_UNSUPPORTED;
518 goto err;
519 }
520
521 ctx->image_size = image_size;
522 ctx->image_addr = image_addr;
523 ctx->loaded_dp = loaded_dp;
524 ctx->ramdisk_blk_dev = blk;
525 ctx->mem_handle = mem_handle;
526
527 ret = EFI_CALL(efi_load_image(false, efi_root, loaded_dp, source_buffer,
528 source_size, handle));
529 if (ret != EFI_SUCCESS)
530 goto err;
531
532 /* create event for cleanup when the image returns or error occurs */
533 ret = efi_create_event(EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
534 efi_bootmgr_image_return_notify, ctx,
535 &efi_guid_event_group_return_to_efibootmgr,
536 &event);
537 if (ret != EFI_SUCCESS) {
538 log_err("Creating event failed\n");
539 goto err;
540 }
541
542 return ret;
543
544err:
545 efi_bootmgr_release_uridp_resource(ctx);
546
547 return ret;
548}
549
550/**
Heinrich Schuchardt15621aa2019-07-14 13:20:28 +0200551 * try_load_entry() - try to load image for boot option
552 *
Rob Clark9975fe92017-09-13 18:05:38 -0400553 * Attempt to load load-option number 'n', returning device_path and file_path
Heinrich Schuchardt15621aa2019-07-14 13:20:28 +0200554 * if successful. This checks that the EFI_LOAD_OPTION is active (enabled)
Rob Clark9975fe92017-09-13 18:05:38 -0400555 * and that the specified file to boot exists.
Heinrich Schuchardt15621aa2019-07-14 13:20:28 +0200556 *
Heinrich Schuchardt0ad64002020-08-07 17:49:39 +0200557 * @n: number of the boot option, e.g. 0x0a13 for Boot0A13
558 * @handle: on return handle for the newly installed image
559 * @load_options: load options set on the loaded image protocol
560 * Return: status code
Rob Clark9975fe92017-09-13 18:05:38 -0400561 */
Heinrich Schuchardt0ad64002020-08-07 17:49:39 +0200562static efi_status_t try_load_entry(u16 n, efi_handle_t *handle,
563 void **load_options)
Rob Clark9975fe92017-09-13 18:05:38 -0400564{
AKASHI Takahiro1a82b342018-11-05 18:06:41 +0900565 struct efi_load_option lo;
Heinrich Schuchardt4f419962022-04-25 23:35:01 +0200566 u16 varname[9];
AKASHI Takahiro6b95b382019-04-19 12:22:35 +0900567 void *load_option;
Heinrich Schuchardt45c66f92018-05-17 07:57:05 +0200568 efi_uintn_t size;
AKASHI Takahiro6b95b382019-04-19 12:22:35 +0900569 efi_status_t ret;
Rob Clark9975fe92017-09-13 18:05:38 -0400570
Heinrich Schuchardt4f419962022-04-25 23:35:01 +0200571 efi_create_indexed_name(varname, sizeof(varname), "Boot", n);
Rob Clark9975fe92017-09-13 18:05:38 -0400572
Ilias Apalodimasf4dc1bc2021-03-27 10:56:07 +0200573 load_option = efi_get_var(varname, &efi_global_variable_guid, &size);
Rob Clark9975fe92017-09-13 18:05:38 -0400574 if (!load_option)
AKASHI Takahiro6b95b382019-04-19 12:22:35 +0900575 return EFI_LOAD_ERROR;
Rob Clark9975fe92017-09-13 18:05:38 -0400576
Heinrich Schuchardt0e69bcf2020-05-31 22:46:09 +0200577 ret = efi_deserialize_load_option(&lo, load_option, &size);
578 if (ret != EFI_SUCCESS) {
579 log_warning("Invalid load option for %ls\n", varname);
580 goto error;
581 }
Rob Clark9975fe92017-09-13 18:05:38 -0400582
583 if (lo.attributes & LOAD_OPTION_ACTIVE) {
AKASHI Takahiro4e65ca02022-04-28 17:09:39 +0900584 struct efi_device_path *file_path;
AKASHI Takahiro37279ad2019-03-20 09:07:55 +0900585 u32 attributes;
Rob Clark9975fe92017-09-13 18:05:38 -0400586
Heinrich Schuchardt7ea79e52022-04-29 07:15:04 +0200587 log_debug("trying to load \"%ls\" from %pD\n", lo.label,
588 lo.file_path);
Rob Clark9975fe92017-09-13 18:05:38 -0400589
AKASHI Takahiro57ad6242022-05-12 11:29:02 +0900590 if (EFI_DP_TYPE(lo.file_path, MEDIA_DEVICE, FILE_PATH)) {
591 /* file_path doesn't contain a device path */
592 ret = try_load_from_short_path(lo.file_path, handle);
Masahisa Kojimad7d07a82023-11-10 13:25:40 +0900593 } else if (EFI_DP_TYPE(lo.file_path, MESSAGING_DEVICE, MSG_URI)) {
594 if (IS_ENABLED(CONFIG_EFI_HTTP_BOOT))
595 ret = try_load_from_uri_path(
596 (struct efi_device_path_uri *)lo.file_path,
597 lo.label, handle);
598 else
599 ret = EFI_LOAD_ERROR;
AKASHI Takahiro57ad6242022-05-12 11:29:02 +0900600 } else {
601 file_path = expand_media_path(lo.file_path);
602 ret = EFI_CALL(efi_load_image(true, efi_root, file_path,
603 NULL, 0, handle));
604 efi_free_pool(file_path);
605 }
AKASHI Takahiro94e6e552019-05-29 20:54:25 +0200606 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt7a373e52020-05-31 10:07:31 +0200607 log_warning("Loading %ls '%ls' failed\n",
608 varname, lo.label);
Rob Clark9975fe92017-09-13 18:05:38 -0400609 goto error;
AKASHI Takahiro94e6e552019-05-29 20:54:25 +0200610 }
Rob Clark9975fe92017-09-13 18:05:38 -0400611
AKASHI Takahiro37279ad2019-03-20 09:07:55 +0900612 attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS |
613 EFI_VARIABLE_RUNTIME_ACCESS;
Simon Glass156ccbc2022-01-23 12:55:12 -0700614 ret = efi_set_variable_int(u"BootCurrent",
Heinrich Schuchardtdda8c712020-06-24 19:09:18 +0200615 &efi_global_variable_guid,
Heinrich Schuchardt0ad64002020-08-07 17:49:39 +0200616 attributes, sizeof(n), &n, false);
Ilias Apalodimas53f6a5a2021-03-17 21:55:00 +0200617 if (ret != EFI_SUCCESS)
618 goto unload;
619 /* try to register load file2 for initrd's */
620 if (IS_ENABLED(CONFIG_EFI_LOAD_FILE2_INITRD)) {
621 ret = efi_initrd_register();
622 if (ret != EFI_SUCCESS)
623 goto unload;
AKASHI Takahiro6b95b382019-04-19 12:22:35 +0900624 }
AKASHI Takahiro37279ad2019-03-20 09:07:55 +0900625
Heinrich Schuchardt7a373e52020-05-31 10:07:31 +0200626 log_info("Booting: %ls\n", lo.label);
AKASHI Takahiro6b95b382019-04-19 12:22:35 +0900627 } else {
628 ret = EFI_LOAD_ERROR;
Rob Clark9975fe92017-09-13 18:05:38 -0400629 }
630
Heinrich Schuchardt0ad64002020-08-07 17:49:39 +0200631 /* Set load options */
Masahisa Kojimac416f1c2022-09-12 17:33:54 +0900632 if (size >= sizeof(efi_guid_t) &&
633 !guidcmp(lo.optional_data, &efi_guid_bootmenu_auto_generated))
634 size = 0;
635
Heinrich Schuchardt0ad64002020-08-07 17:49:39 +0200636 if (size) {
637 *load_options = malloc(size);
638 if (!*load_options) {
639 ret = EFI_OUT_OF_RESOURCES;
640 goto error;
641 }
642 memcpy(*load_options, lo.optional_data, size);
643 ret = efi_set_load_options(*handle, size, *load_options);
644 } else {
Heinrich Schuchardte4343112020-12-27 15:46:00 +0100645 *load_options = NULL;
Heinrich Schuchardt0ad64002020-08-07 17:49:39 +0200646 }
647
Rob Clark9975fe92017-09-13 18:05:38 -0400648error:
649 free(load_option);
650
AKASHI Takahiro6b95b382019-04-19 12:22:35 +0900651 return ret;
Ilias Apalodimas53f6a5a2021-03-17 21:55:00 +0200652
653unload:
654 if (EFI_CALL(efi_unload_image(*handle)) != EFI_SUCCESS)
655 log_err("Unloading image failed\n");
656 free(load_option);
657
658 return ret;
Rob Clark9975fe92017-09-13 18:05:38 -0400659}
660
Heinrich Schuchardt15621aa2019-07-14 13:20:28 +0200661/**
662 * efi_bootmgr_load() - try to load from BootNext or BootOrder
663 *
AKASHI Takahiro37279ad2019-03-20 09:07:55 +0900664 * Attempt to load from BootNext or in the order specified by BootOrder
665 * EFI variable, the available load-options, finding and returning
666 * the first one that can be loaded successfully.
Heinrich Schuchardt15621aa2019-07-14 13:20:28 +0200667 *
Heinrich Schuchardt0ad64002020-08-07 17:49:39 +0200668 * @handle: on return handle for the newly installed image
669 * @load_options: load options set on the loaded image protocol
670 * Return: status code
Rob Clark9975fe92017-09-13 18:05:38 -0400671 */
Heinrich Schuchardt0ad64002020-08-07 17:49:39 +0200672efi_status_t efi_bootmgr_load(efi_handle_t *handle, void **load_options)
Rob Clark9975fe92017-09-13 18:05:38 -0400673{
AKASHI Takahiro37279ad2019-03-20 09:07:55 +0900674 u16 bootnext, *bootorder;
Heinrich Schuchardt45c66f92018-05-17 07:57:05 +0200675 efi_uintn_t size;
Rob Clark9975fe92017-09-13 18:05:38 -0400676 int i, num;
AKASHI Takahiro37279ad2019-03-20 09:07:55 +0900677 efi_status_t ret;
Rob Clark9975fe92017-09-13 18:05:38 -0400678
Rob Clark9975fe92017-09-13 18:05:38 -0400679 bs = systab.boottime;
680 rs = systab.runtime;
681
AKASHI Takahiro37279ad2019-03-20 09:07:55 +0900682 /* BootNext */
AKASHI Takahiro37279ad2019-03-20 09:07:55 +0900683 size = sizeof(bootnext);
Simon Glass156ccbc2022-01-23 12:55:12 -0700684 ret = efi_get_variable_int(u"BootNext",
Heinrich Schuchardtdda8c712020-06-24 19:09:18 +0200685 &efi_global_variable_guid,
686 NULL, &size, &bootnext, NULL);
AKASHI Takahiro37279ad2019-03-20 09:07:55 +0900687 if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) {
688 /* BootNext does exist here */
689 if (ret == EFI_BUFFER_TOO_SMALL || size != sizeof(u16))
Heinrich Schuchardt7a373e52020-05-31 10:07:31 +0200690 log_err("BootNext must be 16-bit integer\n");
AKASHI Takahiro37279ad2019-03-20 09:07:55 +0900691
692 /* delete BootNext */
Simon Glass156ccbc2022-01-23 12:55:12 -0700693 ret = efi_set_variable_int(u"BootNext",
Heinrich Schuchardtdda8c712020-06-24 19:09:18 +0200694 &efi_global_variable_guid,
695 0, 0, NULL, false);
AKASHI Takahiro37279ad2019-03-20 09:07:55 +0900696
697 /* load BootNext */
698 if (ret == EFI_SUCCESS) {
699 if (size == sizeof(u16)) {
Heinrich Schuchardt0ad64002020-08-07 17:49:39 +0200700 ret = try_load_entry(bootnext, handle,
701 load_options);
AKASHI Takahiro6b95b382019-04-19 12:22:35 +0900702 if (ret == EFI_SUCCESS)
703 return ret;
Heinrich Schuchardt7a373e52020-05-31 10:07:31 +0200704 log_warning(
705 "Loading from BootNext failed, falling back to BootOrder\n");
AKASHI Takahiro37279ad2019-03-20 09:07:55 +0900706 }
707 } else {
Heinrich Schuchardt7a373e52020-05-31 10:07:31 +0200708 log_err("Deleting BootNext failed\n");
AKASHI Takahiro37279ad2019-03-20 09:07:55 +0900709 }
710 }
711
712 /* BootOrder */
Simon Glass156ccbc2022-01-23 12:55:12 -0700713 bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, &size);
Heinrich Schuchardt33e44972019-02-24 04:44:48 +0100714 if (!bootorder) {
Heinrich Schuchardt7a373e52020-05-31 10:07:31 +0200715 log_info("BootOrder not defined\n");
AKASHI Takahiro6b95b382019-04-19 12:22:35 +0900716 ret = EFI_NOT_FOUND;
Rob Clark9975fe92017-09-13 18:05:38 -0400717 goto error;
Heinrich Schuchardt33e44972019-02-24 04:44:48 +0100718 }
Rob Clark9975fe92017-09-13 18:05:38 -0400719
720 num = size / sizeof(uint16_t);
721 for (i = 0; i < num; i++) {
Heinrich Schuchardt7ea79e52022-04-29 07:15:04 +0200722 log_debug("trying to load Boot%04X\n", bootorder[i]);
Heinrich Schuchardt0ad64002020-08-07 17:49:39 +0200723 ret = try_load_entry(bootorder[i], handle, load_options);
AKASHI Takahiro6b95b382019-04-19 12:22:35 +0900724 if (ret == EFI_SUCCESS)
Rob Clark9975fe92017-09-13 18:05:38 -0400725 break;
726 }
727
728 free(bootorder);
729
730error:
AKASHI Takahiro6b95b382019-04-19 12:22:35 +0900731 return ret;
Rob Clark9975fe92017-09-13 18:05:38 -0400732}
Raymond Mao339b5272023-06-19 14:22:58 -0700733
734/**
735 * efi_bootmgr_enumerate_boot_option() - enumerate the possible bootable media
736 *
737 * @opt: pointer to the media boot option structure
738 * @volume_handles: pointer to the efi handles
739 * @count: number of efi handle
740 * Return: status code
741 */
742static efi_status_t efi_bootmgr_enumerate_boot_option(struct eficonfig_media_boot_option *opt,
743 efi_handle_t *volume_handles,
744 efi_status_t count)
745{
746 u32 i;
747 struct efi_handler *handler;
748 efi_status_t ret = EFI_SUCCESS;
749
750 for (i = 0; i < count; i++) {
751 u16 *p;
752 u16 dev_name[BOOTMENU_DEVICE_NAME_MAX];
753 char *optional_data;
754 struct efi_load_option lo;
755 char buf[BOOTMENU_DEVICE_NAME_MAX];
756 struct efi_device_path *device_path;
Raymond Mao7aa022c2023-06-19 14:23:01 -0700757 struct efi_device_path *short_dp;
Raymond Mao339b5272023-06-19 14:22:58 -0700758
759 ret = efi_search_protocol(volume_handles[i], &efi_guid_device_path, &handler);
760 if (ret != EFI_SUCCESS)
761 continue;
762 ret = efi_protocol_open(handler, (void **)&device_path,
763 efi_root, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
764 if (ret != EFI_SUCCESS)
765 continue;
766
767 ret = efi_disk_get_device_name(volume_handles[i], buf, BOOTMENU_DEVICE_NAME_MAX);
768 if (ret != EFI_SUCCESS)
769 continue;
770
771 p = dev_name;
772 utf8_utf16_strncpy(&p, buf, strlen(buf));
773
Raymond Mao7aa022c2023-06-19 14:23:01 -0700774 /* prefer to short form device path */
775 short_dp = efi_dp_shorten(device_path);
776 if (short_dp)
777 device_path = short_dp;
778
Raymond Mao339b5272023-06-19 14:22:58 -0700779 lo.label = dev_name;
780 lo.attributes = LOAD_OPTION_ACTIVE;
781 lo.file_path = device_path;
782 lo.file_path_length = efi_dp_size(device_path) + sizeof(END);
783 /*
784 * Set the dedicated guid to optional_data, it is used to identify
785 * the boot option that automatically generated by the bootmenu.
786 * efi_serialize_load_option() expects optional_data is null-terminated
787 * utf8 string, so set the "1234567" string to allocate enough space
788 * to store guid, instead of realloc the load_option.
789 */
790 lo.optional_data = "1234567";
791 opt[i].size = efi_serialize_load_option(&lo, (u8 **)&opt[i].lo);
792 if (!opt[i].size) {
793 ret = EFI_OUT_OF_RESOURCES;
794 goto out;
795 }
796 /* set the guid */
797 optional_data = (char *)opt[i].lo + (opt[i].size - u16_strsize(u"1234567"));
798 memcpy(optional_data, &efi_guid_bootmenu_auto_generated, sizeof(efi_guid_t));
799 }
800
801out:
802 return ret;
803}
804
805/**
806 * efi_bootmgr_delete_invalid_boot_option() - delete non-existing boot option
807 *
808 * @opt: pointer to the media boot option structure
809 * @count: number of media boot option structure
810 * Return: status code
811 */
812static efi_status_t efi_bootmgr_delete_invalid_boot_option(struct eficonfig_media_boot_option *opt,
813 efi_status_t count)
814{
815 efi_uintn_t size;
816 void *load_option;
817 u32 i, list_size = 0;
818 struct efi_load_option lo;
819 u16 *var_name16 = NULL;
820 u16 varname[] = u"Boot####";
821 efi_status_t ret = EFI_SUCCESS;
822 u16 *delete_index_list = NULL, *p;
823 efi_uintn_t buf_size;
824
825 buf_size = 128;
826 var_name16 = malloc(buf_size);
827 if (!var_name16)
828 return EFI_OUT_OF_RESOURCES;
829
830 var_name16[0] = 0;
831 for (;;) {
832 int index;
833 efi_guid_t guid;
834 efi_uintn_t tmp;
835
836 ret = efi_next_variable_name(&buf_size, &var_name16, &guid);
837 if (ret == EFI_NOT_FOUND) {
838 /*
839 * EFI_NOT_FOUND indicates we retrieved all EFI variables.
840 * This should be treated as success.
841 */
842 ret = EFI_SUCCESS;
843 break;
844 }
845
846 if (ret != EFI_SUCCESS)
847 goto out;
848
849 if (!efi_varname_is_load_option(var_name16, &index))
850 continue;
851
852 efi_create_indexed_name(varname, sizeof(varname), "Boot", index);
853 load_option = efi_get_var(varname, &efi_global_variable_guid, &size);
854 if (!load_option)
855 continue;
856
857 tmp = size;
858 ret = efi_deserialize_load_option(&lo, load_option, &size);
859 if (ret != EFI_SUCCESS)
860 goto next;
861
862 if (size >= sizeof(efi_guid_bootmenu_auto_generated) &&
863 !guidcmp(lo.optional_data, &efi_guid_bootmenu_auto_generated)) {
864 for (i = 0; i < count; i++) {
865 if (opt[i].size == tmp &&
866 memcmp(opt[i].lo, load_option, tmp) == 0) {
867 opt[i].exist = true;
868 break;
869 }
870 }
871
872 /*
873 * The entire list of variables must be retrieved by
874 * efi_get_next_variable_name_int() before deleting the invalid
875 * boot option, just save the index here.
876 */
877 if (i == count) {
878 p = realloc(delete_index_list, sizeof(u32) *
879 (list_size + 1));
880 if (!p) {
881 ret = EFI_OUT_OF_RESOURCES;
882 goto out;
883 }
884 delete_index_list = p;
885 delete_index_list[list_size++] = index;
886 }
887 }
888next:
889 free(load_option);
890 }
891
892 /* delete all invalid boot options */
893 for (i = 0; i < list_size; i++) {
894 ret = efi_bootmgr_delete_boot_option(delete_index_list[i]);
895 if (ret != EFI_SUCCESS)
896 goto out;
897 }
898
899out:
900 free(var_name16);
901 free(delete_index_list);
902
903 return ret;
904}
905
906/**
907 * efi_bootmgr_get_unused_bootoption() - get unused "Boot####" index
908 *
909 * @buf: pointer to the buffer to store boot option variable name
910 * @buf_size: buffer size
911 * @index: pointer to store the index in the BootOrder variable
912 * Return: status code
913 */
914efi_status_t efi_bootmgr_get_unused_bootoption(u16 *buf, efi_uintn_t buf_size,
915 unsigned int *index)
916{
917 u32 i;
918 efi_status_t ret;
919 efi_uintn_t size;
920
921 if (buf_size < u16_strsize(u"Boot####"))
922 return EFI_BUFFER_TOO_SMALL;
923
924 for (i = 0; i <= 0xFFFF; i++) {
925 size = 0;
926 efi_create_indexed_name(buf, buf_size, "Boot", i);
927 ret = efi_get_variable_int(buf, &efi_global_variable_guid,
928 NULL, &size, NULL, NULL);
929 if (ret == EFI_BUFFER_TOO_SMALL)
930 continue;
931 else
932 break;
933 }
934
935 if (i > 0xFFFF)
936 return EFI_OUT_OF_RESOURCES;
937
938 *index = i;
939
940 return EFI_SUCCESS;
941}
942
943/**
944 * efi_bootmgr_append_bootorder() - append new boot option in BootOrder variable
945 *
946 * @index: "Boot####" index to append to BootOrder variable
947 * Return: status code
948 */
949efi_status_t efi_bootmgr_append_bootorder(u16 index)
950{
951 u16 *bootorder;
952 efi_status_t ret;
953 u16 *new_bootorder = NULL;
954 efi_uintn_t last, size, new_size;
955
956 /* append new boot option */
957 bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, &size);
958 last = size / sizeof(u16);
959 new_size = size + sizeof(u16);
960 new_bootorder = calloc(1, new_size);
961 if (!new_bootorder) {
962 ret = EFI_OUT_OF_RESOURCES;
963 goto out;
964 }
965 memcpy(new_bootorder, bootorder, size);
966 new_bootorder[last] = index;
967
968 ret = efi_set_variable_int(u"BootOrder", &efi_global_variable_guid,
969 EFI_VARIABLE_NON_VOLATILE |
970 EFI_VARIABLE_BOOTSERVICE_ACCESS |
971 EFI_VARIABLE_RUNTIME_ACCESS,
972 new_size, new_bootorder, false);
973 if (ret != EFI_SUCCESS)
974 goto out;
975
976out:
977 free(bootorder);
978 free(new_bootorder);
979
980 return ret;
981}
982
983/**
984 * efi_bootmgr_delete_boot_option() - delete selected boot option
985 *
986 * @boot_index: boot option index to delete
987 * Return: status code
988 */
989efi_status_t efi_bootmgr_delete_boot_option(u16 boot_index)
990{
991 u16 *bootorder;
992 u16 varname[9];
993 efi_status_t ret;
994 unsigned int index;
995 efi_uintn_t num, size;
996
997 efi_create_indexed_name(varname, sizeof(varname),
998 "Boot", boot_index);
999 ret = efi_set_variable_int(varname, &efi_global_variable_guid,
1000 0, 0, NULL, false);
1001 if (ret != EFI_SUCCESS) {
1002 log_err("delete boot option(%ls) failed\n", varname);
1003 return ret;
1004 }
1005
1006 /* update BootOrder if necessary */
1007 bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, &size);
1008 if (!bootorder)
1009 return EFI_SUCCESS;
1010
1011 num = size / sizeof(u16);
1012 if (!efi_search_bootorder(bootorder, num, boot_index, &index))
1013 return EFI_SUCCESS;
1014
1015 memmove(&bootorder[index], &bootorder[index + 1],
1016 (num - index - 1) * sizeof(u16));
1017 size -= sizeof(u16);
1018 ret = efi_set_variable_int(u"BootOrder", &efi_global_variable_guid,
1019 EFI_VARIABLE_NON_VOLATILE |
1020 EFI_VARIABLE_BOOTSERVICE_ACCESS |
1021 EFI_VARIABLE_RUNTIME_ACCESS,
1022 size, bootorder, false);
1023
1024 return ret;
1025}
1026
1027/**
1028 * efi_bootmgr_update_media_device_boot_option() - generate the media device boot option
1029 *
1030 * This function enumerates all devices supporting EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
1031 * and generate the bootmenu entries.
1032 * This function also provide the BOOT#### variable maintenance for
1033 * the media device entries.
1034 * - Automatically create the BOOT#### variable for the newly detected device,
1035 * this BOOT#### variable is distinguished by the special GUID
1036 * stored in the EFI_LOAD_OPTION.optional_data
1037 * - If the device is not attached to the system, the associated BOOT#### variable
1038 * is automatically deleted.
1039 *
1040 * Return: status code
1041 */
1042efi_status_t efi_bootmgr_update_media_device_boot_option(void)
1043{
1044 u32 i;
1045 efi_status_t ret;
1046 efi_uintn_t count;
1047 efi_handle_t *volume_handles = NULL;
1048 struct eficonfig_media_boot_option *opt = NULL;
1049
1050 ret = efi_locate_handle_buffer_int(BY_PROTOCOL,
1051 &efi_simple_file_system_protocol_guid,
1052 NULL, &count,
1053 (efi_handle_t **)&volume_handles);
1054 if (ret != EFI_SUCCESS)
Raymond Mao9945bc42023-06-19 14:22:59 -07001055 goto out;
Raymond Mao339b5272023-06-19 14:22:58 -07001056
1057 opt = calloc(count, sizeof(struct eficonfig_media_boot_option));
Raymond Mao9945bc42023-06-19 14:22:59 -07001058 if (!opt) {
1059 ret = EFI_OUT_OF_RESOURCES;
Raymond Mao339b5272023-06-19 14:22:58 -07001060 goto out;
Raymond Mao9945bc42023-06-19 14:22:59 -07001061 }
Raymond Mao339b5272023-06-19 14:22:58 -07001062
1063 /* enumerate all devices supporting EFI_SIMPLE_FILE_SYSTEM_PROTOCOL */
1064 ret = efi_bootmgr_enumerate_boot_option(opt, volume_handles, count);
1065 if (ret != EFI_SUCCESS)
1066 goto out;
1067
1068 /*
1069 * System hardware configuration may vary depending on the user setup.
1070 * The boot option is automatically added by the bootmenu.
1071 * If the device is not attached to the system, the boot option needs
1072 * to be deleted.
1073 */
1074 ret = efi_bootmgr_delete_invalid_boot_option(opt, count);
1075 if (ret != EFI_SUCCESS)
1076 goto out;
1077
1078 /* add non-existent boot option */
1079 for (i = 0; i < count; i++) {
1080 u32 boot_index;
1081 u16 var_name[9];
1082
1083 if (!opt[i].exist) {
1084 ret = efi_bootmgr_get_unused_bootoption(var_name, sizeof(var_name),
1085 &boot_index);
1086 if (ret != EFI_SUCCESS)
1087 goto out;
1088
1089 ret = efi_set_variable_int(var_name, &efi_global_variable_guid,
1090 EFI_VARIABLE_NON_VOLATILE |
1091 EFI_VARIABLE_BOOTSERVICE_ACCESS |
1092 EFI_VARIABLE_RUNTIME_ACCESS,
1093 opt[i].size, opt[i].lo, false);
1094 if (ret != EFI_SUCCESS)
1095 goto out;
1096
1097 ret = efi_bootmgr_append_bootorder(boot_index);
1098 if (ret != EFI_SUCCESS) {
1099 efi_set_variable_int(var_name, &efi_global_variable_guid,
1100 0, 0, NULL, false);
1101 goto out;
1102 }
1103 }
1104 }
1105
1106out:
1107 if (opt) {
1108 for (i = 0; i < count; i++)
1109 free(opt[i].lo);
1110 }
1111 free(opt);
1112 efi_free_pool(volume_handles);
1113
Raymond Mao9945bc42023-06-19 14:22:59 -07001114 if (ret == EFI_NOT_FOUND)
1115 return EFI_SUCCESS;
Raymond Mao339b5272023-06-19 14:22:58 -07001116 return ret;
1117}