diff options
Diffstat (limited to 'boot')
-rw-r--r-- | boot/Makefile | 2 | ||||
-rw-r--r-- | boot/bootdev-uclass.c | 4 | ||||
-rw-r--r-- | boot/bootm.c | 2 | ||||
-rw-r--r-- | boot/image-fdt.c | 37 | ||||
-rw-r--r-- | boot/vbe_fixup.c | 233 | ||||
-rw-r--r-- | boot/vbe_simple.c | 16 |
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); } |