diff options
author | Vadim Bendebury <vbendeb@chromium.org> | 2019-02-28 20:11:28 -0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2019-04-05 09:21:44 -0700 |
commit | 171578b67f40355528cbb5f34b78e8e8ed83e335 (patch) | |
tree | 2303b74da9487ca2d046b93ad04212feff6164ac | |
parent | 1d6c7bb9773f76aa70ce65822fa001ff72892cd2 (diff) | |
download | chrome-ec-171578b67f40355528cbb5f34b78e8e8ed83e335.tar.gz |
cr50: complete support of the new NVMEM structure
This patch eliminates unnecessary legacy nvmem.c and nvmem_vars.c code
and brings the code base to the state where the new NVMEM layout is
fully functional.
BRANCH=cr50, cr50-mp
BUG=b:69907320, b:129710256
CQ-DEPEND=CL:1450278
TEST=the following tests pass:
- test cases in ./test/nvmem.c
- TCG suite (passes on par with the existing Cr50 code with the
reduced code footprint TPM2 library)
- Chrome OS device migrates from legacy to new implementation with
user account maintained.
- Chrome OS user account is maintained over AP and H1 reboots and
deep sleep cycles.
Change-Id: If4bc2dd125873a79dbe0e268eb32100a8b8b352d
Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1496607
Reviewed-by: Andrey Pronin <apronin@chromium.org>
-rw-r--r-- | board/cr50/board.c | 2 | ||||
-rw-r--r-- | board/cr50/board.h | 16 | ||||
-rw-r--r-- | board/cr50/u2f.c | 15 | ||||
-rw-r--r-- | common/build.mk | 1 | ||||
-rw-r--r-- | common/ccd_config.c | 4 | ||||
-rw-r--r-- | common/new_nvmem.c | 13 | ||||
-rw-r--r-- | common/nvmem.c | 185 | ||||
-rw-r--r-- | common/nvmem_vars.c | 411 | ||||
-rw-r--r-- | common/pinweaver.c | 56 | ||||
-rw-r--r-- | common/shmalloc.c | 2 | ||||
-rw-r--r-- | common/tpm_registers.c | 22 | ||||
-rw-r--r-- | include/common.h | 5 | ||||
-rw-r--r-- | include/nvmem.h | 18 | ||||
-rw-r--r-- | include/nvmem_vars.h | 35 | ||||
-rw-r--r-- | test/nvmem.c | 2 | ||||
-rw-r--r-- | test/pinweaver.c | 10 |
16 files changed, 194 insertions, 603 deletions
diff --git a/board/cr50/board.c b/board/cr50/board.c index 09a43901a4..e7482a9577 100644 --- a/board/cr50/board.c +++ b/board/cr50/board.c @@ -717,8 +717,6 @@ static void board_init(void) init_runlevel(PERMISSION_MEDIUM); /* Initialize NvMem partitions */ nvmem_init(); - /* Initialize the persistent storage. */ - initvars(); /* * If this was a low power wake and not a rollback, restore the ccd diff --git a/board/cr50/board.h b/board/cr50/board.h index 2e75645138..f6f2f5c9de 100644 --- a/board/cr50/board.h +++ b/board/cr50/board.h @@ -62,12 +62,20 @@ #define CONFIG_FLASH_NVMEM_OFFSET_A (CFG_TOP_A_OFF + CONFIG_FLASH_NVCTR_SIZE) #define CONFIG_FLASH_NVMEM_OFFSET_B (CFG_TOP_B_OFF + CONFIG_FLASH_NVCTR_SIZE) /* Address of start of Nvmem area */ -#define CONFIG_FLASH_NVMEM_BASE_A (CONFIG_PROGRAM_MEMORY_BASE + \ - CONFIG_FLASH_NVMEM_OFFSET_A) -#define CONFIG_FLASH_NVMEM_BASE_B (CONFIG_PROGRAM_MEMORY_BASE + \ - CONFIG_FLASH_NVMEM_OFFSET_B) +#define CONFIG_FLASH_NVMEM_BASE_A \ + (CONFIG_PROGRAM_MEMORY_BASE + CONFIG_FLASH_NVMEM_OFFSET_A) +#define CONFIG_FLASH_NVMEM_BASE_B \ + (CONFIG_PROGRAM_MEMORY_BASE + CONFIG_FLASH_NVMEM_OFFSET_B) +#define CONFIG_FLASH_NEW_NVMEM_BASE_A \ + (CONFIG_FLASH_NVMEM_BASE_A + CONFIG_FLASH_BANK_SIZE) +#define CONFIG_FLASH_NEW_NVMEM_BASE_B \ + (CONFIG_FLASH_NVMEM_BASE_B + CONFIG_FLASH_BANK_SIZE) + /* Size partition in NvMem */ #define NVMEM_PARTITION_SIZE (CFG_TOP_SIZE - CONFIG_FLASH_NVCTR_SIZE) +#define NEW_NVMEM_PARTITION_SIZE (NVMEM_PARTITION_SIZE - CONFIG_FLASH_BANK_SIZE) +#define NEW_NVMEM_TOTAL_PAGES \ + (2 * NEW_NVMEM_PARTITION_SIZE / CONFIG_FLASH_BANK_SIZE) /* Size in bytes of NvMem area */ #define CONFIG_FLASH_LOG #define CONFIG_FLASH_NVMEM_SIZE (NVMEM_PARTITION_SIZE * NVMEM_NUM_PARTITIONS) diff --git a/board/cr50/u2f.c b/board/cr50/u2f.c index a858edfa58..320f026a6e 100644 --- a/board/cr50/u2f.c +++ b/board/cr50/u2f.c @@ -82,25 +82,22 @@ static int load_state(void) /* create random salt */ if (!DCRYPTO_ladder_random(salt)) return 0; - if (setvar(&k_salt, sizeof(k_salt), - (const uint8_t *)salt, sizeof(salt))) + if (setvar(&k_salt, sizeof(k_salt), (const uint8_t *)salt, + sizeof(salt))) return 0; - /* really save the new variable to flash */ - writevars(); } else { memcpy(salt, tuple_val(t_salt), sizeof(salt)); + freevar(t_salt); } - if (read_tpm_nvmem_hidden( - TPM_HIDDEN_U2F_KEK, - sizeof(salt_kek), salt_kek) == - tpm_read_not_found) { + if (read_tpm_nvmem_hidden(TPM_HIDDEN_U2F_KEK, sizeof(salt_kek), + salt_kek) == tpm_read_not_found) { /* * Not found means that we have not used u2f before, * or not used it with updated fw that resets kek seed * on TPM clear. */ - if (t_salt) { + if (t_salt) { /* Note that memory has been freed already!. */ /* * We have previously used u2f, and may have * existing registrations; we don't want to diff --git a/common/build.mk b/common/build.mk index 7d5cd9dad0..5ba841734e 100644 --- a/common/build.mk +++ b/common/build.mk @@ -66,6 +66,7 @@ common-$(CONFIG_FLASH)+=flash.o common-$(CONFIG_FLASH_LOG)+=flash_log.o flash_log_vc.o common-$(CONFIG_FLASH_NVCOUNTER)+=nvcounter.o common-$(CONFIG_FLASH_NVMEM)+=nvmem.o +common-$(CONFIG_FLASH_NVMEM)+=new_nvmem.o common-$(CONFIG_FLASH_NVMEM_VARS)+=nvmem_vars.o common-$(CONFIG_FMAP)+=fmap.o common-$(CONFIG_GESTURE_SW_DETECTION)+=gesture.o diff --git a/common/ccd_config.c b/common/ccd_config.c index c2a92aeb30..62f97892f4 100644 --- a/common/ccd_config.c +++ b/common/ccd_config.c @@ -389,6 +389,8 @@ static void ccd_load_config(void) ccd_reset_config(t->val_len < 2 ? CCD_RESET_TEST_LAB : 0); } + freevar(t); + ccd_is_loaded: ccd_config_loaded = 1; @@ -410,8 +412,6 @@ static int ccd_save_config(void) if (rv) return rv; - rv = writevars(); - /* * Notify CCD users of configuration change. * Protect this notify with the ccd_config_loaded flag so recipients of diff --git a/common/new_nvmem.c b/common/new_nvmem.c index 50433feb4c..9ec6e3c885 100644 --- a/common/new_nvmem.c +++ b/common/new_nvmem.c @@ -1379,7 +1379,7 @@ static enum ec_error_list migrate_vars(struct nn_container *ch) var = NULL; total_var_space = 0; - while ((var = getnextvar(var)) != NULL) + while ((var = legacy_getnextvar(var)) != NULL) save_var(var->data_, var->key_len, var->data_ + var->key_len, var->val_len, (struct max_var_container *)ch); @@ -2607,9 +2607,9 @@ static struct max_var_container *find_var(const uint8_t *key, size_t key_len, return NULL; } -struct tuple *getvar(const uint8_t *key, uint8_t key_len) +const struct tuple *getvar(const uint8_t *key, uint8_t key_len) { - struct max_var_container *vc; + const struct max_var_container *vc; struct access_tracker at = {}; if (!key || !key_len) @@ -2623,14 +2623,15 @@ struct tuple *getvar(const uint8_t *key, uint8_t key_len) return NULL; } -int freevar(struct tuple *var) +void freevar(const struct tuple *var) { void *vc; + if (!var) + return; + vc = (uint8_t *)var - offsetof(struct max_var_container, t_header); shared_mem_release(vc); - - return EC_SUCCESS; /* Could verify var first before releasing. */ } static enum ec_error_list save_container(struct nn_container *nc) diff --git a/common/nvmem.c b/common/nvmem.c index de6fba47b5..577318af2f 100644 --- a/common/nvmem.c +++ b/common/nvmem.c @@ -8,14 +8,13 @@ #include "dcrypto.h" #include "flash.h" #include "nvmem.h" +#include "new_nvmem.h" #include "task.h" #include "timer.h" #include "util.h" -#define CPRINTF(format, args...) cprintf(CC_COMMAND, format, ## args) -#define CPRINTS(format, args...) cprints(CC_COMMAND, format, ## args) - -#define NVMEM_NOT_INITIALIZED (-1) +#define CPRINTF(format, args...) cprintf(CC_COMMAND, format, ##args) +#define CPRINTS(format, args...) cprints(CC_COMMAND, format, ##args) /* * The NVMEM contents are stored in flash memory. At run time there is an SRAM @@ -103,74 +102,13 @@ static void nvmem_compute_sha(struct nvmem_tag *tag, void *sha_buf) static int nvmem_save(void) { - struct nvmem_partition *part; - size_t nvmem_offset; - int dest_partition; - uint8_t sha_comp[NVMEM_SHA_SIZE]; - int rv = EC_SUCCESS; - - if (!DCRYPTO_ladder_is_enabled()) { - CPRINTF("%s: Key ladder is disabled. Skipping flash write\n", - __func__); - goto release_cache; - } - - part = (struct nvmem_partition *)nvmem_cache; - - /* Has anything changed in the cache? */ - nvmem_compute_sha(&part->tag, sha_comp); - - if (!memcmp(part->tag.sha, sha_comp, sizeof(part->tag.sha))) { - CPRINTF("%s: Nothing changed, skipping flash write\n", - __func__); - goto release_cache; - } + enum ec_error_list rv; - /* Get flash offset of the partition to save to. */ - dest_partition = (nvmem_act_partition + 1) % NVMEM_NUM_PARTITIONS; - nvmem_offset = nvmem_base_addr[dest_partition] - - CONFIG_PROGRAM_MEMORY_BASE; + rv = new_nvmem_save(); - /* Erase partition */ - rv = flash_physical_erase(nvmem_offset, NVMEM_PARTITION_SIZE); - if (rv != EC_SUCCESS) { - CPRINTF("%s flash erase failed\n", __func__); - goto release_cache; - } - - part->tag.layout_version = NVMEM_LAYOUT_VERSION; - part->tag.generation++; - - /* Calculate sha of the whole thing. */ - nvmem_compute_sha(&part->tag, part->tag.sha); - - /* Encrypt actual payload. */ - if (!app_cipher(part->tag.sha, part->buffer, part->buffer, - sizeof(part->buffer))) { - CPRINTF("%s encryption failed\n", __func__); - rv = EC_ERROR_UNKNOWN; - goto release_cache; - } - - rv = flash_physical_write(nvmem_offset, - NVMEM_PARTITION_SIZE, - nvmem_cache); - if (rv != EC_SUCCESS) { - CPRINTF("%s flash write failed\n", __func__); - goto release_cache; - } + if (rv == EC_SUCCESS) + nvmem_act_partition = NVMEM_NOT_INITIALIZED; - /* Restore payload. */ - if (!app_cipher(part->tag.sha, part->buffer, part->buffer, - sizeof(part->buffer))) { - CPRINTF("%s decryption failed\n", __func__); - rv = EC_ERROR_UNKNOWN; - goto release_cache; - } - - nvmem_act_partition = dest_partition; - - release_cache: nvmem_mutex.write_in_progress = 0; nvmem_release_cache(); return rv; @@ -245,21 +183,6 @@ static void nvmem_release_cache(void) mutex_unlock(&nvmem_mutex.mtx); } -static int nvmem_reinitialize(void) -{ - nvmem_lock_cache(); /* Unlocked by nvmem_save() below. */ - /* - * NvMem is not properly initialized. Let's just erase everything and - * start over, so that at least 1 partition is ready to be used. - */ - nvmem_act_partition = 0; - - memset(nvmem_cache, 0xff, NVMEM_PARTITION_SIZE); - - /* Start with generation zero in the current active partition. */ - return nvmem_save(); -} - static int nvmem_compare_generation(void) { struct nvmem_partition *p_part; @@ -301,10 +224,10 @@ static int nvmem_find_partition(void) if (nvmem_partition_read_verify(check_part) == EC_SUCCESS) { nvmem_act_partition = check_part; + ccprintf("%s:%d found legacy partition %d\n", __func__, + __LINE__, check_part); return EC_SUCCESS; } - ccprintf("%s:%d partiton %d verification FAILED\n", - __func__, __LINE__, check_part); } /* @@ -312,14 +235,8 @@ static int nvmem_find_partition(void) * is valid. Let's reinitialize the NVMEM - there is nothing else we * can do. */ - CPRINTS("%s: No Valid Partition found, will reinitialize!", __func__); - - if (nvmem_reinitialize() != EC_SUCCESS) { - CPRINTS("%s: Reinitialization failed!!"); - return EC_ERROR_UNKNOWN; - } - - return EC_SUCCESS; + CPRINTS("%s: No Legacy Partitions found.", __func__); + return EC_ERROR_INVALID_CONFIG; } static int nvmem_generate_offset_table(void) @@ -342,8 +259,17 @@ static int nvmem_generate_offset_table(void) return EC_SUCCESS; } -static int nvmem_get_partition_off(int user, uint32_t offset, - uint32_t len, uint32_t *p_buf_offset) + +void *nvmem_cache_base(enum nvmem_users user) +{ + if ((user < 0) || (user >= NVMEM_NUM_USERS)) + return NULL; + + return nvmem_cache + nvmem_user_start_offset[user]; +} + +static int nvmem_get_partition_off(int user, uint32_t offset, uint32_t len, + uint32_t *p_buf_offset) { uint32_t start_offset; @@ -365,48 +291,6 @@ static int nvmem_get_partition_off(int user, uint32_t offset, return EC_SUCCESS; } -int nvmem_erase_user_data(enum nvmem_users user) -{ - int part; - int ret; - uint32_t user_offset, user_size; - - if (user >= NVMEM_NUM_USERS) - return EC_ERROR_INVAL; - - CPRINTS("Erasing NVMEM Flash Partition user: %d", user); - - ret = EC_SUCCESS; - - /* Find offset within cache. */ - user_offset = nvmem_user_start_offset[user]; - user_size = nvmem_user_sizes[user]; - - for (part = 0; part < NVMEM_NUM_PARTITIONS; part++) { - int rv; - - /* Lock the cache buffer. */ - nvmem_lock_cache(); - /* Erase the user's data. */ - memset(nvmem_cache + user_offset, 0xFF, user_size); - - /* - * Make sure the contents change between runs of - * nvmem_save() so that all flash partitions are - * written with empty contents and different - * generation numbers. - */ - ((struct nvmem_partition *)nvmem_cache)->tag.generation = part; - - /* Make a best effort to clear each partition. */ - rv = nvmem_save(); - if (rv != EC_SUCCESS) - ret = rv; - } - - return ret; -} - int nvmem_init(void) { int ret; @@ -417,8 +301,6 @@ int nvmem_init(void) CPRINTF("%s:%d\n", __func__, __LINE__); return ret; } - /* Initialize error state, assume everything is good */ - nvmem_error_state = EC_SUCCESS; nvmem_write_error = 0; /* @@ -426,24 +308,27 @@ int nvmem_init(void) * succeeds to bootstrap the nvmem area. */ commits_enabled = 1; - ret = nvmem_find_partition(); + + /* + * Try discovering legacy partition(s). If even one is present, need + * to migrate to the new nvmem storage scheme. + */ + if (nvmem_find_partition() == EC_SUCCESS) + ret = new_nvmem_migrate(nvmem_act_partition); + else + ret = new_nvmem_init(); + + nvmem_error_state = ret; if (ret != EC_SUCCESS) { - /* Change error state to non-zero */ - nvmem_error_state = ret; - CPRINTF("%s:%d\n", __func__, __LINE__); + CPRINTF("%s:%d error %d!\n", __func__, __LINE__, ret); return ret; } - CPRINTS("Active Nvmem partition set to %d", nvmem_act_partition); - return EC_SUCCESS; } -int nvmem_get_error_state(void) -{ - return nvmem_error_state; -} +int nvmem_get_error_state(void) { return nvmem_error_state; } int nvmem_is_different(uint32_t offset, uint32_t size, void *data, enum nvmem_users user) diff --git a/common/nvmem_vars.c b/common/nvmem_vars.c index d90fe37f9e..2b60dbed0c 100644 --- a/common/nvmem_vars.c +++ b/common/nvmem_vars.c @@ -7,7 +7,7 @@ #include "common.h" #include "console.h" #include "nvmem.h" -#include "nvmem_vars.h" +#include "new_nvmem.h" #include "printf.h" #include "shared_mem.h" #include "util.h" @@ -17,33 +17,14 @@ test_mockable_static uint8_t *rbuf; -test_mockable_static -void release_local_copy(void) +int set_local_copy(void) { if (rbuf) - shared_mem_release(rbuf); - rbuf = NULL; -} - -test_mockable_static -int get_local_copy(void) -{ - int rv; - - if (rbuf) - return EC_SUCCESS; - - rv = SHARED_MEM_ACQUIRE_CHECK(CONFIG_FLASH_NVMEM_VARS_USER_SIZE, - (char **)&rbuf); + return EC_ERROR_UNKNOWN; - if (rv == EC_SUCCESS) { - rv = nvmem_read(0, CONFIG_FLASH_NVMEM_VARS_USER_SIZE, - rbuf, CONFIG_FLASH_NVMEM_VARS_USER_NUM); - if (rv != EC_SUCCESS) - release_local_copy(); - } + rbuf = nvmem_cache_base(NVMEM_CR50); - return rv; + return EC_SUCCESS; } /****************************************************************************/ @@ -88,261 +69,42 @@ int get_local_copy(void) */ /****************************************************************************/ -/* Helper functions */ - -/* Return true if the tuple at rbuf+idx matches the key */ -static int match_key_at(uint32_t idx, const uint8_t *key, uint8_t key_len) -{ - struct tuple *tuple = (struct tuple *)(rbuf + idx); - uint32_t i, max_len; - uint8_t diffs; - - /* Don't try to look past the 0 at the end of the user region */ - max_len = MIN(key_len, CONFIG_FLASH_NVMEM_VARS_USER_SIZE - idx - 1); - - /* Do constant-time comparision, since AP sets key_len to look for */ - diffs = max_len ^ key_len; - diffs |= tuple->key_len ^ key_len; - for (i = 0; i < max_len; i++) - diffs |= tuple->data_[i] ^ key[i]; - - return !diffs; -} - -/* - * Find the start of the next tuple in rbuf. Return false if there isn't one. - * The idx arg tracks where to start looking and where the next tuple was - * expected to be found. - */ -static int next_tuple(uint32_t *idx) -{ - struct tuple *tuple = (struct tuple *)(rbuf + *idx); - - /* Not at a valid tuple now, so there aren't any more */ - if (!tuple->key_len) - return 0; - - /* Advance to the next one */ - *idx += sizeof(struct tuple) + tuple->key_len + tuple->val_len; - tuple = (struct tuple *)(rbuf + *idx); - - /* Do we have one or not? */ - return tuple->key_len; -} - -/* - * Look for the key in rbuf. If a match is found, set the index to the start of - * the tuple and return true. If the key is not found, set the index to the - * location where a new tuple should be added (0 if no tuples exist at all, - * else at the '\0' at the end of the tuples) and return false. - */ -test_mockable_static -int getvar_idx(uint32_t *idx, const uint8_t *key, uint8_t key_len) -{ - uint32_t i = *idx; - - do { - if (match_key_at(i, key, key_len)) { - *idx = i; - return 1; - } - } while (next_tuple(&i)); - - *idx = i; - return 0; -} - -static inline int bogus_blob(const uint8_t *blob, uint8_t blob_len) -{ - return !blob || !blob_len; -} - -/****************************************************************************/ /* API functions */ -/* This MUST be called first. The internal functions assume valid entries */ -int initvars(void) +const struct tuple *legacy_getnextvar(const struct tuple *prev_var) { - struct tuple *tuple; - int rv, i, len; - - rv = get_local_copy(); - if (rv != EC_SUCCESS) - return rv; - - for (i = len = 0; /* FOREVER */ 1; i += len) { - /* Zero byte (i.e. key_len == 0) indicates end of tuples. */ - if (rbuf[i] == 0) - break; - - tuple = (struct tuple *)(rbuf + i); - len = sizeof(struct tuple); - - /* Make sure the tuple struct is within bounds. */ - if (i + len > CONFIG_FLASH_NVMEM_VARS_USER_SIZE) - goto fixit; - - /* Empty values are not allowed */ - if (!tuple->val_len) - goto fixit; - - /* See how big the tuple is */ - len += tuple->key_len + tuple->val_len; + const struct tuple *var; + uintptr_t idx; - /* Oops, it's off the end (leave one byte for final 0) */ - if (i + len >= CONFIG_FLASH_NVMEM_VARS_USER_SIZE) - goto fixit; + if (!prev_var) { + /* + * The caller is just starting, let's get the first var, if + * any. + */ + if (!rbuf[0]) + return NULL; + return (const struct tuple *)rbuf; } - /* Found the end of variables. Now make sure the rest is all 0xff. */ - for (i++ ; i < CONFIG_FLASH_NVMEM_VARS_USER_SIZE; i++) - if (rbuf[i] != 0xff) - goto fixit; + /* Let's try to get the next one. */ + idx = (uintptr_t)prev_var; + idx += prev_var->key_len + prev_var->val_len + sizeof(struct tuple); - release_local_copy(); - return EC_SUCCESS; + var = (const struct tuple *)idx; -fixit: - /* No variables */ - rbuf[0] = 0; - /* Everything else is 0xff */ - memset(rbuf + 1, 0xff, CONFIG_FLASH_NVMEM_VARS_USER_SIZE - 1); + if (var->key_len) + return var; - return writevars(); + return NULL; } -const struct tuple *getvar(const uint8_t *key, uint8_t key_len) -{ - uint32_t i = 0; - - if (bogus_blob(key, key_len)) - return 0; - - if (get_local_copy() != EC_SUCCESS) - return 0; - - if (!getvar_idx(&i, key, key_len)) - return 0; - - return (const struct tuple *)(rbuf + i); -} - -const uint8_t *tuple_key(const struct tuple *t) -{ - return t->data_; -} +const uint8_t *tuple_key(const struct tuple *t) { return t->data_; } const uint8_t *tuple_val(const struct tuple *t) { return t->data_ + t->key_len; } -int setvar(const uint8_t *key, uint8_t key_len, - const uint8_t *val, uint8_t val_len) -{ - struct tuple *tuple; - int rv, i, j; - - if (bogus_blob(key, key_len)) - return EC_ERROR_INVAL; - - rv = get_local_copy(); - if (rv != EC_SUCCESS) - return rv; - - i = 0; - if (getvar_idx(&i, key, key_len)) { - /* Found the match at position i */ - j = i; - if (next_tuple(&j)) { - /* - * Now j is the start of the tuple after ours. Delete - * our entry by shifting left from there to the end of - * rbuf, so that it covers ours up. - * - * Before: - * i j - * <foo,bar><KEY,VAL><hey,splat>0 - * - * After: - * i - * <foo,bar><hey,splat>0... - */ - memmove(rbuf + i, rbuf + j, - CONFIG_FLASH_NVMEM_VARS_USER_SIZE - j); - /* Advance i to point to the end of all tuples */ - while (next_tuple(&i)) - ; - } - /* Whether we found a match or not, it's not there now */ - } - /* - * Now i is where the new tuple should be written. - * - * Either this: - * i - * <foo,bar><hey,splat>0 - * - * or there are no tuples at all and i == 0 - * - */ - - /* If there's no value to save, we're done. */ - if (bogus_blob(val, val_len)) - goto done; - - /* - * We'll always write the updated entry at the end of any existing - * tuples, and we mark the end with an additional 0. Make sure all that - * will all fit. If it doesn't, we've already removed the previous - * entry but we still need to mark the end. - */ - if (i + sizeof(struct tuple) + key_len + val_len + 1 > - CONFIG_FLASH_NVMEM_VARS_USER_SIZE) { - rv = EC_ERROR_OVERFLOW; - goto done; - } - - /* write the tuple */ - tuple = (struct tuple *)(rbuf + i); - tuple->key_len = key_len; - tuple->val_len = val_len; - tuple->flags = 0; /* UNUSED, set to zero */ - memcpy(tuple->data_, key, key_len); - memcpy(tuple->data_ + key_len, val, val_len); - /* move past it */ - next_tuple(&i); - -done: - /* mark the end */ - rbuf[i++] = 0; - /* erase the rest */ - memset(rbuf + i, 0xff, CONFIG_FLASH_NVMEM_VARS_USER_SIZE - i); - - return rv; -} - -int writevars(void) -{ - int rv; - - if (!rbuf) - return EC_SUCCESS; - - rv = nvmem_write(0, CONFIG_FLASH_NVMEM_VARS_USER_SIZE, - rbuf, CONFIG_FLASH_NVMEM_VARS_USER_NUM); - if (rv != EC_SUCCESS) - return rv; - - rv = nvmem_commit(); - if (rv != EC_SUCCESS) - return rv; - - release_local_copy(); - - return rv; -} - /****************************************************************************/ #if defined(TEST_BUILD) && !defined(TEST_FUZZ) #include "console.h" @@ -382,133 +144,28 @@ static int command_set(int argc, char **argv) return EC_ERROR_PARAM_COUNT; if (argc == 2) - rc = setvar(argv[1], strlen(argv[1]), 0, 0); + rc = setvar(argv[1], strlen(argv[1]), 0, 0); else - rc = setvar(argv[1], strlen(argv[1]), - argv[2], strlen(argv[2])); - if (rc) - return rc; + rc = setvar(argv[1], strlen(argv[1]), argv[2], strlen(argv[2])); - return writevars(); + return rc; } -DECLARE_CONSOLE_COMMAND(set, command_set, - "VARIABLE [VALUE]", +DECLARE_CONSOLE_COMMAND(set, command_set, "VARIABLE [VALUE]", "Set/clear the value of the specified variable"); static int command_print(int argc, char **argv) { - const struct tuple *tuple; - int rv, i = 0; - - rv = get_local_copy(); - if (rv) - return rv; - - tuple = (const struct tuple *)(rbuf + i); - if (!tuple->key_len) - return EC_SUCCESS; - - do { - tuple = (const struct tuple *)(rbuf + i); - print_blob(tuple_key(tuple), tuple->key_len); - ccprintf("="); - print_blob(tuple_val(tuple), tuple->val_len); - ccprintf("\n"); - } while (next_tuple(&i)); - - return EC_SUCCESS; + ccprintf("Print all vars is not yet implemented\n"); + return EC_ERROR_INVAL; } -DECLARE_CONSOLE_COMMAND(print, command_print, - "", +DECLARE_CONSOLE_COMMAND(print, command_print, "", "Print all defined variables"); -static int command_dump(int argc, char **argv) -{ - int i, rv; - - rv = get_local_copy(); - if (rv) - return rv; - - for (i = 0; i < CONFIG_FLASH_NVMEM_VARS_USER_SIZE; i++) - ccprintf(" %02x", rbuf[i]); - ccprintf("\n"); - release_local_copy(); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(dump, command_dump, - "", - "Dump the variable memory"); - static int command_clear_nvmem_vars(int argc, char **argv) { - int rv; - - rv = nvmem_erase_user_data(CONFIG_FLASH_NVMEM_VARS_USER_NUM); - if (rv) - ccprintf("Error clearing nvmem vars! (rv: %d)\n", rv); - else - ccprintf("NvMem vars cleared successfully.\n"); - - /* - * Invalidate the cache buffer since we just erased the backing - * store. - */ - writevars(); - - /* - * Re-initialize the NvMem vars space so that it's ready for - * immediate use. - */ - initvars(); - - /* - * TODO(aaboagye): For "V1", this is where you might want to call and - * reset the defaults. - */ - - return rv; + ccprintf("Nvmem clear vars has not yet been implemented\n"); + return EC_ERROR_INVAL; } -DECLARE_CONSOLE_COMMAND(clr_nvmem_vars, command_clear_nvmem_vars, - "", +DECLARE_CONSOLE_COMMAND(clr_nvmem_vars, command_clear_nvmem_vars, "", "Clear the NvMem variables."); - -static int command_nv_test_var(int argc, char **argv) -{ - const struct tuple *t; - uint8_t key; - uint8_t val; - int rv; - - key = NVMEM_VAR_TEST_VAR; - - if (argc > 1) { - val = (uint8_t)atoi(argv[1]); - rv = setvar(&key, 1, &val, 1); - if (rv) - ccprintf("setvar err %d", rv); - - rv = writevars(); - if (rv) - ccprintf("writevar err %d", rv); - } - - t = getvar(&key, 1); - if (t) { - val = *tuple_val(t); - } else { - ccprintf("No value set.\n"); - return EC_SUCCESS; - } - - /* Invalidate RAM buffer. */ - writevars(); - ccprintf("test_var: %d\n", val); - - return EC_SUCCESS; -} -DECLARE_SAFE_CONSOLE_COMMAND(nvtestvar, command_nv_test_var, - "[0-255]", - "Get/Set an NvMem test variable."); #endif diff --git a/common/pinweaver.c b/common/pinweaver.c index 1777a4c28b..d65e1bad0c 100644 --- a/common/pinweaver.c +++ b/common/pinweaver.c @@ -656,6 +656,7 @@ static int load_log_data(struct pw_log_storage_t *log) { const struct tuple *ptr; const struct pw_log_storage_t *view; + int rv = EC_SUCCESS; ptr = getvar(PW_LOG_VAR0, sizeof(PW_LOG_VAR0) - 1); if (ptr == NULL) @@ -663,24 +664,21 @@ static int load_log_data(struct pw_log_storage_t *log) view = (void *)tuple_val(ptr); if (ptr->val_len != sizeof(struct pw_log_storage_t)) - return PW_ERR_NV_LENGTH_MISMATCH; - if (view->storage_version != PW_STORAGE_VERSION) - return PW_ERR_NV_VERSION_MISMATCH; + rv = PW_ERR_NV_LENGTH_MISMATCH; + else if (view->storage_version != PW_STORAGE_VERSION) + rv = PW_ERR_NV_VERSION_MISMATCH; + else + memcpy(log, view, ptr->val_len); - memcpy(log, view, ptr->val_len); - return EC_SUCCESS; + freevar(ptr); + + return rv; } int store_log_data(const struct pw_log_storage_t *log) { - int ret; - - ret = setvar(PW_LOG_VAR0, sizeof(PW_LOG_VAR0) - 1, (uint8_t *)log, - sizeof(struct pw_log_storage_t)); - if (ret != EC_SUCCESS) - return ret; - - return writevars(); + return setvar(PW_LOG_VAR0, sizeof(PW_LOG_VAR0) - 1, (uint8_t *)log, + sizeof(struct pw_log_storage_t)); } static int load_merkle_tree(struct merkle_tree_t *merkle_tree) @@ -695,15 +693,19 @@ static int load_merkle_tree(struct merkle_tree_t *merkle_tree) const struct pw_long_term_storage_t *tree; ptr = getvar(PW_TREE_VAR, sizeof(PW_TREE_VAR) - 1); - if (ptr == NULL) + if (!ptr) return PW_ERR_NV_EMPTY; tree = (void *)tuple_val(ptr); /* Add storage format updates here. */ - if (ptr->val_len != sizeof(*tree)) + if (ptr->val_len != sizeof(*tree)) { + freevar(ptr); return PW_ERR_NV_LENGTH_MISMATCH; - if (tree->storage_version != PW_STORAGE_VERSION) + } + if (tree->storage_version != PW_STORAGE_VERSION) { + freevar(ptr); return PW_ERR_NV_VERSION_MISMATCH; + } merkle_tree->bits_per_level = tree->bits_per_level; merkle_tree->height = tree->height; @@ -711,8 +713,10 @@ static int load_merkle_tree(struct merkle_tree_t *merkle_tree) tree->key_derivation_nonce, sizeof(tree->key_derivation_nonce)); ret = derive_keys(merkle_tree); - if (ret != EC_SUCCESS) + if (ret != EC_SUCCESS) { + freevar(ptr); return ret; + } } /* Handle the root hash. */ @@ -720,15 +724,19 @@ static int load_merkle_tree(struct merkle_tree_t *merkle_tree) struct pw_log_storage_t *log; ptr = getvar(PW_LOG_VAR0, sizeof(PW_LOG_VAR0) - 1); - if (ptr == NULL) + if (!ptr) return PW_ERR_NV_EMPTY; log = (void *)tuple_val(ptr); /* Add storage format updates here. */ - if (ptr->val_len != sizeof(struct pw_log_storage_t)) + if (ptr->val_len != sizeof(struct pw_log_storage_t)) { + freevar(ptr); return PW_ERR_NV_LENGTH_MISMATCH; - if (log->storage_version != PW_STORAGE_VERSION) + } + if (log->storage_version != PW_STORAGE_VERSION) { + freevar(ptr); return PW_ERR_NV_VERSION_MISMATCH; + } memcpy(merkle_tree->root, log->entries[0].root, sizeof(merkle_tree->root)); @@ -747,15 +755,15 @@ static int load_merkle_tree(struct merkle_tree_t *merkle_tree) ret = setvar(PW_LOG_VAR0, sizeof(PW_LOG_VAR0) - 1, (uint8_t *)log, sizeof(struct pw_log_storage_t)); - if (ret != EC_SUCCESS) - return ret; - ret = writevars(); - if (ret != EC_SUCCESS) + if (ret != EC_SUCCESS) { + freevar(ptr); return ret; + } } pw_restart_count = log->restart_count; } + freevar(ptr); cprints(CC_TASK, "PinWeaver: Loaded Tree. restart_count = %d", pw_restart_count); diff --git a/common/shmalloc.c b/common/shmalloc.c index c1cebaaf7c..8c66a63eb8 100644 --- a/common/shmalloc.c +++ b/common/shmalloc.c @@ -310,6 +310,8 @@ int shared_mem_acquire(int size, char **dest_ptr) int rv; struct shm_buffer *new_buf; + *dest_ptr = NULL; + if (in_interrupt_context()) return EC_ERROR_INVAL; diff --git a/common/tpm_registers.c b/common/tpm_registers.c index 142261ecf3..947a3b089a 100644 --- a/common/tpm_registers.c +++ b/common/tpm_registers.c @@ -13,7 +13,7 @@ #include "console.h" #include "extension.h" #include "link_defs.h" -#include "nvmem.h" +#include "new_nvmem.h" #include "printf.h" #include "signed_header.h" #include "sps.h" @@ -828,20 +828,11 @@ static void tpm_reset_now(int wipe_first) if (wipe_first) /* Now wipe the TPM's nvmem */ - wipe_result = nvmem_erase_user_data(NVMEM_TPM); + wipe_result = nvmem_erase_tpm_data(); else wipe_result = EC_SUCCESS; /* - * Clear the TPM library's zero-init data. Note that the linker script - * includes this file's .bss in the same section, so it will be cleared - * at the same time. - */ - memset(&__bss_libtpm2_start, 0, - (uintptr_t)(&__bss_libtpm2_end) - - (uintptr_t)(&__bss_libtpm2_start)); - - /* * NOTE: If any __initialized variables need reinitializing after * reset, this is the place to do it. */ @@ -853,6 +844,15 @@ static void tpm_reset_now(int wipe_first) nvmem_enable_commits(); /* + * Clear the TPM library's zero-init data. Note that the linker script + * includes this file's .bss in the same section, so it will be cleared + * at the same time. + */ + memset(&__bss_libtpm2_start, 0, + (uintptr_t)(&__bss_libtpm2_end) - + (uintptr_t)(&__bss_libtpm2_start)); + + /* * Prevent NVRAM commits until further notice, unless running in * factory mode. */ diff --git a/include/common.h b/include/common.h index 4f1b1f76a4..56ba15a8a4 100644 --- a/include/common.h +++ b/include/common.h @@ -180,6 +180,9 @@ enum ec_error_list { /* something wrong in a HW */ EC_ERROR_HW_INTERNAL = 25, + /* Sometimes operation is expected to have to be repeated. */ + EC_ERROR_TRY_AGAIN = 26, + /* Verified boot errors */ EC_ERROR_VBOOT_SIGNATURE = 0x1000, /* 4096 */ EC_ERROR_VBOOT_SIG_MAGIC = 0x1001, @@ -200,7 +203,7 @@ enum ec_error_list { /* Module-internal error codes may use this range. */ EC_ERROR_INTERNAL_FIRST = 0x10000, - EC_ERROR_INTERNAL_LAST = 0x1FFFF + EC_ERROR_INTERNAL_LAST = 0x1FFFF }; /* diff --git a/include/nvmem.h b/include/nvmem.h index 341a7c083d..f48c9cd9c4 100644 --- a/include/nvmem.h +++ b/include/nvmem.h @@ -178,15 +178,6 @@ int nvmem_move(uint32_t src_offset, uint32_t dest_offset, uint32_t size, int nvmem_commit(void); /* - * Clear out a user's data across all partitions. - * - * @param user: The user who's data should be cleared. - * @return EC_SUCCESS if the user's data across all partitions was - * cleared. Error othrwise. - */ -int nvmem_erase_user_data(enum nvmem_users user); - -/* * Temporarily stopping NVMEM commits could be beneficial. One use case is * when TPM operations need to be sped up. * @@ -206,6 +197,15 @@ void nvmem_disable_commits(void); int nvmem_enable_commits(void); /* + * Function to retrieve the base address of the nvmem cache of the appropriate + * user. After migration there is only one user and one base address, this + * function will be eliminated. + * + * @return pointer to the base address. + */ +void *nvmem_cache_base(enum nvmem_users user); + +/* * Clear all NVMEM cache in SRAM. */ void nvmem_clear_cache(void); diff --git a/include/nvmem_vars.h b/include/nvmem_vars.h index add14345e7..eec1e757a2 100644 --- a/include/nvmem_vars.h +++ b/include/nvmem_vars.h @@ -65,12 +65,32 @@ struct tuple { int initvars(void); /* - * Look up a key, return a pointer to the tuple. If the key is not found, - * return NULL. WARNING: The returned pointer is only valid until the next call - * to setvar() or writevars(). Use it or lose it. + * Look up the key passed in the input tuple and fill the value, if found. + * + * The val_len field in the passed in tuple indicates how much room is + * available, the actual value size could be smaller. + * + * Return: + * + * EC_SUCCESS - if the key was found and there was enough room in the passed + * in tuple for the value. + * EC_ERROR_INVAL - if the key was not found. + * + * EC_ERROR_MEMORY_ALLOCATION - if the value would not fit into the supplied + * tuple. */ const struct tuple *getvar(const uint8_t *key, uint8_t key_len); +/* + * Free memory held by the previously read tuple. + * + * Note that tuple address is not the address to be returned to the heap, so + * the user must use this function to free this memory. If var is NULL this + * function is a no-op. + * + */ +void freevar(const struct tuple *var); + /* Use these to access the data components of a valid struct tuple pointer */ const uint8_t *tuple_key(const struct tuple *); const uint8_t *tuple_val(const struct tuple *); @@ -88,6 +108,15 @@ int setvar(const uint8_t *key, uint8_t key_len, */ int writevars(void); +/* + * A fully contained function which does not use any available nvmem_vars + * methods, as it is used solely for retrieving vars from legacy storage + * format. Runs only during migration. + */ +const struct tuple *legacy_getnextvar(const struct tuple *prev_var); + +int set_local_copy(void); + #ifdef __cplusplus } #endif diff --git a/test/nvmem.c b/test/nvmem.c index 2b814251c9..dc5cde1eee 100644 --- a/test/nvmem.c +++ b/test/nvmem.c @@ -523,7 +523,7 @@ static int var_read_write_delete_helper(int do_write) const void *value; for (j = 0; j < ARRAY_SIZE(kv_pairs); j++) { - struct tuple *t; + const struct tuple *t; coverage_map |= 1; diff --git a/test/pinweaver.c b/test/pinweaver.c index 079fbe2b88..093443e49e 100644 --- a/test/pinweaver.c +++ b/test/pinweaver.c @@ -793,7 +793,7 @@ uint8_t get_current_pcr_digest(const uint8_t bitmask[2], /******************************************************************************/ /* Mock implementations of nvmem_vars functionality. */ -struct tuple *getvar(const uint8_t *key, uint8_t key_len) +const struct tuple *getvar(const uint8_t *key, uint8_t key_len) { struct tuple *var = NULL; size_t i; @@ -831,11 +831,13 @@ struct tuple *getvar(const uint8_t *key, uint8_t key_len) return var; } -int freevar(struct tuple *var) +void freevar(const struct tuple *var) { - free(var); + if (!var) + return; - return EC_SUCCESS; + /* This typecast is OK because we know that 'var' came from malloc. */ + free((void *)var); } const uint8_t *tuple_val(const struct tuple *tpl) { |