summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/flash.c135
-rw-r--r--common/system.c30
-rw-r--r--common/vboot_hash.c39
-rw-r--r--include/config.h7
-rw-r--r--include/flash.h22
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.