summaryrefslogtreecommitdiff
path: root/include/nvmem.h
blob: 00dc4b787996488341772e11b717c43e47041a4f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
/* Copyright 2016 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 __CROS_EC_NVMEM_UTILS_H
#define __CROS_EC_NVMEM_UTILS_H

#include "crypto_api.h"

#ifdef __cplusplus
extern "C" {
#endif

/*
 * In order to provide maximum robustness for NvMem operations, the NvMem space
 * is divided into two equal sized partitions. A partition contains a tag
 * and a buffer for each NvMem user.
 *
 *     NvMem Partiion
 *     ------------------------------------------------------------------------
 *     |36 byte tag | User Buffer 0 | User Buffer 1 | .... |  User Buffer N-1 |
 *     ------------------------------------------------------------------------
 *
 *     Physical Block Tag details
 *     ------------------------------------------------------------------------
 *     |      sha       |      padding     |  version  | generation | reserved |
 *     -------------------------------------------------------------------------
 *         sha        -> 16 bytes of sha1 digest
 *         padding    -> 16 bytes for future extensions
 *         version    -> nvmem layout version, currently at 0
 *         generation -> 1 byte generation number (0 - 0xfe)
 *         reserved   -> 2 bytes
 *
 * At initialization time, each partition is scanned to see if it has a good sha
 * entry. One of the two partitions being valid is a supported condition. If
 * neither partiion is valid a new partition is created with generation set to
 * zero.
 *
 * Note that the NvMem partitions can be placed anywhere in flash space, but
 * must be equal in total size. A table is used by the NvMem module to get the
 * correct base address for each partition.
 *
 * A generation number is used to distinguish between two valid partitions with
 * the newsest generation number (in a circular sense) marking the correct
 * partition to use. The parition number 0/1 is tracked via a static
 * variable. When the NvMem contents need to be updated, the flash erase/write
 * of the updated partition will use the inactive partition space in NvMem. This
 * way if there is a critical failure (i.e. loss of power) during the erase or
 * write operation, then the contents of the active partition prior the most
 * recent writes will still be preserved.
 *
 * The following CONFIG_FLASH_NVMEM_ defines are required for this module:
 *    CONFIG_FLASH_NVMEM -> enable/disable the module
 *    CONFIG_FLASH_NVMEM_OFFSET_(A|B) -> offset to start of each partition
 *    CONFIG_FLASH_NVMEM_BASE_(A|B) -> address of start of each partition
 *
 * The board.h file must define a macro or enum named NVMEM_NUM_USERS.
 * The board.c file must implement:
 *    nvmem_user_sizes[] -> array of user buffer lengths
 * The chip must provide
 *    app_compute_hash() -> function used to compute 16 byte sha (or equivalent)
 *
 * Note that total length of user buffers must satisfy the following:
 *   sum(user sizes) <= (NVMEM_PARTITION_SIZE) - sizeof(struct nvmem_tag)
 */

/* NvMem user buffer length table */
extern uint32_t nvmem_user_sizes[NVMEM_NUM_USERS];

#define NVMEM_NUM_PARTITIONS 2
#define NVMEM_SHA_SIZE CIPHER_SALT_SIZE
#define NVMEM_GENERATION_BITS 8
#define NVMEM_GENERATION_MASK (BIT(NVMEM_GENERATION_BITS) - 1)
#define NVMEM_PADDING_SIZE 16
#define NVMEM_LAYOUT_VERSION 0

/* Struct for NV block tag */
struct nvmem_tag {
	uint8_t sha[NVMEM_SHA_SIZE];
	uint8_t padding[NVMEM_PADDING_SIZE];
	uint8_t layout_version;
	uint8_t generation;
	uint8_t reserved[2];
};

/* Structure MvMem Partition */
struct nvmem_partition {
	struct nvmem_tag tag;
	uint8_t buffer[NVMEM_PARTITION_SIZE -
		       sizeof(struct nvmem_tag)];
};

/**
 * Initialize NVMem translation table and state variables
 *
 * @return EC_SUCCESS if a valid translation table is constructed, else
 *         error code.
 */
int nvmem_init(void);

/**
 * Get Nvmem internal error state
 *
 * @return nvmem_error_state variable.
 */
int nvmem_get_error_state(void);

/**
 * Compare 'size' amount of bytes in NvMem
 *
 * @param offset: Offset (in bytes) into NVmem logical space
 * @param size: Number of bytes to compare
 * @param data: Pointer to data to be compared with
 * @param user: Data section within NvMem space
 * @return 0 if the data is same, non-zero if data is different
 */
int nvmem_is_different(uint32_t offset, uint32_t size,
		       void *data, enum nvmem_users user);

/**
 * Read 'size' amount of bytes from NvMem
 *
 * @param startOffset: Offset (in bytes) into NVmem logical space
 * @param size: Number of bytes to read
 * @param data: Pointer to destination buffer
 * @param user: Data section within NvMem space
 * @return EC_ERROR_OVERFLOW (non-zero) if the read operation would exceed the
 *         buffer length of the given user, otherwise EC_SUCCESS.
 */
int nvmem_read(uint32_t startOffset, uint32_t size,
		void *data, enum nvmem_users user);

/**
 * Write 'size' amount of bytes to NvMem
 *
 * Calling this function will wait for the mutex, then lock it until
 * nvmem_commit() is invoked.
 *
 * @param startOffset: Offset (in bytes) into NVmem logical space
 * @param size: Number of bytes to write
 * @param data: Pointer to source buffer
 * @param user: Data section within NvMem space
 * @return EC_ERROR_OVERFLOW if write exceeds buffer length
 *         EC_ERROR_TIMEOUT if nvmem cache buffer is not available
 *         EC_SUCCESS if no errors.
 */
int nvmem_write(uint32_t startOffset, uint32_t size,
		 void *data, enum nvmem_users user);

/**
 * Move 'size' amount of bytes within NvMem
 *
 * Calling this function will wait for the mutex, then lock it until
 * nvmem_commit() is invoked.
 *
 * @param src_offset: source offset within NvMem logical space
 * @param dest_offset: destination offset within NvMem logical space
 * @param size: Number of bytes to move
 * @param user: Data section within NvMem space
 * @return EC_ERROR_OVERFLOW if write exceeds buffer length
 *         EC_ERROR_TIMEOUT if nvmem cache buffer is not available
 *         EC_SUCCESS if no errors.
 */
int nvmem_move(uint32_t src_offset, uint32_t dest_offset, uint32_t size,
	       enum nvmem_users user);
/**
 * Commit all previous NvMem writes to flash
 *
 * @return EC_SUCCESS if flash erase/operations are successful.

 *         EC_ERROR_OVERFLOW in case the mutex is not locked when this
 *                           function is called
 *         EC_ERROR_INVAL    if task trying to commit is not the one
 *                           holding the mutex
 *         EC_ERROR_UNKNOWN  in other error cases
 */
int nvmem_commit(void);

/*
 * Temporarily stopping NVMEM commits could be beneficial. One use case is
 * when TPM operations need to be sped up.
 *
 * Calling this function will wait for the mutex, then lock it until
 * nvmem_commit() is invoked.
 *
 * Both below functions should be called from the same task.
 */
void nvmem_disable_commits(void);

/*
 * Only the task holding the mutex is allowed to enable commits.
 *
 * @return error if this task does not hold the lock or commit
 *         fails, EC_SUCCESS otherwise.
 */
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);

void nvmem_wipe_cache(void);

/*
 * Unlock nvmem mutex lock.
 *
 * @param init_act_partition: boolean to request to initialize active nvmem
 *                            partition status or not.
 */
void nvmem_unlock_cache(int init_act_partition);

#ifdef __cplusplus
}
#endif

#endif /* __CROS_EC_NVMEM_UTILS_H */