summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVadim Bendebury <vbendeb@chromium.org>2011-11-03 14:00:57 -0700
committerVadim Bendebury <vbendeb@chromium.org>2011-11-04 09:51:55 -0700
commitb09086595e7844d068994476bd64737dc37a072b (patch)
treebc0f92ec1d18bb96ce7edf49a0784c00873b122e
parent103dcae4b23ba2a3a33447af20342ca9fb4b55ce (diff)
Introduce ability to use hardware SPI mapping for read accesses.
On X86 systems the hardware maps the bootprom SPI flash chip into the top of memory address range. This could be used for accessing all information in the SPI flash. The vboot-reference code requires access to FMAP sections containing cryptographic information, and as of today, u-boot reads the whole sections, which are 64 KB in size, even though the actual areas accessed by vboot-reference are much smaller. A much faster way of accessing this information would be just passing around pointers to the appropriate memory areas. This would eliminate one copy, and also would make sure that only the areas actually accessed get fetched from SPI flash. This patch provides this ability trying to keep code changes to a minimum. New feature is enabled by defining CONFIG_HARDWARE_MAPPED_SPI. The firmware storage API for file reads changes when the new configuration option is set: a pointer to pointer to buffer is passed to the read_spi() function instead of a pointer to buffer. When the new feature is enabled the read_spi() function sets the pointer value to point to the requested data instead of copying the data into the buffer. A new data type is introduced (read_buf_type), which is set to be a (void *) if the new feature is not enabled, or (void **) otherwise. This type is used as the buffer pointer in the spi_read() function. Code allocating/freeing buffers used to keep data read from SPI flash is now conditionally compiled. Call sites for the spi_read() function are modified to adjust the buffer pointer parameter (pass the address of the parameter instead of the parameter, when the new feature is enabled). gbb field access functions can be aliased to gbb_init(), as they all in fact do the same - read a certain section of the gbb area. This change does not benefit the ARM implementations, and makes the code more complicated that it should be. Some u-boot rearchitecture along with vboot_reference API enhancements could address this. A tracking issue (http://code.google.com/p/chromium-os/issues/detail?id=22528) has been opened for that. BUG=chrome-os-partner:6585, chromium-os:22528 TEST=manual . build a new stumpy firmware image . boot the stumpy, observe it start up chromeos. . assess the boot timing using the cbmem.py utility (this modification shaves in excess of 100ms off the boot time). . disable the new feature, build a stumpy image, observe that is still boots chromeOs. . run emerge-terga2_kaen chromeos-u-boot to confirem that ARM version builds cleanly. Change-Id: I4e6ab530d24f5771b5a86a48d3f3135101b469a6 Signed-off-by: Vadim Bendebury <vbendeb@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/11152
-rw-r--r--board/chromebook-x86/coreboot/coreboot.c8
-rw-r--r--common/cmd_vboot_test.c14
-rw-r--r--common/cmd_vboot_twostop.c51
-rw-r--r--include/chromeos/firmware_storage.h12
-rw-r--r--include/chromeos/gbb.h13
-rw-r--r--include/configs/coreboot.h2
-rw-r--r--lib/chromeos/firmware_storage_spi.c46
-rw-r--r--lib/chromeos/gbb.c12
-rw-r--r--lib/vbexport/load_firmware.c3
9 files changed, 133 insertions, 28 deletions
diff --git a/board/chromebook-x86/coreboot/coreboot.c b/board/chromebook-x86/coreboot/coreboot.c
index dace515ea4..e633f3b4b2 100644
--- a/board/chromebook-x86/coreboot/coreboot.c
+++ b/board/chromebook-x86/coreboot/coreboot.c
@@ -144,16 +144,18 @@ static void handle_mrc_cache(void)
return;
}
+#ifndef CONFIG_HARDWARE_MAPPED_SPI
saved_entry = malloc(fme.length);
if (!saved_entry) {
printf("%s: failed to allocate %d bytes\n",
__func__, fme.length);
return;
}
+#endif
- if (file.read(&file, fme.offset, fme.length, saved_entry)) {
+ if (file.read(&file, fme.offset, fme.length, BT_EXTRA saved_entry)) {
printf("%s: failed to read %d bytes\n", __func__, fme.length);
- free(saved_entry);
+ FREE_IF_NEEDED(saved_entry);
return;
}
@@ -173,7 +175,7 @@ static void handle_mrc_cache(void)
} else {
printf("%s: cached storage match\n", __func__);
}
- free(saved_entry);
+ FREE_IF_NEEDED(saved_entry);
}
int misc_init_r(void)
diff --git a/common/cmd_vboot_test.c b/common/cmd_vboot_test.c
index 41963953ab..12e6c4ed59 100644
--- a/common/cmd_vboot_test.c
+++ b/common/cmd_vboot_test.c
@@ -51,10 +51,12 @@ static int do_vboot_test_fwrw(cmd_tbl_t *cmdtp,
return cmd_usage(cmdtp);
}
+#ifndef CONFIG_HARDWARE_MAPPED_SPI
/* Allocate the buffer and fill the target test pattern. */
original_buf = VbExMalloc(test_length);
- target_buf = VbExMalloc(test_length);
verify_buf = VbExMalloc(test_length);
+#endif
+ target_buf = VbExMalloc(test_length);
/* Fill the target test pattern. */
for (i = 0; i < test_length; i++)
@@ -67,7 +69,8 @@ static int do_vboot_test_fwrw(cmd_tbl_t *cmdtp,
}
t0 = VbExGetTimer();
- if (file.read(&file, TEST_FW_START, test_length, original_buf)) {
+ if (file.read(&file, TEST_FW_START,
+ test_length, BT_EXTRA original_buf)) {
VbExDebug("Failed to read firmware!\n");
goto out;
}
@@ -86,7 +89,8 @@ static int do_vboot_test_fwrw(cmd_tbl_t *cmdtp,
ret = 1;
} else {
/* Read back and verify the data. */
- file.read(&file, TEST_FW_START, test_length, verify_buf);
+ file.read(&file, TEST_FW_START, test_length,
+ BT_EXTRA verify_buf);
if (memcmp(target_buf, verify_buf, test_length) != 0) {
VbExDebug("Verify failed. The target data wrote "
"wrong.\n");
@@ -104,9 +108,11 @@ static int do_vboot_test_fwrw(cmd_tbl_t *cmdtp,
out:
file.close(&file);
+#ifndef CONFIG_HARDWARE_MAPPED_SPI
VbExFree(original_buf);
- VbExFree(target_buf);
VbExFree(verify_buf);
+#endif
+ VbExFree(target_buf);
if (ret == 0)
VbExDebug("Read and write firmware test SUCCESS.\n");
diff --git a/common/cmd_vboot_twostop.c b/common/cmd_vboot_twostop.c
index fe1fc54aec..ff6e8c9473 100644
--- a/common/cmd_vboot_twostop.c
+++ b/common/cmd_vboot_twostop.c
@@ -313,6 +313,7 @@ twostop_make_selection(struct twostop_fmap *fmap, firmware_storage_t *file,
fparams.verification_size_A = fparams.verification_size_B = vlength;
+#ifndef CONFIG_HARDWARE_MAPPED_SPI
fparams.verification_block_A = memalign(CACHE_LINE_SIZE, vlength);
if (!fparams.verification_block_A) {
VBDEBUG(PREFIX "failed to allocate vblock A\n");
@@ -323,14 +324,14 @@ twostop_make_selection(struct twostop_fmap *fmap, firmware_storage_t *file,
VBDEBUG(PREFIX "failed to allocate vblock B\n");
goto out;
}
-
+#endif
if (file->read(file, fmap->readwrite_a.vblock.offset, vlength,
- fparams.verification_block_A)) {
+ BT_EXTRA fparams.verification_block_A)) {
VBDEBUG(PREFIX "fail to read vblock A\n");
goto out;
}
if (file->read(file, fmap->readwrite_b.vblock.offset, vlength,
- fparams.verification_block_B)) {
+ BT_EXTRA fparams.verification_block_B)) {
VBDEBUG(PREFIX "fail to read vblock B\n");
goto out;
}
@@ -344,6 +345,7 @@ twostop_make_selection(struct twostop_fmap *fmap, firmware_storage_t *file,
s.fw[0].size = fmap->readwrite_a.boot.length;
s.fw[1].size = fmap->readwrite_b.boot.length;
+#ifndef CONFIG_HARDWARE_MAPPED_SPI
s.fw[0].cache = memalign(CACHE_LINE_SIZE, s.fw[0].size);
if (!s.fw[0].cache) {
VBDEBUG(PREFIX "failed to allocate cache A\n");
@@ -354,6 +356,7 @@ twostop_make_selection(struct twostop_fmap *fmap, firmware_storage_t *file,
VBDEBUG(PREFIX "failed to allocate cache B\n");
goto out;
}
+#endif
s.file = file;
cparams->caller_context = &s;
@@ -368,17 +371,17 @@ twostop_make_selection(struct twostop_fmap *fmap, firmware_storage_t *file,
out:
- free(fparams.verification_block_A);
- free(fparams.verification_block_B);
+ FREE_IF_NEEDED(fparams.verification_block_A);
+ FREE_IF_NEEDED(fparams.verification_block_B);
if (selection == VB_SELECT_FIRMWARE_A) {
*fw_blob_ptr = s.fw[0].cache;
*fw_size_ptr = s.fw[0].size;
- free(s.fw[1].cache);
+ FREE_IF_NEEDED(s.fw[1].cache);
} else if (selection == VB_SELECT_FIRMWARE_B) {
*fw_blob_ptr = s.fw[1].cache;
*fw_size_ptr = s.fw[1].size;
- free(s.fw[0].cache);
+ FREE_IF_NEEDED(s.fw[0].cache);
}
return selection;
@@ -394,7 +397,11 @@ twostop_select_and_set_main_firmware(struct twostop_fmap *fmap,
uint32_t selection;
uint32_t id_offset = 0, id_length = 0;
int firmware_type;
+#ifndef CONFIG_HARDWARE_MAPPED_SPI
uint8_t firmware_id[ID_LEN];
+#else
+ uint8_t *firmware_id;
+#endif
VbCommonParams cparams;
bootstage_mark(BOOTSTAGE_VBOOT_SELECT_AND_SET,
@@ -440,7 +447,7 @@ twostop_select_and_set_main_firmware(struct twostop_fmap *fmap,
if (file->read(file, id_offset,
MIN(sizeof(firmware_id), id_length),
- firmware_id)) {
+ BT_EXTRA firmware_id)) {
VBDEBUG(PREFIX "failed to read active firmware id\n");
firmware_id[0] = '\0';
}
@@ -493,12 +500,18 @@ twostop_jump(crossystem_data_t *cdata, void *fw_blob, uint32_t fw_size)
static int
twostop_init(struct twostop_fmap *fmap, firmware_storage_t *file,
- void *gbb, crossystem_data_t *cdata, void *vb_shared_data)
+ void **gbbp, crossystem_data_t *cdata, void *vb_shared_data)
{
cros_gpio_t wpsw, recsw, devsw;
- GoogleBinaryBlockHeader *gbbh = (GoogleBinaryBlockHeader *)gbb;
- uint8_t hardware_id[ID_LEN], readonly_firmware_id[ID_LEN];
+ GoogleBinaryBlockHeader *gbbh;
+ uint8_t hardware_id[ID_LEN];
+#ifndef CONFIG_HARDWARE_MAPPED_SPI
+ uint8_t readonly_firmware_id[ID_LEN];
+#else
+ uint8_t *readonly_firmware_id;
+#endif
int ret = -1;
+ void *gbb;
bootstage_mark(BOOTSTAGE_VBOOT_TWOSTOP_INIT, "twostop_init");
if (cros_gpio_fetch(CROS_GPIO_WPSW, &wpsw) ||
@@ -527,18 +540,28 @@ twostop_init(struct twostop_fmap *fmap, firmware_storage_t *file,
if (file->read(file, fmap->readonly.firmware_id.offset,
MIN(sizeof(readonly_firmware_id),
fmap->readonly.firmware_id.length),
- readonly_firmware_id)) {
+ BT_EXTRA readonly_firmware_id)) {
VBDEBUG(PREFIX "failed to read firmware ID\n");
readonly_firmware_id[0] = '\0';
}
VBDEBUG(PREFIX "read-only firmware id: \"%s\"\n", readonly_firmware_id);
/* Load basic parts of gbb blob */
+#ifdef CONFIG_HARDWARE_MAPPED_SPI
+ if (gbb_init(gbbp, file, fmap->readonly.gbb.offset)) {
+ VBDEBUG(PREFIX "failed to read gbb\n");
+ goto out;
+ }
+ gbb = *gbbp;
+#else
+ gbb = *gbbp;
if (gbb_init(gbb, file, fmap->readonly.gbb.offset)) {
VBDEBUG(PREFIX "failed to read gbb\n");
goto out;
}
+#endif
+ gbbh = (GoogleBinaryBlockHeader *)gbb;
memcpy(hardware_id, gbb + gbbh->hwid_offset,
MIN(sizeof(hardware_id), gbbh->hwid_size));
VBDEBUG(PREFIX "hardware id: \"%s\"\n", hardware_id);
@@ -637,8 +660,10 @@ static int setup_gbb_and_cdata(void **gbb, crossystem_data_t **cdata,
{
size_t size;
+#ifdef CONFIG_HARDWARE_MAPPED_SPI
*gbb = fdt_decode_chromeos_alloc_region(gd->blob,
"google-binary-block", &size);
+#endif
*cdata = fdt_decode_chromeos_alloc_region(gd->blob, "cros-system-data",
&size);
if (!*gbb || !*cdata) {
@@ -680,7 +705,7 @@ twostop_boot(void)
return VB_SELECT_ERROR;
vb_shared_data = cdata->vb_shared_data;
- if (twostop_init(&fmap, &file, gbb, cdata, vb_shared_data)) {
+ if (twostop_init(&fmap, &file, &gbb, cdata, vb_shared_data)) {
VBDEBUG(PREFIX "failed to init twostop boot\n");
return VB_SELECT_ERROR;
}
diff --git a/include/chromeos/firmware_storage.h b/include/chromeos/firmware_storage.h
index 2ef6e2b034..e45819079b 100644
--- a/include/chromeos/firmware_storage.h
+++ b/include/chromeos/firmware_storage.h
@@ -15,6 +15,16 @@
#include <chromeos/fdt_decode.h>
+#ifndef CONFIG_HARDWARE_MAPPED_SPI
+typedef void *read_buf_type;
+#define BT_EXTRA
+#define FREE_IF_NEEDED(p) free(p)
+#else
+typedef void **read_buf_type;
+#define BT_EXTRA (read_buf_type) &
+#define FREE_IF_NEEDED(p)
+#endif
+
/**
* These read or write [count] bytes starting from [offset] of storage into or
* from the [buf].
@@ -27,7 +37,7 @@
*/
typedef struct firmware_storage_t {
int (*read)(struct firmware_storage_t *file,
- uint32_t offset, uint32_t count, void *buf);
+ uint32_t offset, uint32_t count, read_buf_type buf);
int (*write)(struct firmware_storage_t *file,
uint32_t offset, uint32_t count, void *buf);
int (*close)(struct firmware_storage_t *file);
diff --git a/include/chromeos/gbb.h b/include/chromeos/gbb.h
index 0d54f8fdd8..c3bc304b38 100644
--- a/include/chromeos/gbb.h
+++ b/include/chromeos/gbb.h
@@ -24,8 +24,9 @@
* @param gbb_offset Offset of GBB in flashrom device
* @return zero if this succeeds, non-zero if this fails
*/
-int gbb_init(void *gbb, firmware_storage_t *file, uint32_t gbb_offset);
+int gbb_init(read_buf_type gbb, firmware_storage_t *file, uint32_t gbb_offset);
+#ifndef CONFIG_HARDWARE_MAPPED_SPI
/**
* This loads the BMP block of GBB from flashrom.
*
@@ -34,7 +35,7 @@ int gbb_init(void *gbb, firmware_storage_t *file, uint32_t gbb_offset);
* @param gbb_offset Offset of GBB in flashrom device
* @return zero if this succeeds, non-zero if this fails
*/
-int gbb_read_bmp_block(void *gbb,
+int gbb_read_bmp_block(read_buf_type gbb,
firmware_storage_t *file, uint32_t gbb_offset);
/*
@@ -45,9 +46,15 @@ int gbb_read_bmp_block(void *gbb,
* @param gbb_offset Offset of GBB in flashrom device
* @return zero if this succeeds, non-zero if this fails
*/
-int gbb_read_recovery_key(void *gbb,
+int gbb_read_recovery_key(read_buf_type gbb,
firmware_storage_t *file, uint32_t gbb_offset);
+#else
+
+#define gbb_read_bmp_block gbb_init
+#define gbb_read_recovery_key gbb_init
+
+#endif
/**
* This is a sanity check of GBB blob.
*
diff --git a/include/configs/coreboot.h b/include/configs/coreboot.h
index e76edce6d6..47f4634f3c 100644
--- a/include/configs/coreboot.h
+++ b/include/configs/coreboot.h
@@ -318,6 +318,8 @@
#undef CONFIG_CMD_NET
#endif
+#define CONFIG_HARDWARE_MAPPED_SPI
+
/* Board specific late time init */
#define CONFIG_MISC_INIT_R
diff --git a/lib/chromeos/firmware_storage_spi.c b/lib/chromeos/firmware_storage_spi.c
index 26e01046db..a2d80b585b 100644
--- a/lib/chromeos/firmware_storage_spi.c
+++ b/lib/chromeos/firmware_storage_spi.c
@@ -47,19 +47,61 @@ static int border_check(struct spi_flash *flash, uint32_t offset,
return 0;
}
+#ifdef CONFIG_HARDWARE_MAPPED_SPI
+
+#include <libfdt.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * When using hardware mapped SPI the offset passed to the file_read()
+ * function should be added to the base address of the SPI flash in the CPI
+ * memory. set_spi_flash_base() retrieves the flash chip base address from the
+ * flash map device tree section.
+ */
+static uint32_t spi_flash_base_addr;
+
+void set_spi_flash_base(void)
+{
+ int fmap_offset;
+ uint32_t *property;
+ int length;
+ const void *blob = gd->blob;
+
+ fmap_offset = fdt_node_offset_by_compatible(blob, -1,
+ "chromeos,flashmap");
+ if (fmap_offset < 0) {
+ VBDEBUG(PREFIX "chromeos,flashmap node is missing\n");
+ return;
+ }
+ property = (uint32_t *)fdt_getprop(blob, fmap_offset, "reg", &length);
+ if (!property) {
+ VBDEBUG(PREFIX "reg property missing in flashmap!'\n");
+ return;
+ }
+ spi_flash_base_addr = fdt32_to_cpu(property[0]);
+}
+
+#endif
+
static int read_spi(firmware_storage_t *file, uint32_t offset, uint32_t count,
- void *buf)
+ read_buf_type buf)
{
struct spi_flash *flash = file->context;
if (border_check(flash, offset, count))
return -1;
+#ifndef CONFIG_HARDWARE_MAPPED_SPI
if (flash->read(flash, offset, count, buf)) {
VBDEBUG(PREFIX "SPI read fail\n");
return -1;
}
-
+#else
+ if (!spi_flash_base_addr)
+ set_spi_flash_base();
+ *buf = (void *) (spi_flash_base_addr + offset);
+#endif
return 0;
}
diff --git a/lib/chromeos/gbb.c b/lib/chromeos/gbb.c
index efadcd3037..25d5741318 100644
--- a/lib/chromeos/gbb.c
+++ b/lib/chromeos/gbb.c
@@ -16,8 +16,9 @@
#define PREFIX "gbb: "
-int gbb_init(void *gbb, firmware_storage_t *file, uint32_t gbb_offset)
+int gbb_init(read_buf_type gbb, firmware_storage_t *file, uint32_t gbb_offset)
{
+#ifndef CONFIG_HARDWARE_MAPPED_SPI
GoogleBinaryBlockHeader *gbbh = (GoogleBinaryBlockHeader *)gbb;
if (file->read(file, gbb_offset, sizeof(*gbbh), gbbh)) {
@@ -38,10 +39,18 @@ int gbb_init(void *gbb, firmware_storage_t *file, uint32_t gbb_offset)
VBDEBUG(PREFIX "failed to read root key\n");
return 1;
}
+#else
+ if (file->read(file, gbb_offset,
+ sizeof(GoogleBinaryBlockHeader), gbb)) {
+ VBDEBUG(PREFIX "failed to read GBB header\n");
+ return 1;
+ }
+#endif
return 0;
}
+#ifndef CONFIG_HARDWARE_MAPPED_SPI
int gbb_read_bmp_block(void *gbb, firmware_storage_t *file, uint32_t gbb_offset)
{
GoogleBinaryBlockHeader *gbbh = (GoogleBinaryBlockHeader *)gbb;
@@ -70,6 +79,7 @@ int gbb_read_recovery_key(void *gbb,
return 0;
}
+#endif
int gbb_check_integrity(uint8_t *gbb)
{
diff --git a/lib/vbexport/load_firmware.c b/lib/vbexport/load_firmware.c
index 847418293e..49b0215351 100644
--- a/lib/vbexport/load_firmware.c
+++ b/lib/vbexport/load_firmware.c
@@ -49,7 +49,8 @@ VbError_t VbExHashFirmwareBody(VbCommonParams* cparams, uint32_t firmware_index)
*/
s->fw[i].size = firmware_body_size((uintptr_t)s->fw[i].vblock);
- if (file->read(file, s->fw[i].offset, s->fw[i].size, s->fw[i].cache)) {
+ if (file->read(file, s->fw[i].offset,
+ s->fw[i].size, BT_EXTRA(s->fw[i].cache))) {
VBDEBUG(PREFIX "fail to read firmware: %d\n", firmware_index);
return 1;
}