summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVadim Bendebury <vbendeb@chromium.org>2017-01-15 15:23:46 -0800
committerchrome-bot <chrome-bot@chromium.org>2017-01-18 16:06:58 -0800
commit755a1d02fed240a3b0b760bb047b6f1017e39240 (patch)
treef62832ed8fda1a0f628bd2edd222b4519450c1f2
parentf1f1203431b10e36a249b4a618e2e82ae2fa800c (diff)
downloadchrome-ec-755a1d02fed240a3b0b760bb047b6f1017e39240.tar.gz
common: prepare nvmem for encryption support
This patch mostly is rearranging the code to make it easier to add encryption layer in the upcoming change. One substantial change is making sure that in case when NVMEM contents are corrupted for whatever reason, the initialization function re-creates a blank NVMEM space; it was just bailing out before not leaving any initialized partitions behind. There is no need in two separate tables - one for base absolute addresses of the NVMEM partitions, and one for their flash memory offsets, one can be easily derived from the other. Code erasing the destination partition, calculating the SHA1 of the new blob and writing it into the flash was separated into own function. BRANCH=none BUG=chrome-os-partner:55331 TEST=make buildall -j still passes (which means NVMEM tests succeed). TPM TCG test suite also passes. Change-Id: I378265d8b49b81398aece2eadf9698abb05caaa1 Signed-off-by: Vadim Bendebury <vbendeb@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/428172 Reviewed-by: Scott Collyer <scollyer@chromium.org>
-rw-r--r--common/nvmem.c164
1 files changed, 76 insertions, 88 deletions
diff --git a/common/nvmem.c b/common/nvmem.c
index a93852191c..6a11b64fa7 100644
--- a/common/nvmem.c
+++ b/common/nvmem.c
@@ -24,11 +24,6 @@ static const uintptr_t nvmem_base_addr[NVMEM_NUM_PARTITIONS] = {
CONFIG_FLASH_NVMEM_BASE_A,
CONFIG_FLASH_NVMEM_BASE_B
};
-/* Table of offset within flash space to start of each partition */
-static const uint32_t nvmem_flash_offset[NVMEM_NUM_PARTITIONS] = {
- CONFIG_FLASH_NVMEM_OFFSET_A,
- CONFIG_FLASH_NVMEM_OFFSET_B
- };
/* NvMem user buffer start offset table */
static uint32_t nvmem_user_start_offset[NVMEM_NUM_USERS];
@@ -53,30 +48,60 @@ static int nvmem_error_state;
/* Flag to track if an Nv write/move is not completed */
static int nvmem_write_error;
-static int nvmem_verify_partition_sha(int index)
+static int nvmem_save(uint8_t tag_version, size_t partition)
+{
+ struct nvmem_tag *tag;
+ size_t nvmem_offset;
+
+ /* Flash offset of the partition to save. */
+ nvmem_offset = nvmem_base_addr[partition] - CONFIG_PROGRAM_MEMORY_BASE;
+
+ /* Erase partition */
+ if (flash_physical_erase(nvmem_offset,
+ NVMEM_PARTITION_SIZE)) {
+ CPRINTF("%s:%d\n", __func__, __LINE__);
+ return EC_ERROR_UNKNOWN;
+ }
+
+ tag = (struct nvmem_tag *)cache.base_ptr;
+ tag->version = tag_version;
+
+ /* Calculate sha of the whole thing. */
+ nvmem_compute_sha(&tag->version,
+ NVMEM_PARTITION_SIZE -
+ offsetof(struct nvmem_tag, version),
+ tag->sha,
+ sizeof(tag->sha));
+
+ /* Write partition */
+ if (flash_physical_write(nvmem_offset,
+ NVMEM_PARTITION_SIZE,
+ cache.base_ptr)) {
+ CPRINTF("%s:%d\n", __func__, __LINE__);
+ return EC_ERROR_UNKNOWN;
+ }
+
+ return EC_SUCCESS;
+}
+
+static int nvmem_partition_sha_match(int index)
{
uint8_t sha_comp[NVMEM_SHA_SIZE];
struct nvmem_partition *p_part;
- uint8_t *p_data;
p_part = (struct nvmem_partition *)nvmem_base_addr[index];
- p_data = (uint8_t *)p_part;
- p_data += sizeof(sha_comp);
-
- /* Number of bytes to compute sha over */
- nvmem_compute_sha(p_data,
+ nvmem_compute_sha(&p_part->tag.version,
(NVMEM_PARTITION_SIZE - NVMEM_SHA_SIZE),
- sha_comp,
- NVMEM_SHA_SIZE);
+ sha_comp, sizeof(sha_comp));
+
/* Check if computed value matches stored value. */
- return memcmp(p_part->tag.sha, sha_comp, NVMEM_SHA_SIZE);
+ return !memcmp(p_part->tag.sha, sha_comp, NVMEM_SHA_SIZE);
}
+/* Called with the semaphore locked. */
static int nvmem_acquire_cache(void)
{
int attempts = 0;
- uint8_t *shared_mem_ptr;
- uint8_t *p_src;
int ret;
if (shared_mem_size() < NVMEM_PARTITION_SIZE) {
@@ -87,13 +112,13 @@ static int nvmem_acquire_cache(void)
while (attempts < NVMEM_ACQUIRE_CACHE_MAX_ATTEMPTS) {
ret = shared_mem_acquire(NVMEM_PARTITION_SIZE,
- (char **)&shared_mem_ptr);
+ (char **)&cache.base_ptr);
if (ret == EC_SUCCESS) {
/* Copy partiion contents from flash into cache */
- p_src = (uint8_t *)nvmem_base_addr[nvmem_act_partition];
- memcpy(shared_mem_ptr, p_src, NVMEM_PARTITION_SIZE);
- /* Now that cache is up to date, assign pointer */
- cache.base_ptr = shared_mem_ptr;
+ memcpy(cache.base_ptr,
+ (void *)nvmem_base_addr[nvmem_act_partition],
+ NVMEM_PARTITION_SIZE);
+
return EC_SUCCESS;
} else if (ret == EC_ERROR_BUSY) {
CPRINTF("Shared Mem not avail! Attempt %d\n", attempts);
@@ -105,6 +130,7 @@ static int nvmem_acquire_cache(void)
}
/* Timeout Error condition */
CPRINTF("%s:%d\n", __func__, __LINE__);
+ cache.base_ptr = NULL; /* Just in case. */
return EC_ERROR_TIMEOUT;
}
@@ -154,48 +180,25 @@ static void nvmem_release_cache(void)
mutex_unlock(&cache.mtx);
}
-static int nvmem_is_unitialized(void)
+static int nvmem_reinitialize(void)
{
- int p;
- int n;
int ret;
- uint32_t *p_nvmem;
- struct nvmem_partition *p_part;
-
- for (p = 0; p < NVMEM_NUM_PARTITIONS; p++) {
- /* Point to start of Nv Memory */
- p_nvmem = (uint32_t *)nvmem_base_addr[p];
- /* Verify that each byte is 0xff (4 bytes at a time) */
- for (n = 0; n < (NVMEM_PARTITION_SIZE >> 2); n++)
- if (p_nvmem[n] != 0xffffffff)
- return EC_ERROR_CRC;
- }
/*
- * NvMem is fully unitialized. Need to initialize tag and write tag to
- * flash so at least 1 partition is ready to be used.
+ * NvMem is not properly itialized. Let's just erase everything and
+ * start over, so that at least 1 partition is ready to be used.
*/
nvmem_act_partition = 0;
+
/* Need to acquire the shared memory buffer */
ret = nvmem_lock_cache();
if (ret != EC_SUCCESS)
return ret;
- p_part = (struct nvmem_partition *)cache.base_ptr;
- /* Start with version 0 */
- p_part->tag.version = 0;
- /* Compute sha with updated tag */
- nvmem_compute_sha(&cache.base_ptr[NVMEM_SHA_SIZE],
- NVMEM_PARTITION_SIZE - NVMEM_SHA_SIZE,
- p_part->tag.sha,
- NVMEM_SHA_SIZE);
- /*
- * Partition 0 is initialized, write tag only to flash. Since the
- * partition was just verified to be fully erased, can just do write
- * operation.
- */
- ret = flash_physical_write(nvmem_flash_offset[0],
- sizeof(struct nvmem_tag),
- cache.base_ptr);
+
+ memset(cache.base_ptr, 0xff, NVMEM_PARTITION_SIZE);
+
+ /* Start with version zero in the current active partition. */
+ ret = nvmem_save(0, nvmem_act_partition);
nvmem_release_cache();
if (ret) {
CPRINTF("%s:%d\n", __func__, __LINE__);
@@ -237,23 +240,28 @@ static int nvmem_find_partition(void)
* the most recent one.
*/
for (n = 0; n < NVMEM_NUM_PARTITIONS; n++)
- if (nvmem_verify_partition_sha(n) == EC_SUCCESS) {
+ if (nvmem_partition_sha_match(n)) {
if (nvmem_act_partition == NVMEM_NOT_INITIALIZED)
nvmem_act_partition = n;
else
nvmem_act_partition = nvmem_compare_version();
+ } else {
+ ccprintf("%s:%d partiton %d verification FAILED\n",
+ __func__, __LINE__, n);
}
- /*
- * If active_partition is still not selected, then neither partition is
- * valid. In this case need to determine if they are simply erased or
- * both are corrupt. If erased, then can initialze the tag for the first
- * one. If not fully erased, then this is an error condition.
- */
+
if (nvmem_act_partition != NVMEM_NOT_INITIALIZED)
return EC_SUCCESS;
- if (nvmem_is_unitialized()) {
- CPRINTS("NvMem: No Valid Paritions!");
+ /*
+ * If active_partition is still not selected, then neither partition
+ * is valid. Let's reinitialize the NVMEM - there is nothing else we
+ * can do.
+ */
+ CPRINTS("%s: No Valid Parition found, have to reinitialize!");
+
+ if (nvmem_reinitialize() != EC_SUCCESS) {
+ CPRINTS("%s: Reinitialization failed!!");
return EC_ERROR_UNKNOWN;
}
@@ -538,7 +546,6 @@ void nvmem_disable_commits(void)
int nvmem_commit(void)
{
- int nvmem_offset;
int new_active_partition;
uint16_t version;
struct nvmem_partition *p_part;
@@ -573,40 +580,21 @@ int nvmem_commit(void)
/* Check for restricted version number */
if (version == NVMEM_VERSION_MASK)
version = 0;
- p_part->tag.version = version;
- /* Update the sha */
- nvmem_compute_sha(&cache.base_ptr[NVMEM_SHA_SIZE],
- NVMEM_PARTITION_SIZE - NVMEM_SHA_SIZE,
- p_part->tag.sha,
- NVMEM_SHA_SIZE);
/* Toggle parition being used (always write to current spare) */
new_active_partition = nvmem_act_partition ^ 1;
- /* Point to first block within active partition */
- nvmem_offset = nvmem_flash_offset[new_active_partition];
- /* Write partition to NvMem */
- /* Erase partition */
- if (flash_physical_erase(nvmem_offset,
- NVMEM_PARTITION_SIZE)) {
- CPRINTF("%s:%d\n", __func__, __LINE__);
- /* Free up scratch buffers */
- nvmem_release_cache();
- return EC_ERROR_UNKNOWN;
- }
- /* Write partition */
- if (flash_physical_write(nvmem_offset,
- NVMEM_PARTITION_SIZE,
- cache.base_ptr)) {
- CPRINTF("%s:%d\n", __func__, __LINE__);
+ /* Write active partition to NvMem */
+ if (nvmem_save(version, new_active_partition) != EC_SUCCESS) {
/* Free up scratch buffers */
nvmem_release_cache();
return EC_ERROR_UNKNOWN;
}
- /* Free up scratch buffers */
- nvmem_release_cache();
/* Update newest partition index */
nvmem_act_partition = new_active_partition;
+
+ /* Free up scratch buffers */
+ nvmem_release_cache();
return EC_SUCCESS;
}