[coreboot-gerrit] New patch to review for coreboot: 75f332f vboot: allow for non-memory-mapped VBOOT regions

Marc Jones (marc.jones@se-eng.com) gerrit at coreboot.org
Mon Dec 8 00:59:59 CET 2014


Marc Jones (marc.jones at se-eng.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/7709

-gerrit

commit 75f332ff038f7ac550ca658a8181075233c23789
Author: Aaron Durbin <adurbin at chromium.org>
Date:   Thu Mar 20 14:28:17 2014 -0500

    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 at chromium.org>
    Original-Reviewed-on: https://chromium-review.googlesource.com/190924
    Original-Reviewed-by: Hung-Te Lin <hungte at chromium.org>
    (cherry picked from commit aee0280bbfe110eae88aa297b433c1038c6fe8a3)
    Signed-off-by: Marc Jones <marc.jones at se-eng.com>
    
    Change-Id: Ia020d1eebad753da950342656cd11b84e9a85376
---
 src/drivers/spi/Kconfig                        |   7 +
 src/vendorcode/google/chromeos/Makefile.inc    |   5 +
 src/vendorcode/google/chromeos/chromeos.h      |   7 +
 src/vendorcode/google/chromeos/vboot_context.h |  22 ++-
 src/vendorcode/google/chromeos/vboot_handoff.c |  29 ++++
 src/vendorcode/google/chromeos/vboot_loader.c  | 194 +++++++++++++++++++++++--
 src/vendorcode/google/chromeos/vboot_wrapper.c | 124 +++++++---------
 7 files changed, 296 insertions(+), 92 deletions(-)

diff --git a/src/drivers/spi/Kconfig b/src/drivers/spi/Kconfig
index 4cc439a..f96bf9f 100644
--- a/src/drivers/spi/Kconfig
+++ b/src/drivers/spi/Kconfig
@@ -26,6 +26,13 @@ config SPI_FLASH
 
 if SPI_FLASH
 
+config SPI_FLASH_MEMORY_MAPPED
+	bool
+	default y if ARCH_X86
+	default n if !ARCH_X86
+	help
+	  Inform system if SPI is memory-mapped or not.
+
 config SPI_FLASH_SMM
 	bool "SPI flash driver support in SMM"
 	default n
diff --git a/src/vendorcode/google/chromeos/Makefile.inc b/src/vendorcode/google/chromeos/Makefile.inc
index d02c09f..678c4ee 100644
--- a/src/vendorcode/google/chromeos/Makefile.inc
+++ b/src/vendorcode/google/chromeos/Makefile.inc
@@ -43,6 +43,10 @@ ramstage-y += vboot_handoff.c
 romstage-y += vboot_loader.c
 rmodules_$(ARCH-romstage-y)-y += vboot_wrapper.c
 
+ifneq ($(CONFIG_SPI_FLASH_MEMORY_MAPPED),y)
+VBOOT_MAKEFLAGS = REGION_READ=1
+endif
+
 VB_LIB = $(obj)/external/vboot_reference/vboot_fw.a
 # Currently, vboot comes into picture only during the romstage, thus
 # is compiled for being used in romstage only. Since, we are splitting
@@ -83,6 +87,7 @@ $(VB_LIB):
 		CC="$(CC_romstage)" \
 		CFLAGS="$(VBOOT_CFLAGS)" \
 		make -C $(VB_SOURCE) \
+		$(VBOOT_MAKEFLAGS) \
 		BUILD=../$(dir $(VB_LIB)) \
 		V=$(V) \
 		fwlib
diff --git a/src/vendorcode/google/chromeos/chromeos.h b/src/vendorcode/google/chromeos/chromeos.h
index 20cac99..c162891 100644
--- a/src/vendorcode/google/chromeos/chromeos.h
+++ b/src/vendorcode/google/chromeos/chromeos.h
@@ -36,6 +36,13 @@ void init_chromeos(int bootmode);
 
 struct romstage_handoff;
 #if CONFIG_VBOOT_VERIFY_FIRMWARE
+/*
+ * This is a dual purpose routine. If dest is non-NULL the region at
+ * offset_addr will be read into the area pointed to by dest.  If dest
+ * is NULL,the region will be mapped to a memory location. NULL is
+ * returned on error else the location of the requested region.
+ */
+void *vboot_get_region(uintptr_t offset_addr, size_t size, void *dest);
 /* Returns 0 on success < 0 on error. */
 int vboot_get_handoff_info(void **addr, uint32_t *size);
 int vboot_enable_developer(void);
diff --git a/src/vendorcode/google/chromeos/vboot_context.h b/src/vendorcode/google/chromeos/vboot_context.h
index 72a0535..822fed4 100644
--- a/src/vendorcode/google/chromeos/vboot_context.h
+++ b/src/vendorcode/google/chromeos/vboot_context.h
@@ -22,17 +22,30 @@
 #include <stdint.h>
 #include <vboot_api.h>
 
+struct cbmem_entry;
+
 /* The vboot context structure provides all the necessary data for invoking
  * vboot. The vboot loader sets everything up for vboot module to use. */
 
+struct vboot_region {
+	/*
+	 * The offset_addr field may be an offset or an address. It depends
+	 * on the capabilities of the underlying architecture.
+	 */
+	uintptr_t offset_addr;
+	int32_t size;
+};
+
 struct vboot_context {
 	struct vboot_handoff *handoff;
 	VbCommonParams *cparams;
 	VbSelectFirmwareParams *fparams;
-	uint8_t *fw_a;
-	uint32_t fw_a_size;
-	uint8_t *fw_b;
-	uint32_t fw_b_size;
+	struct vboot_region gbb;
+	struct vboot_region vblock_a;
+	struct vboot_region fw_a;
+	struct vboot_region vblock_b;
+	struct vboot_region fw_b;
+	const struct cbmem_entry *vblocks;
 	/* Callback implementations living in romstage. */
 	void (*read_vbnv)(uint8_t *vbnv_copy);
 	void (*save_vbnv)(const uint8_t *vbnv_copy);
@@ -43,6 +56,7 @@ struct vboot_context {
 	                    size_t *recv_len);
 	void (*log_msg)(const char *fmt, va_list args);
 	void (*fatal_error)(void);
+	void *(*get_region)(uintptr_t offset_addr, size_t size, void *dest);
 };
 
 #endif /* VBOOT_CONTEXT_H */
diff --git a/src/vendorcode/google/chromeos/vboot_handoff.c b/src/vendorcode/google/chromeos/vboot_handoff.c
index 937b2e3..c3c5a13 100644
--- a/src/vendorcode/google/chromeos/vboot_handoff.c
+++ b/src/vendorcode/google/chromeos/vboot_handoff.c
@@ -18,8 +18,10 @@
  */
 
 #include <stddef.h>
+#include <string.h>
 #include "chromeos.h"
 #include <boot/coreboot_tables.h>
+#include <cbfs.h>
 #include <cbmem.h>
 #include <console/console.h>
 #include <payload_loader.h>
@@ -52,6 +54,33 @@ int vboot_enable_recovery(void)
 	return !!(vbho->init_params.out_flags & VB_INIT_OUT_ENABLE_RECOVERY);
 }
 
+void *vboot_get_region(uintptr_t offset_addr, size_t size, void *dest)
+{
+      if (IS_ENABLED(CONFIG_SPI_FLASH_MEMORY_MAPPED)) {
+               if (dest != NULL)
+                       return memcpy(dest, (void *)offset_addr, size);
+               else
+                       return (void *)offset_addr;
+       } else {
+               struct cbfs_media default_media, *media = &default_media;
+               void *cache;
+
+               init_default_cbfs_media(media);
+               media->open(media);
+               if (dest != NULL) {
+                       cache = dest;
+                       if (media->read(media, dest, offset_addr, size) != size)
+                               cache = NULL;
+               } else {
+                       cache = media->map(media, offset_addr, size);
+                       if (cache == CBFS_MEDIA_INVALID_MAP_ADDRESS)
+                               cache = NULL;
+               }
+               media->close(media);
+               return cache;
+       }
+}
+
 static void *vboot_get_payload(size_t *len)
 {
 	struct vboot_handoff *vboot_handoff;
diff --git a/src/vendorcode/google/chromeos/vboot_loader.c b/src/vendorcode/google/chromeos/vboot_loader.c
index cfdc5af..8e0babe 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");
diff --git a/src/vendorcode/google/chromeos/vboot_wrapper.c b/src/vendorcode/google/chromeos/vboot_wrapper.c
index d008de1..5611451 100644
--- a/src/vendorcode/google/chromeos/vboot_wrapper.c
+++ b/src/vendorcode/google/chromeos/vboot_wrapper.c
@@ -31,43 +31,9 @@
 /* Keep a global context pointer around for the callbacks to use. */
 static struct vboot_context *gcontext;
 
-/* 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. */
-#define MAX_NUM_COMPONENTS 20
-
-struct component_entry {
-	uint32_t offset;
-	uint32_t size;
-} __attribute__((packed));
-
-struct components {
-	uint32_t num_components;
-	struct component_entry entries[0];
-} __attribute__((packed));
-
-
-static void parse_component(const struct components *components, int num,
-                            struct firmware_component *fw)
-{
-	const char *base;
-
-	if (num >= components->num_components)
-		return;
-
-	/* Offsets are relative to the stat of the book keeping structure. */
-	base = (void *)components;
-
-	fw->address = (uint32_t)&base[components->entries[num].offset];
-	fw->size = (uint32_t)components->entries[num].size;
-}
-
 static void vboot_wrapper(void *arg)
 {
-	int i;
 	VbError_t res;
-	const struct components *components;
 	struct vboot_context *context;
 
 	context = arg;
@@ -86,23 +52,6 @@ static void vboot_wrapper(void *arg)
 
 	if (res != VBERROR_SUCCESS)
 		return;
-
-	/* 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)
-		components = (void *)context->fw_a;
-	else if  (context->handoff->selected_firmware == VB_SELECT_FIRMWARE_B)
-		components = (void *)context->fw_b;
-	else
-		return;
-
-	for (i = 0; i < MAX_PARSED_FW_COMPONENTS; i++) {
-		parse_component(components, i,
-		                &context->handoff->components[i]);
-	}
 }
 
 void VbExError(const char *format, ...)
@@ -203,43 +152,51 @@ void *Memset(void *dest, const uint8_t c, uint64_t n)
 	return memset(dest, c, n);
 }
 
+static inline size_t get_hash_block_size(size_t requested_size)
+{
+	if (!IS_ENABLED(CONFIG_SPI_FLASH_MEMORY_MAPPED)) {
+		const size_t block_size = 64 * 1024;
+		if (requested_size > block_size)
+			return block_size;
+	}
+	return requested_size;
+}
+
 VbError_t VbExHashFirmwareBody(VbCommonParams *cparams, uint32_t firmware_index)
 {
 	uint8_t *data;
-	uint32_t size;
-	uint32_t data_size;
-	struct components *components;
-	uint32_t i;
+	struct vboot_region *region;
+	struct vboot_context *ctx;
+	size_t data_size;
+	uintptr_t offset_addr;
+
+	ctx = cparams->caller_context;
 
 	switch (firmware_index) {
 	case VB_SELECT_FIRMWARE_A:
-		data = gcontext->fw_a;
-		size = gcontext->fw_a_size;
+		region = &ctx->fw_a;
 		break;
 	case VB_SELECT_FIRMWARE_B:
-		data = gcontext->fw_b;
-		size = gcontext->fw_b_size;
+		region = &ctx->fw_b;
 		break;
 	default:
 		return VBERROR_UNKNOWN;
 	}
 
-	components = (void *)data;
-	data_size = sizeof(struct components);
-
-	if (components->num_components > MAX_NUM_COMPONENTS)
-		return VBERROR_UNKNOWN;
-
-	data_size +=
-		components->num_components * sizeof(struct component_entry);
+	data_size = region->size;
+	offset_addr = region->offset_addr;
+	while (data_size) {
+		size_t block_size;
 
-	for (i = 0; i < components->num_components; i++)
-		data_size += ALIGN(components->entries[i].size, 4);
-
-	if (size < data_size)
+		block_size = get_hash_block_size(data_size);
+		data = ctx->get_region(offset_addr, block_size, NULL);
+		if (data == NULL)
 			return VBERROR_UNKNOWN;
+		VbUpdateFirmwareBodyHash(cparams, data, block_size);
 
-	VbUpdateFirmwareBodyHash(cparams, data, data_size);
+		data_size -= block_size;
+		offset_addr += block_size;
+	}
 
 	return VBERROR_SUCCESS;
 }
@@ -274,4 +231,27 @@ VbError_t VbExTpmSendReceive(const uint8_t *request, uint32_t request_length,
 	return VBERROR_SUCCESS;
 }
 
+#if !CONFIG_SPI_FLASH_MEMORY_MAPPED
+VbError_t VbExRegionRead(VbCommonParams *cparams,
+                         enum vb_firmware_region region, uint32_t offset,
+                         uint32_t size, void *buf)
+{
+	struct vboot_context *ctx;
+	VbExDebug("VbExRegionRead: offset=%x size=%x, buf=%p\n",
+	          offset, size, buf);
+	ctx = cparams->caller_context;
+
+	if (region == VB_REGION_GBB) {
+		if (offset + size > cparams->gbb_size)
+			return VBERROR_REGION_READ_INVALID;
+		offset += ctx->gbb.offset_addr;
+		if (ctx->get_region(offset, size, buf) == NULL)
+			return VBERROR_REGION_READ_INVALID;
+		return VBERROR_SUCCESS;
+	}
+
+	return VBERROR_UNSUPPORTED_REGION;
+}
+#endif /* CONFIG_SPI_FLASH_MEMORY_MAPPED */
+
 RMODULE_ENTRY(vboot_wrapper);



More information about the coreboot-gerrit mailing list