blob: 86ba00c2bdd96648972a8b077489b0a2c214f39f [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 *
78 * @fdt: on return device-tree, must be freed via efi_free_pages()
79 * @fdt_size: buffer size
80 */
81void efi_load_distro_fdt(void **fdt, efi_uintn_t *fdt_size)
82{
83 struct efi_device_path *rem, *dp;
84 efi_status_t ret;
85 efi_handle_t device;
86
87 *fdt = NULL;
88
89 dp = efi_get_dp_from_boot(NULL);
90 if (!dp)
91 return;
92 device = efi_dp_find_obj(dp, NULL, &rem);
93 ret = efi_search_protocol(device, &efi_simple_file_system_protocol_guid,
94 NULL);
95 if (ret != EFI_SUCCESS)
96 goto err;
97 memcpy(rem, &END, sizeof(END));
98
99 /* try the various available names */
100 for (int seq = 0; ; ++seq) {
101 struct efi_device_path *file;
102 char buf[255];
103
104 if (efi_get_distro_fdt_name(buf, sizeof(buf), seq))
105 break;
106 file = efi_dp_from_file(dp, buf);
107 if (!file)
108 break;
109 ret = efi_load_image_from_path(true, file, fdt, fdt_size);
110 efi_free_pool(file);
111 if (ret == EFI_SUCCESS)
112 break;
113 }
114
115err:
116 efi_free_pool(dp);
117}