blob: bfaa9cfc207d314f9b7d2bdf8b914d48e9d3f7b3 [file] [log] [blame]
Heinrich Schuchardt1a41ca42024-04-26 16:13:18 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Bootmethod for distro boot via EFI
4 *
5 * Copyright 2021 Google LLC
6 * Written by Simon Glass <sjg@chromium.org>
7 */
8
Heinrich Schuchardt955a3212025-01-16 20:26:59 +01009#define LOG_CATEGORY LOGC_EFI
10
Simon Glass37972f42025-05-24 11:28:21 -060011#include <efi_device_path.h>
Heinrich Schuchardt1a41ca42024-04-26 16:13:18 +020012#include <efi_loader.h>
13#include <env.h>
14#include <errno.h>
15#include <log.h>
16#include <string.h>
17#include <vsprintf.h>
18
19/**
Heinrich Schuchardt4e11a332024-08-07 00:11:38 +020020 * efi_get_distro_fdt_name() - get the filename for reading the .dtb file
Heinrich Schuchardt1a41ca42024-04-26 16:13:18 +020021 *
22 * @fname: buffer for filename
23 * @size: buffer size
24 * @seq: sequence number, to cycle through options (0=first)
25 *
26 * Returns:
27 * 0 on success,
28 * -ENOENT if the "fdtfile" env var does not exist,
29 * -EINVAL if there are no more options,
30 * -EALREADY if the control FDT should be used
31 */
32int efi_get_distro_fdt_name(char *fname, int size, int seq)
33{
34 const char *fdt_fname;
35 const char *prefix;
36
37 /* select the prefix */
38 switch (seq) {
39 case 0:
40 /* this is the default */
41 prefix = "/dtb";
42 break;
43 case 1:
44 prefix = "";
45 break;
46 case 2:
47 prefix = "/dtb/current";
48 break;
Caleb Connollyfeb76da2024-07-22 19:55:23 +020049 case 3:
50 prefix = "/dtbs";
51 break;
Heinrich Schuchardt1a41ca42024-04-26 16:13:18 +020052 default:
53 return log_msg_ret("pref", -EINVAL);
54 }
55
56 fdt_fname = env_get("fdtfile");
57 if (fdt_fname) {
58 snprintf(fname, size, "%s/%s", prefix, fdt_fname);
59 log_debug("Using device tree: %s\n", fname);
60 } else if (IS_ENABLED(CONFIG_OF_HAS_PRIOR_STAGE)) {
61 strcpy(fname, "<prior>");
62 return log_msg_ret("pref", -EALREADY);
63 /* Use this fallback only for 32-bit ARM */
64 } else if (IS_ENABLED(CONFIG_ARM) && !IS_ENABLED(CONFIG_ARM64)) {
65 const char *soc = env_get("soc");
66 const char *board = env_get("board");
67 const char *boardver = env_get("boardver");
68
69 /* cf the code in label_boot() which seems very complex */
70 snprintf(fname, size, "%s/%s%s%s%s.dtb", prefix,
71 soc ? soc : "", soc ? "-" : "", board ? board : "",
72 boardver ? boardver : "");
73 log_debug("Using default device tree: %s\n", fname);
74 } else {
75 return log_msg_ret("env", -ENOENT);
76 }
77
78 return 0;
79}
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +020080
81/**
82 * efi_load_distro_fdt() - load distro device-tree
83 *
Heinrich Schuchardt8257f162024-07-13 13:30:29 +020084 * @handle: handle of loaded image
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +020085 * @fdt: on return device-tree, must be freed via efi_free_pages()
86 * @fdt_size: buffer size
87 */
Heinrich Schuchardt8257f162024-07-13 13:30:29 +020088void efi_load_distro_fdt(efi_handle_t handle, void **fdt, efi_uintn_t *fdt_size)
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +020089{
Heinrich Schuchardt8257f162024-07-13 13:30:29 +020090 struct efi_device_path *dp;
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +020091 efi_status_t ret;
Heinrich Schuchardt8257f162024-07-13 13:30:29 +020092 struct efi_handler *handler;
93 struct efi_loaded_image *loaded_image;
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +020094 efi_handle_t device;
95
96 *fdt = NULL;
97
Heinrich Schuchardt8257f162024-07-13 13:30:29 +020098 /* Get boot device from loaded image protocol */
99 ret = efi_search_protocol(handle, &efi_guid_loaded_image, &handler);
100 if (ret != EFI_SUCCESS)
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +0200101 return;
Heinrich Schuchardt8257f162024-07-13 13:30:29 +0200102 loaded_image = handler->protocol_interface;
103 device = loaded_image->device_handle;
104
105 /* Get device path of boot device */
106 ret = efi_search_protocol(device, &efi_guid_device_path, &handler);
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +0200107 if (ret != EFI_SUCCESS)
Heinrich Schuchardt8257f162024-07-13 13:30:29 +0200108 return;
109 dp = handler->protocol_interface;
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +0200110
Heinrich Schuchardt8257f162024-07-13 13:30:29 +0200111 /* Try the various available names */
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +0200112 for (int seq = 0; ; ++seq) {
113 struct efi_device_path *file;
114 char buf[255];
115
116 if (efi_get_distro_fdt_name(buf, sizeof(buf), seq))
117 break;
118 file = efi_dp_from_file(dp, buf);
119 if (!file)
120 break;
121 ret = efi_load_image_from_path(true, file, fdt, fdt_size);
122 efi_free_pool(file);
Heinrich Schuchardt8257f162024-07-13 13:30:29 +0200123 if (ret == EFI_SUCCESS) {
124 log_debug("Fdt %pD loaded\n", file);
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +0200125 break;
Heinrich Schuchardt8257f162024-07-13 13:30:29 +0200126 }
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +0200127 }
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +0200128}