diff options
-rw-r--r-- | common/flash.c | 135 | ||||
-rw-r--r-- | common/system.c | 30 | ||||
-rw-r--r-- | common/vboot_hash.c | 39 | ||||
-rw-r--r-- | include/config.h | 7 | ||||
-rw-r--r-- | include/flash.h | 22 |
5 files changed, 209 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) { diff --git a/include/config.h b/include/config.h index e3983eb064..a6d7d6cfb6 100644 --- a/include/config.h +++ b/include/config.h @@ -550,6 +550,13 @@ #undef CONFIG_FLASH_BASE #undef CONFIG_FLASH_ERASED_VALUE32 #undef CONFIG_FLASH_ERASE_SIZE + +/* + * Flash is directly mapped into the EC's address space. If this is not + * defined, the flash driver must implement flash_physical_read(). + */ +#define CONFIG_FLASH_MAPPED + #undef CONFIG_FLASH_PHYSICAL_SIZE #undef CONFIG_FLASH_PROTECT_NEXT_BOOT #undef CONFIG_FLASH_SIZE diff --git a/include/flash.h b/include/flash.h index a77d5a1cb2..3a4a120938 100644 --- a/include/flash.h +++ b/include/flash.h @@ -39,6 +39,15 @@ enum flash_wp_range { /* Low-level methods, for use by flash_common. */ /** + * Read from physical flash. + * + * @param offset Flash offset to write. + * @param size Number of bytes to write. + * @param data Destination buffer for data. Must be 32-bit aligned. + */ +int flash_physical_read(int offset, int size, char *data); + +/** * Write to physical flash. * * Offset and size must be a multiple of CONFIG_FLASH_WRITE_SIZE. @@ -190,6 +199,19 @@ int flash_get_size(void); int flash_dataptr(int offset, int size_req, int align, const char **ptrp); /** + * Read from flash. + * + * If flash is mapped (CONFIG_FLASH_MAPPED), it is usually more efficient to + * use flash_dataptr() to get a pointer directly to the flash memory rather + * than use flash_read(), since the former saves a memcpy() operation. + * + * @param offset Flash offset to write. + * @param size Number of bytes to write. + * @param data Destination buffer for data. Must be 32-bit aligned. + */ +int flash_read(int offset, int size, char *data); + +/** * Write to flash. * * Offset and size must be a multiple of CONFIG_FLASH_WRITE_SIZE. |