summaryrefslogtreecommitdiff
path: root/include/new_nvmem.h
diff options
context:
space:
mode:
authorVadim Bendebury <vbendeb@chromium.org>2019-02-01 10:19:51 -0800
committerchrome-bot <chrome-bot@chromium.org>2019-04-04 05:40:01 -0700
commit574e131187492b0e5ba1af06d9a6baee22a2302e (patch)
tree3d8bac1e9d431bac227dc03cec0909b0c9513390 /include/new_nvmem.h
parentfd2a6277b4b2262efda3d22e46ec9a48bc7339b2 (diff)
downloadchrome-ec-574e131187492b0e5ba1af06d9a6baee22a2302e.tar.gz
cr50: New NVMEM flash storage implementation
This patch is a proposed implementation of the new TPM NVMEM flash layer. There is a big comment block in common/new_nvmem.c describing the approach taken, changes to the API and outstanding issues. This implementation follows the design document attached to b:69907320. With all required changes to the rest of the code this new flash storage scheme consumes 7816(!) bytes of code storage. One of the more important aspects of this implementation is that the (key, value) pair objects are stored in the flash only, they are not duplicated in the SRAM cache. The advantage of this is that there could be more space dedicated to these objects. Soft limit is set to 1K as opposed to 272 bytes available with the legacy scheme. The major disadvantage is the need for the user not to forget to release the (key, value) pair retrieved from NVMEM, as it occupies space on the heap. BRANCH=cr50, cr50-mp BUG=b:69907320, b:129710256 TEST=with the rest of the patches applied the following tests pass: - test cases in ./test (completely reworked for the new scheme) - 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: I6252649597c03abd4a08e2d55d61e384fe037ef7 Signed-off-by: Vadim Bendebury <vbendeb@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1450277 Reviewed-by: Andrey Pronin <apronin@chromium.org>
Diffstat (limited to 'include/new_nvmem.h')
-rw-r--r--include/new_nvmem.h155
1 files changed, 155 insertions, 0 deletions
diff --git a/include/new_nvmem.h b/include/new_nvmem.h
new file mode 100644
index 0000000000..110cfd1667
--- /dev/null
+++ b/include/new_nvmem.h
@@ -0,0 +1,155 @@
+/* Copyright 2019 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef __TPM2_NVMEM_TEST_NEW_NVMEM_H
+#define __TPM2_NVMEM_TEST_NEW_NVMEM_H
+
+#include "common.h"
+#include "nvmem.h"
+#include "nvmem_vars.h"
+#include "util.h"
+
+#define NVMEM_NOT_INITIALIZED ((unsigned int)-1)
+
+/*
+ * A totally arbitrary byte limit for space occupied by (key, value) pairs in
+ * the flash. This is an improvement compared to the legacy case where there
+ * were just 272 bytes dedicated to the (key, value) pairs storage.
+ */
+#define MAX_VAR_TOTAL_SPACE 1000
+
+/*
+ * Let's be reasonable: we're unlikely to have keys longer than 40 or so
+ * bytes, and leave full 255 bytes for the value. Total data space occupied by
+ * a (key, value) pair is not to exceed the value below.
+ */
+#define MAX_VAR_BODY_SPACE 300
+
+enum nn_object_type {
+ NN_OBJ_OLD_COPY = 0,
+ NN_OBJ_TUPLE = 1,
+ NN_OBJ_TPM_RESERVED = 2,
+ NN_OBJ_TPM_EVICTABLE = 3,
+ NN_OBJ_TRANSACTION_DEL = 4,
+ NN_OBJ_ESCAPE = 5,
+ NN_OBJ_ERASED = 7,
+};
+
+/*
+ * Structure placed at the base of each flash page used for NVMEM storage.
+ *
+ * page_number: allows to arrange pages in order they were added
+ *
+ * data_offset: the offset of the first element in the page (space above
+ * page header and below data_offset could be taken by the
+ * 'tail' of the object stored on the previous page).
+ *
+ * page_hash: is used to verify page header integrity
+ */
+struct nn_page_header {
+ unsigned int page_number : 21;
+ unsigned int data_offset : 11;
+ uint32_t page_hash;
+} __packed;
+
+/*
+ * Index of the 'virtual' last reserved object. RAM index space and max
+ * counter objects stored at fixed location in the NVMEM cache are considered
+ * reserved objects by this NVMEM flash layer.
+ */
+#define NV_VIRTUAL_RESERVE_LAST (NV_RESERVE_LAST + 2)
+
+/*
+ * Container header for all blobs stored in flash.
+ *
+ * container_type: type of object stored in the container. MAKE SURE THIS
+ * FIELD TYPE IS THE FIRST FIELD IN THIS STRUCTURE, it is
+ * supposed to be in the first word of the container so that
+ * the type can be erased when object is deleted.
+ *
+ * container_type_copy: immutable copy of the container_type field, used to
+ * verify contents of deleted objects.
+ *
+ * encrypted: set to 1 if contents are encrypted.
+ *
+ * size: size of the payload, 12 bits allocated, 11 bits would be enough for
+ * this use case.
+ *
+ * generation: a free running counter, used to compare ages of two containers
+ *
+ * container_hash: hash of the ENTIRE container, both header and body
+ * included. This field is set to zero before hash is calculated
+ */
+struct nn_container {
+ unsigned int container_type : 3;
+ unsigned int container_type_copy : 3;
+ unsigned int encrypted : 1;
+ unsigned int size : 11;
+ unsigned int generation : 2;
+ unsigned int container_hash : 12;
+} __packed;
+
+/*
+ * A structure to keep context of accessing to a page, page header and offset
+ * define where the next access would happen.
+ */
+struct page_tracker {
+ const struct nn_page_header *ph;
+ uint16_t data_offset;
+};
+
+/*
+ * Helper structure to keep track of accesses to the flash storage.
+ *
+ * mt: main tracker for read or write accesses.
+ *
+ * ct: keeps track of container fetches, as the location of containers has
+ * special significance: it is both part of the seed used when
+ * encrypting/decryping container contents, and also is necessary to
+ * unwind reading of the container header when the end of storage is
+ * reached and a header of all 0xff is read.
+ *
+ * dt: keeps track of delimiters which is important when assessing flash
+ * contents integrity. If during startup the last item in flash is not a
+ * delimiter, this is an indication of a failed transaction, all data
+ * after the previous delimiter needs to be discarded.
+ *
+ * list_index; index of the current page in the list of pages, useful when
+ * sequential reading and need to get to the next page in the
+ * list.
+ */
+
+struct access_tracker {
+ struct page_tracker mt; /* Main tracker. */
+ struct page_tracker ct; /* Container tracker. */
+ struct page_tracker dt; /* Delimiter tracker.*/
+ uint8_t list_index;
+};
+
+enum ec_error_list new_nvmem_init(void);
+enum ec_error_list new_nvmem_migrate(unsigned int nvmem_act_partition);
+enum ec_error_list new_nvmem_save(void);
+
+enum ec_error_list get_next_object(struct access_tracker *at,
+ struct nn_container *ch,
+ int include_deleted);
+
+#if defined(TEST_BUILD) && !defined(TEST_FUZZ)
+#define NVMEM_TEST_BUILD
+enum ec_error_list browse_flash_contents(int);
+enum ec_error_list compact_nvmem(void);
+extern struct access_tracker master_at;
+extern uint16_t total_var_space;
+int is_uninitialized(const void *p, size_t size);
+size_t init_object_offsets(uint16_t *offsets, size_t count);
+struct nn_page_header *list_element_to_ph(size_t el);
+void *evictable_offs_to_addr(uint16_t offset);
+#endif
+
+/*
+ * Clear tpm data from nvmem.
+ */
+int nvmem_erase_tpm_data(void);
+
+#endif /* ! __TPM2_NVMEM_TEST_NEW_NVMEM_H */