summaryrefslogtreecommitdiff
path: root/boot
diff options
context:
space:
mode:
Diffstat (limited to 'boot')
-rw-r--r--boot/Makefile2
-rw-r--r--boot/bootdev-uclass.c4
-rw-r--r--boot/bootm.c2
-rw-r--r--boot/image-fdt.c37
-rw-r--r--boot/vbe_fixup.c233
-rw-r--r--boot/vbe_simple.c16
6 files changed, 266 insertions, 28 deletions
diff --git a/boot/Makefile b/boot/Makefile
index 67e335255f1..dd45d786f8c 100644
--- a/boot/Makefile
+++ b/boot/Makefile
@@ -47,5 +47,5 @@ ifdef CONFIG_SPL_BUILD
obj-$(CONFIG_SPL_LOAD_FIT) += common_fit.o
endif
-obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_VBE) += vbe.o
+obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_VBE) += vbe.o vbe_fixup.o
obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_VBE_SIMPLE) += vbe_simple.o
diff --git a/boot/bootdev-uclass.c b/boot/bootdev-uclass.c
index 13ac69eb392..9d98bee4549 100644
--- a/boot/bootdev-uclass.c
+++ b/boot/bootdev-uclass.c
@@ -195,7 +195,7 @@ void bootdev_list(bool probe)
printf("Seq Probed Status Uclass Name\n");
printf("--- ------ ------ -------- ------------------\n");
if (probe)
- ret = uclass_first_device_err(UCLASS_BOOTDEV, &dev);
+ ret = uclass_first_device_check(UCLASS_BOOTDEV, &dev);
else
ret = uclass_find_first_device(UCLASS_BOOTDEV, &dev);
for (i = 0; dev; i++) {
@@ -204,7 +204,7 @@ void bootdev_list(bool probe)
ret ? simple_itoa(ret) : "OK",
dev_get_uclass_name(dev_get_parent(dev)), dev->name);
if (probe)
- ret = uclass_next_device_err(&dev);
+ ret = uclass_next_device_check(&dev);
else
ret = uclass_find_next_device(&dev);
}
diff --git a/boot/bootm.c b/boot/bootm.c
index 5b20b418dba..a4c0870c0fe 100644
--- a/boot/bootm.c
+++ b/boot/bootm.c
@@ -790,7 +790,7 @@ int do_bootm_states(struct cmd_tbl *cmdtp, int flag, int argc,
/* Check for unsupported subcommand. */
if (ret) {
- puts("subcommand not supported\n");
+ printf("subcommand failed (err=%d)\n", ret);
return ret;
}
diff --git a/boot/image-fdt.c b/boot/image-fdt.c
index 884e089f2d8..b830a0ab418 100644
--- a/boot/image-fdt.c
+++ b/boot/image-fdt.c
@@ -186,24 +186,25 @@ int boot_relocate_fdt(struct lmb *lmb, char **of_flat_tree, ulong *of_size)
/* If fdt_high is set use it to select the relocation address */
fdt_high = env_get("fdt_high");
if (fdt_high) {
- void *desired_addr = (void *)hextoul(fdt_high, NULL);
+ ulong desired_addr = hextoul(fdt_high, NULL);
+ ulong addr;
- if (((ulong) desired_addr) == ~0UL) {
+ if (desired_addr == ~0UL) {
/* All ones means use fdt in place */
of_start = fdt_blob;
- lmb_reserve(lmb, (ulong)of_start, of_len);
+ lmb_reserve(lmb, map_to_sysmem(of_start), of_len);
disable_relocation = 1;
} else if (desired_addr) {
- of_start =
- (void *)(ulong) lmb_alloc_base(lmb, of_len, 0x1000,
- (ulong)desired_addr);
+ addr = lmb_alloc_base(lmb, of_len, 0x1000,
+ desired_addr);
+ of_start = map_sysmem(addr, of_len);
if (of_start == NULL) {
puts("Failed using fdt_high value for Device Tree");
goto error;
}
} else {
- of_start =
- (void *)(ulong) lmb_alloc(lmb, of_len, 0x1000);
+ addr = lmb_alloc(lmb, of_len, 0x1000);
+ of_start = map_sysmem(addr, of_len);
}
} else {
mapsize = env_get_bootm_mapsize();
@@ -224,9 +225,8 @@ int boot_relocate_fdt(struct lmb *lmb, char **of_flat_tree, ulong *of_size)
* At least part of this DRAM bank is usable, try
* using it for LMB allocation.
*/
- of_start =
- (void *)(ulong) lmb_alloc_base(lmb, of_len, 0x1000,
- start + usable);
+ of_start = map_sysmem((ulong)lmb_alloc_base(lmb,
+ of_len, 0x1000, start + usable), of_len);
/* Allocation succeeded, use this block. */
if (of_start != NULL)
break;
@@ -665,15 +665,18 @@ int image_setup_libfdt(struct bootm_headers *images, void *blob,
goto err;
}
}
- if (CONFIG_IS_ENABLED(EVENT)) {
+ if (!of_live_active() && CONFIG_IS_ENABLED(EVENT)) {
struct event_ft_fixup fixup;
- fixup.tree = oftree_default();
+ fixup.tree = oftree_from_fdt(blob);
fixup.images = images;
- ret = event_notify(EVT_FT_FIXUP, &fixup, sizeof(fixup));
- if (ret) {
- printf("ERROR: fdt fixup event failed: %d\n", ret);
- goto err;
+ if (oftree_valid(fixup.tree)) {
+ ret = event_notify(EVT_FT_FIXUP, &fixup, sizeof(fixup));
+ if (ret) {
+ printf("ERROR: fdt fixup event failed: %d\n",
+ ret);
+ goto err;
+ }
}
}
diff --git a/boot/vbe_fixup.c b/boot/vbe_fixup.c
new file mode 100644
index 00000000000..53d88678c92
--- /dev/null
+++ b/boot/vbe_fixup.c
@@ -0,0 +1,233 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Verified Boot for Embedded (VBE) device tree fixup functions
+ *
+ * Copyright 2022 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#define LOG_CATEGORY LOGC_BOOT
+
+#include <common.h>
+#include <dm.h>
+#include <event.h>
+#include <image.h>
+#include <malloc.h>
+#include <rng.h>
+#include <dm/ofnode.h>
+
+#define VBE_PREFIX "vbe,"
+#define VBE_PREFIX_LEN (sizeof(VBE_PREFIX) - 1)
+#define VBE_ERR_STR_LEN 128
+#define VBE_MAX_RAND_SIZE 256
+
+struct vbe_result {
+ int errnum;
+ char err_str[VBE_ERR_STR_LEN];
+};
+
+typedef int (*vbe_req_func)(ofnode node, struct vbe_result *result);
+
+static int handle_random_req(ofnode node, int default_size,
+ struct vbe_result *result)
+{
+ char buf[VBE_MAX_RAND_SIZE];
+ struct udevice *dev;
+ u32 size;
+ int ret;
+
+ if (!IS_ENABLED(CONFIG_DM_RNG))
+ return -ENOTSUPP;
+
+ if (ofnode_read_u32(node, "vbe,size", &size)) {
+ if (!default_size) {
+ snprintf(result->err_str, VBE_ERR_STR_LEN,
+ "Missing vbe,size property");
+ return log_msg_ret("byt", -EINVAL);
+ }
+ size = default_size;
+ }
+ if (size > VBE_MAX_RAND_SIZE) {
+ snprintf(result->err_str, VBE_ERR_STR_LEN,
+ "vbe,size %#x exceeds max size %#x", size,
+ VBE_MAX_RAND_SIZE);
+ return log_msg_ret("siz", -E2BIG);
+ }
+ ret = uclass_first_device_err(UCLASS_RNG, &dev);
+ if (ret) {
+ snprintf(result->err_str, VBE_ERR_STR_LEN,
+ "Cannot find random-number device (err=%d)", ret);
+ return log_msg_ret("wr", ret);
+ }
+ ret = dm_rng_read(dev, buf, size);
+ if (ret) {
+ snprintf(result->err_str, VBE_ERR_STR_LEN,
+ "Failed to read random-number device (err=%d)", ret);
+ return log_msg_ret("rd", ret);
+ }
+ ret = ofnode_write_prop(node, "data", buf, size, true);
+ if (ret)
+ return log_msg_ret("wr", -EINVAL);
+
+ return 0;
+}
+
+static int vbe_req_random_seed(ofnode node, struct vbe_result *result)
+{
+ return handle_random_req(node, 0, result);
+}
+
+static int vbe_req_aslr_move(ofnode node, struct vbe_result *result)
+{
+ return -ENOTSUPP;
+}
+
+static int vbe_req_aslr_rand(ofnode node, struct vbe_result *result)
+{
+ return handle_random_req(node, 4, result);
+}
+
+static int vbe_req_efi_runtime_rand(ofnode node, struct vbe_result *result)
+{
+ return handle_random_req(node, 4, result);
+}
+
+static struct vbe_req {
+ const char *compat;
+ vbe_req_func func;
+} vbe_reqs[] = {
+ /* address space layout randomization - move the OS in memory */
+ { "aslr-move", vbe_req_aslr_move },
+
+ /* provide random data for address space layout randomization */
+ { "aslr-rand", vbe_req_aslr_rand },
+
+ /* provide random data for EFI-runtime-services address */
+ { "efi-runtime-rand", vbe_req_efi_runtime_rand },
+
+ /* generate random data bytes to see the OS's rand generator */
+ { "random-rand", vbe_req_random_seed },
+
+};
+
+static int vbe_process_request(ofnode node, struct vbe_result *result)
+{
+ const char *compat, *req_name;
+ int i;
+
+ compat = ofnode_read_string(node, "compatible");
+ if (!compat)
+ return 0;
+
+ if (strlen(compat) <= VBE_PREFIX_LEN ||
+ strncmp(compat, VBE_PREFIX, VBE_PREFIX_LEN))
+ return -EINVAL;
+
+ req_name = compat + VBE_PREFIX_LEN; /* drop "vbe," prefix */
+ for (i = 0; i < ARRAY_SIZE(vbe_reqs); i++) {
+ if (!strcmp(vbe_reqs[i].compat, req_name)) {
+ int ret;
+
+ ret = vbe_reqs[i].func(node, result);
+ if (ret)
+ return log_msg_ret("req", ret);
+ return 0;
+ }
+ }
+ snprintf(result->err_str, VBE_ERR_STR_LEN, "Unknown request: %s",
+ req_name);
+
+ return -ENOTSUPP;
+}
+
+/**
+ * bootmeth_vbe_ft_fixup() - Process VBE OS requests and do device tree fixups
+ *
+ * If there are no images provided, this does nothing and returns 0.
+ *
+ * @ctx: Context for event
+ * @event: Event to process
+ * @return 0 if OK, -ve on error
+ */
+static int bootmeth_vbe_ft_fixup(void *ctx, struct event *event)
+{
+ const struct event_ft_fixup *fixup = &event->data.ft_fixup;
+ const struct bootm_headers *images = fixup->images;
+ ofnode parent, dest_parent, root, node;
+ oftree fit;
+
+ if (!images || !images->fit_hdr_os)
+ return 0;
+
+ /* Get the image node with requests in it */
+ log_debug("fit=%p, noffset=%d\n", images->fit_hdr_os,
+ images->fit_noffset_os);
+ fit = oftree_from_fdt(images->fit_hdr_os);
+ root = oftree_root(fit);
+ if (of_live_active()) {
+ log_warning("Cannot fix up live tree\n");
+ return 0;
+ }
+ if (!ofnode_valid(root))
+ return log_msg_ret("rt", -EINVAL);
+ parent = noffset_to_ofnode(root, images->fit_noffset_os);
+ if (!ofnode_valid(parent))
+ return log_msg_ret("img", -EINVAL);
+ dest_parent = oftree_path(fixup->tree, "/chosen");
+ if (!ofnode_valid(dest_parent))
+ return log_msg_ret("dst", -EINVAL);
+
+ ofnode_for_each_subnode(node, parent) {
+ const char *name = ofnode_get_name(node);
+ struct vbe_result result;
+ ofnode dest;
+ int ret;
+
+ log_debug("copy subnode: %s\n", name);
+ ret = ofnode_add_subnode(dest_parent, name, &dest);
+ if (ret && ret != -EEXIST)
+ return log_msg_ret("add", ret);
+ ret = ofnode_copy_props(node, dest);
+ if (ret)
+ return log_msg_ret("cp", ret);
+
+ *result.err_str = '\0';
+ ret = vbe_process_request(dest, &result);
+ if (ret) {
+ result.errnum = ret;
+ log_err("Failed to process VBE request %s (err=%d)\n",
+ ofnode_get_name(dest), ret);
+ if (*result.err_str) {
+ char *msg = strdup(result.err_str);
+
+ if (!msg)
+ return log_msg_ret("msg", -ENOMEM);
+ ret = ofnode_write_string(dest, "vbe,error",
+ msg);
+ if (ret) {
+ free(msg);
+ return log_msg_ret("str", -ENOMEM);
+ }
+ }
+ if (result.errnum) {
+ ret = ofnode_write_u32(dest, "vbe,errnum",
+ result.errnum);
+ if (ret)
+ return log_msg_ret("num", -ENOMEM);
+ if (result.errnum != -ENOTSUPP)
+ return log_msg_ret("pro",
+ result.errnum);
+ if (result.errnum == -ENOTSUPP &&
+ ofnode_read_bool(dest, "vbe,required")) {
+ log_err("Cannot handle required request: %s\n",
+ ofnode_get_name(dest));
+ return log_msg_ret("req",
+ result.errnum);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+EVENT_SPY(EVT_FT_FIXUP, bootmeth_vbe_ft_fixup);
diff --git a/boot/vbe_simple.c b/boot/vbe_simple.c
index 61b6322ebe2..076b650c25a 100644
--- a/boot/vbe_simple.c
+++ b/boot/vbe_simple.c
@@ -6,6 +6,8 @@
* Written by Simon Glass <sjg@chromium.org>
*/
+#define LOG_CATEGORY LOGC_BOOT
+
#include <common.h>
#include <log.h>
#include <memalign.h>
@@ -199,17 +201,17 @@ int vbe_simple_fixup_node(ofnode node, struct simple_state *state)
version = strdup(state->fw_version);
if (!version)
- return log_msg_ret("ver", -ENOMEM);
+ return log_msg_ret("dup", -ENOMEM);
ret = ofnode_write_string(node, "cur-version", version);
if (ret)
return log_msg_ret("ver", ret);
ret = ofnode_write_u32(node, "cur-vernum", state->fw_vernum);
if (ret)
- return log_msg_ret("ver", ret);
+ return log_msg_ret("num", ret);
ret = ofnode_write_string(node, "bootloader-version", version_string);
if (ret)
- return log_msg_ret("fix", ret);
+ return log_msg_ret("bl", ret);
return 0;
}
@@ -233,7 +235,7 @@ static int bootmeth_vbe_simple_ft_fixup(void *ctx, struct event *event)
*/
for (vbe_find_first_device(&dev); dev; vbe_find_next_device(&dev)) {
struct simple_state state;
- ofnode node;
+ ofnode node, subnode;
int ret;
if (strcmp("vbe_simple", dev->driver->name))
@@ -243,8 +245,8 @@ static int bootmeth_vbe_simple_ft_fixup(void *ctx, struct event *event)
node = oftree_path(tree, "/chosen/fwupd");
if (!ofnode_valid(node))
continue;
- node = ofnode_find_subnode(node, dev->name);
- if (!ofnode_valid(node))
+ subnode = ofnode_find_subnode(node, dev->name);
+ if (!ofnode_valid(subnode))
continue;
log_debug("Fixing up: %s\n", dev->name);
@@ -255,7 +257,7 @@ static int bootmeth_vbe_simple_ft_fixup(void *ctx, struct event *event)
if (ret)
return log_msg_ret("read", ret);
- ret = vbe_simple_fixup_node(node, &state);
+ ret = vbe_simple_fixup_node(subnode, &state);
if (ret)
return log_msg_ret("fix", ret);
}