aboutsummaryrefslogtreecommitdiff
path: root/src/vendorcode/google/chromeos/vboot_loader.c
diff options
context:
space:
mode:
authorAaron Durbin <adurbin@chromium.org>2014-03-20 14:28:17 -0500
committerMarc Jones <marc.jones@se-eng.com>2014-12-09 18:41:00 +0100
commit30974bc2f5f4764425e69256782cca03b290c4f4 (patch)
tree43643987aeb0056ce5e5e154f464e856dc352919 /src/vendorcode/google/chromeos/vboot_loader.c
parentf72f9e7c14a2a5df92c30a3ec88d15b9aca30b1e (diff)
vboot: allow for non-memory-mapped VBOOT regions
Depending on the platform the underlying regions vboot requires may not be accessible through a memory-mapped interface. Allow for non-memory-mapped regions by providing a region request abstraction. There is then only a few touch points in the code to provide compile-time decision making no how to obtain a region. For the vblocks a temporary area is allocated from cbmem. They are then read from the SPI into the temporarily buffer. BUG=chrome-os-partner:27094 BRANCH=None TEST=Built and booted a rambi with vboot verification. Original-Change-Id: I828a7c36387a8eb573c5a0dd020fe9abad03d902 Original-Signed-off-by: Aaron Durbin <adurbin@chromium.org> Original-Reviewed-on: https://chromium-review.googlesource.com/190924 Original-Reviewed-by: Hung-Te Lin <hungte@chromium.org> (cherry picked from commit aee0280bbfe110eae88aa297b433c1038c6fe8a3) Signed-off-by: Marc Jones <marc.jones@se-eng.com> Change-Id: Ia020d1eebad753da950342656cd11b84e9a85376 Reviewed-on: http://review.coreboot.org/7709 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Georgi <pgeorgi@google.com>
Diffstat (limited to 'src/vendorcode/google/chromeos/vboot_loader.c')
-rw-r--r--src/vendorcode/google/chromeos/vboot_loader.c194
1 files changed, 178 insertions, 16 deletions
diff --git a/src/vendorcode/google/chromeos/vboot_loader.c b/src/vendorcode/google/chromeos/vboot_loader.c
index cfdc5af7df..8e0babed35 100644
--- a/src/vendorcode/google/chromeos/vboot_loader.c
+++ b/src/vendorcode/google/chromeos/vboot_loader.c
@@ -20,6 +20,7 @@
#include <arch/stages.h>
#include <stdint.h>
#include <stddef.h>
+#include <string.h>
#include <cbfs.h>
#include <cbmem.h>
#include <console/console.h>
@@ -37,10 +38,29 @@
#include "vboot_context.h"
#include "vboot_handoff.h"
+/* The FW areas consist of multiple components. At the beginning of
+ * each area is the number of total compoments as well as the size and
+ * offset for each component. One needs to caculate the total size of the
+ * signed firmware region based off of the embedded metadata. */
+
+struct component_entry {
+ uint32_t offset;
+ uint32_t size;
+} __attribute__((packed));
+
+struct components {
+ uint32_t num_components;
+ struct component_entry entries[0];
+} __attribute__((packed));
+
+
+#define TEMP_CBMEM_ID_VBOOT 0xffffffff
+#define TEMP_CBMEM_ID_VBLOCKS 0xfffffffe
+
static void vboot_run_stub(struct vboot_context *context)
{
struct rmod_stage_load rmod_stage = {
- .cbmem_id = 0xffffffff,
+ .cbmem_id = TEMP_CBMEM_ID_VBOOT,
.name = CONFIG_CBFS_PREFIX "/vboot",
};
void (*entry)(struct vboot_context *context);
@@ -73,6 +93,142 @@ static void fatal_error(void)
hard_reset();
}
+static void locate_region(const char *name, struct vboot_region *region)
+{
+ region->size = find_fmap_entry(name, (void **)&region->offset_addr);
+}
+
+static int fw_region_size(struct vboot_region *r)
+{
+ struct components *fw_info;
+ int32_t size;
+ size_t req_size;
+ int i;
+
+ req_size = sizeof(*fw_info);
+ req_size += sizeof(struct component_entry) * MAX_PARSED_FW_COMPONENTS;
+
+ /* This will leak a mapping. */
+ fw_info = vboot_get_region(r->offset_addr, req_size, NULL);
+
+ if (fw_info == NULL)
+ return -1;
+
+ if (fw_info->num_components > MAX_PARSED_FW_COMPONENTS)
+ return -1;
+
+ size = sizeof(*fw_info);
+ size += sizeof(struct component_entry) * fw_info->num_components;
+
+ for (i = 0; i < fw_info->num_components; i++)
+ size += ALIGN(fw_info->entries[i].size, sizeof(uint32_t));
+
+ /* Check that size of comopnents does not exceed the region's size. */
+ if (size > r->size)
+ return -1;
+
+ /* Update region with the correct size. */
+ r->size = size;
+
+ return 0;
+}
+
+static int vboot_fill_params(struct vboot_context *ctx)
+{
+ VbCommonParams *cparams;
+ VbSelectFirmwareParams *fparams;
+
+ if (fw_region_size(&ctx->fw_a))
+ return -1;
+
+ if (fw_region_size(&ctx->fw_b))
+ return -1;
+
+ cparams = ctx->cparams;
+ fparams = ctx->fparams;
+
+ cparams->gbb_size = ctx->gbb.size;
+ fparams->verification_size_A = ctx->vblock_a.size;
+ fparams->verification_size_B = ctx->vblock_b.size;
+
+ if (IS_ENABLED(CONFIG_SPI_FLASH_MEMORY_MAPPED)) {
+ /* Get memory-mapped pointers to the regions. */
+ cparams->gbb_data = vboot_get_region(ctx->gbb.offset_addr,
+ ctx->gbb.size, NULL);
+ fparams->verification_block_A =
+ vboot_get_region(ctx->vblock_a.offset_addr,
+ ctx->vblock_a.size, NULL);
+ fparams->verification_block_B =
+ vboot_get_region(ctx->vblock_b.offset_addr,
+ ctx->vblock_b.size, NULL);
+ } else {
+ /*
+ * Copy the vblock info into a buffer in cbmem. The gbb will
+ * be read using VbExRegionRead().
+ */
+ char *dest;
+ size_t vblck_sz;
+
+ vblck_sz = ctx->vblock_a.size + ctx->vblock_b.size;
+ ctx->vblocks = cbmem_entry_add(TEMP_CBMEM_ID_VBLOCKS, vblck_sz);
+ if (ctx->vblocks == NULL)
+ return -1;
+ dest = cbmem_entry_start(ctx->vblocks);
+ if (vboot_get_region(ctx->vblock_a.offset_addr,
+ ctx->vblock_a.size, dest) == NULL)
+ return -1;
+ fparams->verification_block_A = (void *)dest;
+ dest += ctx->vblock_a.size;
+ if (vboot_get_region(ctx->vblock_b.offset_addr,
+ ctx->vblock_b.size, dest) == NULL)
+ return -1;
+ fparams->verification_block_B = (void *)dest;
+ }
+
+ return 0;
+}
+
+static void fill_handoff(struct vboot_context *context)
+{
+ struct components *fw_info;
+ struct vboot_region *region;
+ size_t req_size;
+ int i;
+
+ /* Fix up the handoff structure. */
+ context->handoff->selected_firmware =
+ context->fparams->selected_firmware;
+
+ /* Parse out the components for downstream consumption. */
+ if (context->handoff->selected_firmware == VB_SELECT_FIRMWARE_A)
+ region = &context->fw_a;
+ else if (context->handoff->selected_firmware == VB_SELECT_FIRMWARE_B)
+ region = &context->fw_b;
+ else
+ return;
+
+ req_size = sizeof(*fw_info);
+ req_size += sizeof(struct component_entry) * MAX_PARSED_FW_COMPONENTS;
+
+ /* This will leak a mapping. */
+ fw_info = vboot_get_region(region->offset_addr, req_size, NULL);
+
+ if (fw_info == NULL)
+ return;
+
+ for (i = 0; i < fw_info->num_components; i++) {
+ context->handoff->components[i].address =
+ region->offset_addr + fw_info->entries[i].offset;
+ context->handoff->components[i].size = fw_info->entries[i].size;
+ }
+}
+
+static void vboot_clean_up(struct vboot_context *context)
+{
+ if (context->vblocks != NULL)
+ cbmem_entry_remove(context->vblocks);
+}
+
static void vboot_invoke_wrapper(struct vboot_handoff *vboot_handoff)
{
VbCommonParams cparams;
@@ -104,30 +260,30 @@ static void vboot_invoke_wrapper(struct vboot_handoff *vboot_handoff)
context.cparams = &cparams;
context.fparams = &fparams;
- cparams.gbb_size = find_fmap_entry("GBB", &cparams.gbb_data);
cparams.shared_data_blob = &vboot_handoff->shared_data[0];
cparams.shared_data_size = VB_SHARED_DATA_MIN_SIZE;
cparams.caller_context = &context;
- fparams.verification_size_A =
- find_fmap_entry("VBLOCK_A", &fparams.verification_block_A);
- fparams.verification_size_B =
- find_fmap_entry("VBLOCK_B", &fparams.verification_block_B);
-
- context.fw_a_size =
- find_fmap_entry("FW_MAIN_A", (void **)&context.fw_a);
- context.fw_b_size =
- find_fmap_entry("FW_MAIN_B", (void **)&context.fw_b);
+ locate_region("GBB", &context.gbb);
+ locate_region("VBLOCK_A", &context.vblock_a);
+ locate_region("VBLOCK_B", &context.vblock_b);
+ locate_region("FW_MAIN_A", &context.fw_a);
+ locate_region("FW_MAIN_B", &context.fw_b);
/* Check all fmap entries. */
- if (context.fw_a == NULL || context.fw_b == NULL ||
- fparams.verification_block_A == NULL ||
- fparams.verification_block_B == NULL ||
- cparams.gbb_data == NULL) {
+ if (context.fw_a.size < 0 || context.fw_b.size < 0 ||
+ context.vblock_a.size < 0 || context.vblock_b.size < 0 ||
+ context.gbb.size < 0) {
printk(BIOS_DEBUG, "Not all fmap entries found for vboot.\n");
return;
}
+ /* Fill in vboot parameters. */
+ if (vboot_fill_params(&context)) {
+ vboot_clean_up(&context);
+ return;
+ }
+
/* Initialize callbacks. */
context.read_vbnv = &read_vbnv;
context.save_vbnv = &save_vbnv;
@@ -137,8 +293,13 @@ static void vboot_invoke_wrapper(struct vboot_handoff *vboot_handoff)
context.tis_sendrecv = &tis_sendrecv;
context.log_msg = &log_msg;
context.fatal_error = &fatal_error;
+ context.get_region = &vboot_get_region;
vboot_run_stub(&context);
+
+ fill_handoff(&context);
+
+ vboot_clean_up(&context);
}
#if CONFIG_RELOCATABLE_RAMSTAGE
@@ -228,7 +389,8 @@ static void vboot_load_ramstage(struct vboot_handoff *vboot_handoff,
printk(BIOS_DEBUG, "RW ramstage image at 0x%08x, 0x%08x bytes.\n",
fwc->address, fwc->size);
- stage = vboot_get_region(fwc->address, fwc->size);
+ /* This will leak a mapping. */
+ stage = vboot_get_region(fwc->address, fwc->size, NULL);
if (stage == NULL) {
printk(BIOS_DEBUG, "Unable to get RW ramstage region.\n");