blob: f882622fdadfe708fffadaa22f5776e1198d20c1 [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
9#include <efi_loader.h>
10#include <env.h>
11#include <errno.h>
12#include <log.h>
13#include <string.h>
14#include <vsprintf.h>
15
16/**
Heinrich Schuchardt4e11a332024-08-07 00:11:38 +020017 * efi_get_distro_fdt_name() - get the filename for reading the .dtb file
Heinrich Schuchardt1a41ca42024-04-26 16:13:18 +020018 *
19 * @fname: buffer for filename
20 * @size: buffer size
21 * @seq: sequence number, to cycle through options (0=first)
22 *
23 * Returns:
24 * 0 on success,
25 * -ENOENT if the "fdtfile" env var does not exist,
26 * -EINVAL if there are no more options,
27 * -EALREADY if the control FDT should be used
28 */
29int efi_get_distro_fdt_name(char *fname, int size, int seq)
30{
31 const char *fdt_fname;
32 const char *prefix;
33
34 /* select the prefix */
35 switch (seq) {
36 case 0:
37 /* this is the default */
38 prefix = "/dtb";
39 break;
40 case 1:
41 prefix = "";
42 break;
43 case 2:
44 prefix = "/dtb/current";
45 break;
Caleb Connollyfeb76da2024-07-22 19:55:23 +020046 case 3:
47 prefix = "/dtbs";
48 break;
Heinrich Schuchardt1a41ca42024-04-26 16:13:18 +020049 default:
50 return log_msg_ret("pref", -EINVAL);
51 }
52
53 fdt_fname = env_get("fdtfile");
54 if (fdt_fname) {
55 snprintf(fname, size, "%s/%s", prefix, fdt_fname);
56 log_debug("Using device tree: %s\n", fname);
57 } else if (IS_ENABLED(CONFIG_OF_HAS_PRIOR_STAGE)) {
58 strcpy(fname, "<prior>");
59 return log_msg_ret("pref", -EALREADY);
60 /* Use this fallback only for 32-bit ARM */
61 } else if (IS_ENABLED(CONFIG_ARM) && !IS_ENABLED(CONFIG_ARM64)) {
62 const char *soc = env_get("soc");
63 const char *board = env_get("board");
64 const char *boardver = env_get("boardver");
65
66 /* cf the code in label_boot() which seems very complex */
67 snprintf(fname, size, "%s/%s%s%s%s.dtb", prefix,
68 soc ? soc : "", soc ? "-" : "", board ? board : "",
69 boardver ? boardver : "");
70 log_debug("Using default device tree: %s\n", fname);
71 } else {
72 return log_msg_ret("env", -ENOENT);
73 }
74
75 return 0;
76}
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +020077
78/**
79 * efi_load_distro_fdt() - load distro device-tree
80 *
Heinrich Schuchardt8257f162024-07-13 13:30:29 +020081 * @handle: handle of loaded image
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +020082 * @fdt: on return device-tree, must be freed via efi_free_pages()
83 * @fdt_size: buffer size
84 */
Heinrich Schuchardt8257f162024-07-13 13:30:29 +020085void efi_load_distro_fdt(efi_handle_t handle, void **fdt, efi_uintn_t *fdt_size)
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +020086{
Heinrich Schuchardt8257f162024-07-13 13:30:29 +020087 struct efi_device_path *dp;
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +020088 efi_status_t ret;
Heinrich Schuchardt8257f162024-07-13 13:30:29 +020089 struct efi_handler *handler;
90 struct efi_loaded_image *loaded_image;
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +020091 efi_handle_t device;
92
93 *fdt = NULL;
94
Heinrich Schuchardt8257f162024-07-13 13:30:29 +020095 /* Get boot device from loaded image protocol */
96 ret = efi_search_protocol(handle, &efi_guid_loaded_image, &handler);
97 if (ret != EFI_SUCCESS)
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +020098 return;
Heinrich Schuchardt8257f162024-07-13 13:30:29 +020099 loaded_image = handler->protocol_interface;
100 device = loaded_image->device_handle;
101
102 /* Get device path of boot device */
103 ret = efi_search_protocol(device, &efi_guid_device_path, &handler);
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +0200104 if (ret != EFI_SUCCESS)
Heinrich Schuchardt8257f162024-07-13 13:30:29 +0200105 return;
106 dp = handler->protocol_interface;
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +0200107
Heinrich Schuchardt8257f162024-07-13 13:30:29 +0200108 /* Try the various available names */
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +0200109 for (int seq = 0; ; ++seq) {
110 struct efi_device_path *file;
111 char buf[255];
112
113 if (efi_get_distro_fdt_name(buf, sizeof(buf), seq))
114 break;
115 file = efi_dp_from_file(dp, buf);
116 if (!file)
117 break;
118 ret = efi_load_image_from_path(true, file, fdt, fdt_size);
119 efi_free_pool(file);
Heinrich Schuchardt8257f162024-07-13 13:30:29 +0200120 if (ret == EFI_SUCCESS) {
121 log_debug("Fdt %pD loaded\n", file);
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +0200122 break;
Heinrich Schuchardt8257f162024-07-13 13:30:29 +0200123 }
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +0200124 }
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +0200125}