1 // SPDX-License-Identifier: GPL-2.0
3 * Verified Boot for Embedded (VBE) OS request (device tree fixup) functions
5 * Copyright 2022 Google LLC
9 #define LOG_CATEGORY LOGC_BOOT
16 #include <dm/ofnode.h>
18 #define VBE_PREFIX "vbe,"
19 #define VBE_PREFIX_LEN (sizeof(VBE_PREFIX) - 1)
20 #define VBE_ERR_STR_LEN 128
21 #define VBE_MAX_RAND_SIZE 256
25 char err_str[VBE_ERR_STR_LEN];
28 typedef int (*vbe_req_func)(ofnode node, struct vbe_result *result);
30 static int handle_random_req(ofnode node, int default_size,
31 struct vbe_result *result)
33 char buf[VBE_MAX_RAND_SIZE];
38 if (!CONFIG_IS_ENABLED(DM_RNG))
41 if (ofnode_read_u32(node, "vbe,size", &size)) {
43 snprintf(result->err_str, VBE_ERR_STR_LEN,
44 "Missing vbe,size property");
45 return log_msg_ret("byt", -EINVAL);
49 if (size > VBE_MAX_RAND_SIZE) {
50 snprintf(result->err_str, VBE_ERR_STR_LEN,
51 "vbe,size %#x exceeds max size %#x", size,
53 return log_msg_ret("siz", -E2BIG);
55 ret = uclass_first_device_err(UCLASS_RNG, &dev);
57 snprintf(result->err_str, VBE_ERR_STR_LEN,
58 "Cannot find random-number device (err=%d)", ret);
59 return log_msg_ret("wr", ret);
61 ret = dm_rng_read(dev, buf, size);
63 snprintf(result->err_str, VBE_ERR_STR_LEN,
64 "Failed to read random-number device (err=%d)", ret);
65 return log_msg_ret("rd", ret);
67 ret = ofnode_write_prop(node, "data", buf, size, true);
69 return log_msg_ret("wr", -EINVAL);
74 static int vbe_req_random_seed(ofnode node, struct vbe_result *result)
76 return handle_random_req(node, 0, result);
79 static int vbe_req_aslr_move(ofnode node, struct vbe_result *result)
84 static int vbe_req_aslr_rand(ofnode node, struct vbe_result *result)
86 return handle_random_req(node, 4, result);
89 static int vbe_req_efi_runtime_rand(ofnode node, struct vbe_result *result)
91 return handle_random_req(node, 4, result);
94 static struct vbe_req {
98 /* address space layout randomization - move the OS in memory */
99 { "aslr-move", vbe_req_aslr_move },
101 /* provide random data for address space layout randomization */
102 { "aslr-rand", vbe_req_aslr_rand },
104 /* provide random data for EFI-runtime-services address */
105 { "efi-runtime-rand", vbe_req_efi_runtime_rand },
107 /* generate random data bytes to see the OS's rand generator */
108 { "random-rand", vbe_req_random_seed },
112 static int vbe_process_request(ofnode node, struct vbe_result *result)
114 const char *compat, *req_name;
117 compat = ofnode_read_string(node, "compatible");
121 if (strlen(compat) <= VBE_PREFIX_LEN ||
122 strncmp(compat, VBE_PREFIX, VBE_PREFIX_LEN))
125 req_name = compat + VBE_PREFIX_LEN; /* drop "vbe," prefix */
126 for (i = 0; i < ARRAY_SIZE(vbe_reqs); i++) {
127 if (!strcmp(vbe_reqs[i].compat, req_name)) {
130 ret = vbe_reqs[i].func(node, result);
132 return log_msg_ret("req", ret);
136 snprintf(result->err_str, VBE_ERR_STR_LEN, "Unknown request: %s",
143 * bootmeth_vbe_ft_fixup() - Process VBE OS requests and do device tree fixups
145 * If there are no images provided, this does nothing and returns 0.
147 * @ctx: Context for event
148 * @event: Event to process
149 * @return 0 if OK, -ve on error
151 static int bootmeth_vbe_ft_fixup(void *ctx, struct event *event)
153 const struct event_ft_fixup *fixup = &event->data.ft_fixup;
154 const struct bootm_headers *images = fixup->images;
155 ofnode parent, dest_parent, root, node;
158 if (!images || !images->fit_hdr_os)
161 /* Get the image node with requests in it */
162 log_debug("fit=%p, noffset=%d\n", images->fit_hdr_os,
163 images->fit_noffset_os);
164 fit = oftree_from_fdt(images->fit_hdr_os);
165 root = oftree_root(fit);
166 if (of_live_active()) {
167 log_warning("Cannot fix up live tree\n");
170 if (!ofnode_valid(root))
171 return log_msg_ret("rt", -EINVAL);
172 parent = noffset_to_ofnode(root, images->fit_noffset_os);
173 if (!ofnode_valid(parent))
174 return log_msg_ret("img", -EINVAL);
175 dest_parent = oftree_path(fixup->tree, "/chosen");
176 if (!ofnode_valid(dest_parent))
177 return log_msg_ret("dst", -EINVAL);
179 ofnode_for_each_subnode(node, parent) {
180 const char *name = ofnode_get_name(node);
181 struct vbe_result result;
185 log_debug("copy subnode: %s\n", name);
186 ret = ofnode_add_subnode(dest_parent, name, &dest);
187 if (ret && ret != -EEXIST)
188 return log_msg_ret("add", ret);
189 ret = ofnode_copy_props(dest, node);
191 return log_msg_ret("cp", ret);
193 *result.err_str = '\0';
194 ret = vbe_process_request(dest, &result);
197 log_warning("Failed to process VBE request %s (err=%d)\n",
198 ofnode_get_name(dest), ret);
199 if (*result.err_str) {
200 char *msg = strdup(result.err_str);
203 return log_msg_ret("msg", -ENOMEM);
204 ret = ofnode_write_string(dest, "vbe,error",
208 return log_msg_ret("str", -ENOMEM);
212 ret = ofnode_write_u32(dest, "vbe,errnum",
215 return log_msg_ret("num", -ENOMEM);
216 if (result.errnum != -ENOTSUPP)
217 return log_msg_ret("pro",
219 if (result.errnum == -ENOTSUPP &&
220 ofnode_read_bool(dest, "vbe,required")) {
221 log_err("Cannot handle required request: %s\n",
222 ofnode_get_name(dest));
223 return log_msg_ret("req",
232 EVENT_SPY_FULL(EVT_FT_FIXUP, bootmeth_vbe_ft_fixup);