1 // SPDX-License-Identifier: GPL-2.0
3 * Verified Boot for Embedded (VBE) device tree fixup functions
5 * Copyright 2022 Google LLC
6 * Written by Simon Glass <sjg@chromium.org>
9 #define LOG_CATEGORY LOGC_BOOT
17 #include <dm/ofnode.h>
19 #define VBE_PREFIX "vbe,"
20 #define VBE_PREFIX_LEN (sizeof(VBE_PREFIX) - 1)
21 #define VBE_ERR_STR_LEN 128
22 #define VBE_MAX_RAND_SIZE 256
26 char err_str[VBE_ERR_STR_LEN];
29 typedef int (*vbe_req_func)(ofnode node, struct vbe_result *result);
31 static int handle_random_req(ofnode node, int default_size,
32 struct vbe_result *result)
34 char buf[VBE_MAX_RAND_SIZE];
39 if (!IS_ENABLED(CONFIG_DM_RNG))
42 if (ofnode_read_u32(node, "vbe,size", &size)) {
44 snprintf(result->err_str, VBE_ERR_STR_LEN,
45 "Missing vbe,size property");
46 return log_msg_ret("byt", -EINVAL);
50 if (size > VBE_MAX_RAND_SIZE) {
51 snprintf(result->err_str, VBE_ERR_STR_LEN,
52 "vbe,size %#x exceeds max size %#x", size,
54 return log_msg_ret("siz", -E2BIG);
56 ret = uclass_first_device_err(UCLASS_RNG, &dev);
58 snprintf(result->err_str, VBE_ERR_STR_LEN,
59 "Cannot find random-number device (err=%d)", ret);
60 return log_msg_ret("wr", ret);
62 ret = dm_rng_read(dev, buf, size);
64 snprintf(result->err_str, VBE_ERR_STR_LEN,
65 "Failed to read random-number device (err=%d)", ret);
66 return log_msg_ret("rd", ret);
68 ret = ofnode_write_prop(node, "data", buf, size, true);
70 return log_msg_ret("wr", -EINVAL);
75 static int vbe_req_random_seed(ofnode node, struct vbe_result *result)
77 return handle_random_req(node, 0, result);
80 static int vbe_req_aslr_move(ofnode node, struct vbe_result *result)
85 static int vbe_req_aslr_rand(ofnode node, struct vbe_result *result)
87 return handle_random_req(node, 4, result);
90 static int vbe_req_efi_runtime_rand(ofnode node, struct vbe_result *result)
92 return handle_random_req(node, 4, result);
95 static struct vbe_req {
99 /* address space layout randomization - move the OS in memory */
100 { "aslr-move", vbe_req_aslr_move },
102 /* provide random data for address space layout randomization */
103 { "aslr-rand", vbe_req_aslr_rand },
105 /* provide random data for EFI-runtime-services address */
106 { "efi-runtime-rand", vbe_req_efi_runtime_rand },
108 /* generate random data bytes to see the OS's rand generator */
109 { "random-rand", vbe_req_random_seed },
113 static int vbe_process_request(ofnode node, struct vbe_result *result)
115 const char *compat, *req_name;
118 compat = ofnode_read_string(node, "compatible");
122 if (strlen(compat) <= VBE_PREFIX_LEN ||
123 strncmp(compat, VBE_PREFIX, VBE_PREFIX_LEN))
126 req_name = compat + VBE_PREFIX_LEN; /* drop "vbe," prefix */
127 for (i = 0; i < ARRAY_SIZE(vbe_reqs); i++) {
128 if (!strcmp(vbe_reqs[i].compat, req_name)) {
131 ret = vbe_reqs[i].func(node, result);
133 return log_msg_ret("req", ret);
137 snprintf(result->err_str, VBE_ERR_STR_LEN, "Unknown request: %s",
144 * bootmeth_vbe_ft_fixup() - Process VBE OS requests and do device tree fixups
146 * If there are no images provided, this does nothing and returns 0.
148 * @ctx: Context for event
149 * @event: Event to process
150 * @return 0 if OK, -ve on error
152 static int bootmeth_vbe_ft_fixup(void *ctx, struct event *event)
154 const struct event_ft_fixup *fixup = &event->data.ft_fixup;
155 const struct bootm_headers *images = fixup->images;
156 ofnode parent, dest_parent, root, node;
159 if (!images || !images->fit_hdr_os)
162 /* Get the image node with requests in it */
163 log_debug("fit=%p, noffset=%d\n", images->fit_hdr_os,
164 images->fit_noffset_os);
165 fit = oftree_from_fdt(images->fit_hdr_os);
166 root = oftree_root(fit);
167 if (of_live_active()) {
168 log_warning("Cannot fix up live tree\n");
171 if (!ofnode_valid(root))
172 return log_msg_ret("rt", -EINVAL);
173 parent = noffset_to_ofnode(root, images->fit_noffset_os);
174 if (!ofnode_valid(parent))
175 return log_msg_ret("img", -EINVAL);
176 dest_parent = oftree_path(fixup->tree, "/chosen");
177 if (!ofnode_valid(dest_parent))
178 return log_msg_ret("dst", -EINVAL);
180 ofnode_for_each_subnode(node, parent) {
181 const char *name = ofnode_get_name(node);
182 struct vbe_result result;
186 log_debug("copy subnode: %s\n", name);
187 ret = ofnode_add_subnode(dest_parent, name, &dest);
188 if (ret && ret != -EEXIST)
189 return log_msg_ret("add", ret);
190 ret = ofnode_copy_props(node, dest);
192 return log_msg_ret("cp", ret);
194 *result.err_str = '\0';
195 ret = vbe_process_request(dest, &result);
198 log_err("Failed to process VBE request %s (err=%d)\n",
199 ofnode_get_name(dest), ret);
200 if (*result.err_str) {
201 char *msg = strdup(result.err_str);
204 return log_msg_ret("msg", -ENOMEM);
205 ret = ofnode_write_string(dest, "vbe,error",
209 return log_msg_ret("str", -ENOMEM);
213 ret = ofnode_write_u32(dest, "vbe,errnum",
216 return log_msg_ret("num", -ENOMEM);
217 if (result.errnum != -ENOTSUPP)
218 return log_msg_ret("pro",
220 if (result.errnum == -ENOTSUPP &&
221 ofnode_read_bool(dest, "vbe,required")) {
222 log_err("Cannot handle required request: %s\n",
223 ofnode_get_name(dest));
224 return log_msg_ret("req",
233 EVENT_SPY(EVT_FT_FIXUP, bootmeth_vbe_ft_fixup);