blob: 4ccf2055be3a3d65a361b35d6d253e025012a01f [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/**
17 * distro_efi_get_fdt_name() - get the filename for reading the .dtb file
18 *
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;
46 default:
47 return log_msg_ret("pref", -EINVAL);
48 }
49
50 fdt_fname = env_get("fdtfile");
51 if (fdt_fname) {
52 snprintf(fname, size, "%s/%s", prefix, fdt_fname);
53 log_debug("Using device tree: %s\n", fname);
54 } else if (IS_ENABLED(CONFIG_OF_HAS_PRIOR_STAGE)) {
55 strcpy(fname, "<prior>");
56 return log_msg_ret("pref", -EALREADY);
57 /* Use this fallback only for 32-bit ARM */
58 } else if (IS_ENABLED(CONFIG_ARM) && !IS_ENABLED(CONFIG_ARM64)) {
59 const char *soc = env_get("soc");
60 const char *board = env_get("board");
61 const char *boardver = env_get("boardver");
62
63 /* cf the code in label_boot() which seems very complex */
64 snprintf(fname, size, "%s/%s%s%s%s.dtb", prefix,
65 soc ? soc : "", soc ? "-" : "", board ? board : "",
66 boardver ? boardver : "");
67 log_debug("Using default device tree: %s\n", fname);
68 } else {
69 return log_msg_ret("env", -ENOENT);
70 }
71
72 return 0;
73}
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +020074
75/**
76 * efi_load_distro_fdt() - load distro device-tree
77 *
Heinrich Schuchardt8257f162024-07-13 13:30:29 +020078 * @handle: handle of loaded image
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +020079 * @fdt: on return device-tree, must be freed via efi_free_pages()
80 * @fdt_size: buffer size
81 */
Heinrich Schuchardt8257f162024-07-13 13:30:29 +020082void efi_load_distro_fdt(efi_handle_t handle, void **fdt, efi_uintn_t *fdt_size)
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +020083{
Heinrich Schuchardt8257f162024-07-13 13:30:29 +020084 struct efi_device_path *dp;
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +020085 efi_status_t ret;
Heinrich Schuchardt8257f162024-07-13 13:30:29 +020086 struct efi_handler *handler;
87 struct efi_loaded_image *loaded_image;
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +020088 efi_handle_t device;
89
90 *fdt = NULL;
91
Heinrich Schuchardt8257f162024-07-13 13:30:29 +020092 /* Get boot device from loaded image protocol */
93 ret = efi_search_protocol(handle, &efi_guid_loaded_image, &handler);
94 if (ret != EFI_SUCCESS)
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +020095 return;
Heinrich Schuchardt8257f162024-07-13 13:30:29 +020096 loaded_image = handler->protocol_interface;
97 device = loaded_image->device_handle;
98
99 /* Get device path of boot device */
100 ret = efi_search_protocol(device, &efi_guid_device_path, &handler);
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +0200101 if (ret != EFI_SUCCESS)
Heinrich Schuchardt8257f162024-07-13 13:30:29 +0200102 return;
103 dp = handler->protocol_interface;
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +0200104
Heinrich Schuchardt8257f162024-07-13 13:30:29 +0200105 /* Try the various available names */
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +0200106 for (int seq = 0; ; ++seq) {
107 struct efi_device_path *file;
108 char buf[255];
109
110 if (efi_get_distro_fdt_name(buf, sizeof(buf), seq))
111 break;
112 file = efi_dp_from_file(dp, buf);
113 if (!file)
114 break;
115 ret = efi_load_image_from_path(true, file, fdt, fdt_size);
116 efi_free_pool(file);
Heinrich Schuchardt8257f162024-07-13 13:30:29 +0200117 if (ret == EFI_SUCCESS) {
118 log_debug("Fdt %pD loaded\n", file);
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +0200119 break;
Heinrich Schuchardt8257f162024-07-13 13:30:29 +0200120 }
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +0200121 }
Heinrich Schuchardtd9b23632024-04-26 16:13:21 +0200122}