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