diff options
author | Randall Spangler <rspangler@chromium.org> | 2015-02-04 10:44:02 -0800 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-02-05 21:03:01 +0000 |
commit | f8af89c40d974e79b3e69698f6d8aa98e0e40fc9 (patch) | |
tree | 9d469c96dd9240af3bff374aa93dc92a041c45bc /common | |
parent | c0be4409522bc53447940ac88aff455a6844427c (diff) | |
download | chrome-ec-f8af89c40d974e79b3e69698f6d8aa98e0e40fc9.tar.gz |
Support vboot hash and system version if flash isn't memory-mapped
Some EC chips (mec1322) use external SPI flash which is not mapped
into the EC CPU's address space. These must explicitly read data from
flash when calculating the vboot hash or reading the version string of
the image which isn't currently loaded into code RAM.
To test this bug, I used a board with known working mapped flash, and
temporarily patched it to act like it didn't have mapped flash.
Also add a flashread console command, useful for manually testing.
BUG=chrome-os-partner:35308
BRANCH=glower,strago
TEST=manual
1. Apply this patch to samus
2. Check result for 'vboot hash RW'
3. Check result for 'version'
4a. In board/samus/board.h, #undef CONFIG_FLASH_MAPPED and
#define CONFIG_CMD_FLASH
4b. In chip/lm4/flash.c, add the following:
int flash_physical_read(int offset, int size, char *data)
{
const char *src;
if (offset > CONFIG_FLASH_SIZE ||
offset + size > CONFIG_FLASH_SIZE)
return EC_ERROR_INVAL;
src = (const char *)((uintptr_t)CONFIG_FLASH_BASE + offset);
memcpy(data, src, size);
return EC_SUCCESS;
}
Steps 4a,4b will make the LM4 chip act like it doesn't have
memory-mapped flash.
5. From the dev system, util/flash_ec --board=samus --ro
6. Check result for 'vboot hash RW'. Should be same as 2.
7. Check result for 'version' for RW version. Should be same as in 3.
8. From the dev system, util/flash_ec --board=samus
9. sysjump rw
10. Check result for 'version' for RO version. Should be same as in 3.
11. Compare 'flashread 0x100 0x100' with 'md 0x100 0x40'. The results
should be the same (but endian-swapped, since flashread is byte
ordered and md is 32-bit ordered).
12. Revert changes from steps 4a-4b.
Change-Id: I951d6f5603a84e326740936e4e84dfe6296a0f59
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/246200
Reviewed-by: Shawn N <shawnn@chromium.org>
Diffstat (limited to 'common')
-rw-r--r-- | common/flash.c | 135 | ||||
-rw-r--r-- | common/system.c | 30 | ||||
-rw-r--r-- | common/vboot_hash.c | 39 |
3 files changed, 180 insertions, 24 deletions
diff --git a/common/flash.c b/common/flash.c index 3b269deb46..5f4f5fc2d6 100644 --- a/common/flash.c +++ b/common/flash.c @@ -36,6 +36,17 @@ struct persist_state { /* Protect persist state and RO firmware at boot */ #define PERSIST_FLAG_PROTECT_RO 0x02 +int flash_range_ok(int offset, int size_req, int align) +{ + if (offset < 0 || size_req < 0 || + offset + size_req > CONFIG_FLASH_SIZE || + (offset | size_req) & (align - 1)) + return 0; /* Invalid range */ + + return 1; +} + +#ifdef CONFIG_FLASH_MAPPED /** * Get the physical memory address of a flash offset * @@ -52,6 +63,17 @@ static const char *flash_physical_dataptr(int offset) return (char *)((uintptr_t)CONFIG_FLASH_BASE + offset); } +int flash_dataptr(int offset, int size_req, int align, const char **ptrp) +{ + if (!flash_range_ok(offset, size_req, align)) + return -1; /* Invalid range */ + if (ptrp) + *ptrp = flash_physical_dataptr(offset); + + return CONFIG_FLASH_SIZE - offset; +} +#endif + /** * Read persistent state into pstate. * @@ -59,7 +81,7 @@ static const char *flash_physical_dataptr(int offset) */ static void flash_read_pstate(struct persist_state *pstate) { - memcpy(pstate, flash_physical_dataptr(PSTATE_OFFSET), sizeof(*pstate)); + flash_read(PSTATE_OFFSET, sizeof(*pstate), (char *)pstate); /* Sanity-check data and initialize if necessary */ if (pstate->version != PERSIST_STATE_VERSION) { @@ -103,22 +125,12 @@ static int flash_write_pstate(const struct persist_state *pstate) (const char *)pstate); } -int flash_dataptr(int offset, int size_req, int align, const char **ptrp) -{ - if (offset < 0 || size_req < 0 || - offset + size_req > CONFIG_FLASH_SIZE || - (offset | size_req) & (align - 1)) - return -1; /* Invalid range */ - if (ptrp) - *ptrp = flash_physical_dataptr(offset); - - return CONFIG_FLASH_SIZE - offset; -} - int flash_is_erased(uint32_t offset, int size) { const uint32_t *ptr; +#ifdef CONFIG_FLASH_MAPPED + /* Use pointer directly to flash */ if (flash_dataptr(offset, size, sizeof(uint32_t), (const char **)&ptr) < 0) return 0; @@ -126,13 +138,49 @@ int flash_is_erased(uint32_t offset, int size) for (size /= sizeof(uint32_t); size > 0; size--, ptr++) if (*ptr != CONFIG_FLASH_ERASED_VALUE32) return 0; +#else + /* Read flash a chunk at a time */ + uint32_t buf[8]; + int bsize; + + while (size) { + bsize = MIN(size, sizeof(buf)); + + if (flash_read(offset, bsize, (char *)buf)) + return 0; + + size -= bsize; + offset += bsize; + + ptr = buf; + for (bsize /= sizeof(uint32_t); bsize > 0; bsize--, ptr++) + if (*ptr != CONFIG_FLASH_ERASED_VALUE32) + return 0; + + } +#endif return 1; } +int flash_read(int offset, int size, char *data) +{ +#ifdef CONFIG_FLASH_MAPPED + const char *src; + + if (flash_dataptr(offset, size, 1, &src) < 0) + return EC_ERROR_INVAL; + + memcpy(data, src, size); + return EC_SUCCESS; +#else + return flash_physical_read(offset, size, data); +#endif +} + int flash_write(int offset, int size, const char *data) { - if (flash_dataptr(offset, size, CONFIG_FLASH_WRITE_SIZE, NULL) < 0) + if (!flash_range_ok(offset, size, CONFIG_FLASH_WRITE_SIZE)) return EC_ERROR_INVAL; /* Invalid range */ #ifdef CONFIG_VBOOT_HASH @@ -144,7 +192,7 @@ int flash_write(int offset, int size, const char *data) int flash_erase(int offset, int size) { - if (flash_dataptr(offset, size, CONFIG_FLASH_ERASE_SIZE, NULL) < 0) + if (!flash_range_ok(offset, size, CONFIG_FLASH_ERASE_SIZE)) return EC_ERROR_INVAL; /* Invalid range */ #ifdef CONFIG_VBOOT_HASH @@ -456,6 +504,55 @@ DECLARE_CONSOLE_COMMAND(flashwrite, command_flash_write, "offset [size]", "Write pattern to flash", NULL); + +static int command_flash_read(int argc, char **argv) +{ + int offset = -1; + int size = 256; + int rv; + char *data; + int i; + + rv = parse_offset_size(argc, argv, 1, &offset, &size); + if (rv) + return rv; + + if (size > shared_mem_size()) + size = shared_mem_size(); + + /* Acquire the shared memory buffer */ + rv = shared_mem_acquire(size, &data); + if (rv) { + ccputs("Can't get shared mem\n"); + return rv; + } + + /* Read the data */ + if (flash_read(offset, size, data)) { + shared_mem_release(data); + return EC_ERROR_INVAL; + } + + /* Dump it */ + for (i = 0; i < size; i++) { + if ((offset + i) % 16) { + ccprintf(" %02x", data[i]); + } else { + ccprintf("\n%08x: %02x", offset + i, data[i]); + cflush(); + } + } + ccprintf("\n"); + + /* Free the buffer */ + shared_mem_release(data); + + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(flashread, command_flash_read, + "offset [size]", + "Read flash", + NULL); #endif static int command_flash_wp(int argc, char **argv) @@ -534,15 +631,13 @@ DECLARE_HOST_COMMAND(EC_CMD_FLASH_INFO, static int flash_command_read(struct host_cmd_handler_args *args) { const struct ec_params_flash_read *p = args->params; - const char *src; - - if (flash_dataptr(p->offset, p->size, 1, &src) < 0) - return EC_RES_ERROR; if (p->size > args->response_max) return EC_RES_OVERFLOW; - memcpy(args->response, src, p->size); + if (flash_read(p->offset, p->size, args->response)) + return EC_RES_ERROR; + args->response_size = p->size; return EC_RES_SUCCESS; diff --git a/common/system.c b/common/system.c index cdb940c77b..39ccc29165 100644 --- a/common/system.c +++ b/common/system.c @@ -499,6 +499,10 @@ int system_run_image_copy(enum system_image_copy_t copy) const char *system_get_version(enum system_image_copy_t copy) { +#ifndef CONFIG_FLASH_MAPPED + static struct version_struct vdata; +#endif + uintptr_t addr; const struct version_struct *v; @@ -510,17 +514,35 @@ const char *system_get_version(enum system_image_copy_t copy) if (addr == 0xffffffff) return ""; - /* The version string is always located after the reset vectors, so - * it's the same as in the current image. */ -#ifdef CONFIG_CODERAM_ARCH /* TODO: (ML) we run FW in Code RAM */ + /* + * The version string is always located after the reset vectors, so + * it's the same offset as in the current image. Find that offset. + */ +#ifdef CONFIG_CODERAM_ARCH + /* + * Code has been copied from flash to code RAM, so offset of the + * current image's version struct is from the start of code RAM, not + * the start of the flash image. + */ addr += ((uintptr_t)&version_data - CONFIG_CDRAM_BASE); #else + /* Offset is from the start of the flash image */ addr += ((uintptr_t)&version_data - get_base(system_get_image_copy())); #endif +#ifdef CONFIG_FLASH_MAPPED + /* Directly access the version data */ + v = (const struct version_struct *)addr; +#else + /* Read the version struct into a buffer */ + if (flash_read(addr - CONFIG_FLASH_BASE, sizeof(vdata), (char *)&vdata)) + return ""; + + v = &vdata; +#endif + /* Make sure the version struct cookies match before returning the * version string. */ - v = (const struct version_struct *)addr; if (v->cookie1 == RO(version_data).cookie1 && v->cookie2 == RO(version_data).cookie2) return v->version; diff --git a/common/vboot_hash.c b/common/vboot_hash.c index e7717e96db..f2fa839c67 100644 --- a/common/vboot_hash.c +++ b/common/vboot_hash.c @@ -7,9 +7,11 @@ #include "common.h" #include "console.h" +#include "flash.h" #include "hooks.h" #include "host_command.h" #include "sha256.h" +#include "shared_mem.h" #include "system.h" #include "task.h" #include "timer.h" @@ -56,6 +58,37 @@ static void vboot_hash_abort(void) } } +#ifndef CONFIG_FLASH_MAPPED + +static void vboot_hash_next_chunk(void); + +static int read_and_hash_chunk(int offset, int size) +{ + char *buf; + int rv; + + rv = shared_mem_acquire(size, &buf); + if (rv == EC_ERROR_BUSY) { + /* Couldn't update hash right now; try again later */ + hook_call_deferred(vboot_hash_next_chunk, WORK_INTERVAL_US); + return rv; + } else if (rv != EC_SUCCESS) { + vboot_hash_abort(); + return rv; + } + + rv = flash_read(offset, size, buf); + if (rv == EC_SUCCESS) + SHA256_update(&ctx, (const uint8_t *)buf, size); + else + vboot_hash_abort(); + + shared_mem_release(buf); + return rv; +} + +#endif + /** * Do next chunk of hashing work, if any. */ @@ -72,8 +105,14 @@ static void vboot_hash_next_chunk(void) /* Compute the next chunk of hash */ size = MIN(CHUNK_SIZE, data_size - curr_pos); + +#ifdef CONFIG_FLASH_MAPPED SHA256_update(&ctx, (const uint8_t *)(CONFIG_FLASH_BASE + data_offset + curr_pos), size); +#else + if (read_and_hash_chunk(data_offset + curr_pos, size) != EC_SUCCESS) + return; +#endif curr_pos += size; if (curr_pos >= data_size) { |