1 /*
2 * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
3 * Copyright (c) 2020, Cypress Semiconductor Corporation. All rights reserved.
4 * Copyright (c) 2021-2022, STMicroelectronics.
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7 #include "nv_counters_device.h"
8 #include "tfm_plat_nv_counters.h"
9 #include <limits.h>
10 #include <stddef.h>
11 #include "Driver_Flash.h"
12 #include "nv_counters.h"
13
14 /* Compilation time checks to be sure the defines are well defined */
15 #ifndef DEVICE_NV_COUNTERS_AREA_SIZE
16 #error "DEVICE_NV_COUNTERS_AREA_SIZE must be defined"
17 #endif
18
19 #ifndef DEVICE_NV_COUNTERS_AREA_OFFSET
20 #error "DEVICE_NV_COUNTERS_AREA_OFFSET must be defined"
21 #endif
22
23 #ifndef DEVICE_NV_COUNTERS_SECTOR_SIZE
24 #error "DEVICE_NV_COUNTERS_SECTOR_SIZE must be defined"
25 #endif
26
27 #if DEVICE_NV_COUNTERS_AREA_SIZE!=(2*DEVICE_NV_COUNTERS_SECTOR_SIZE)
28 #error "DEVICE_NV_COUNTERS_AREA_SIZE != 2 x DEVICE_NV_COUNTER_SIZE"
29 #endif
30
31 #ifndef DEVICE_NV_COUNTERS_FLASH_NAME
32 #error "DEVICE_NV_COUNTERS_FLASH_NAME must be defined"
33 #endif
34
35 #ifndef DEVICE_NUM_NV_COUNTERS
36 #error "DEVICE_NUM_NV_COUNTERS"
37 #endif
38 /* End of compilation time checks to be sure the defines are well defined */
39
40 #define SECTOR_OFFSET 0
41 #define NV_COUNTER_SIZE sizeof(uint32_t)
42 #define INIT_VALUE_SIZE sizeof(uint32_t)
43 #define CHECKSUM_SIZE sizeof(uint32_t)
44 #define NUM_NV_COUNTERS (DEVICE_NUM_NV_COUNTERS)
45
46
47 #define BACKUP_ADDRESS (DEVICE_NV_COUNTERS_AREA_OFFSET + DEVICE_NV_COUNTERS_SECTOR_SIZE)
48 #define VALID_ADDRESS (DEVICE_NV_COUNTERS_AREA_OFFSET)
49
50
51 /* Import the CMSIS flash device driver */
52 extern ARM_DRIVER_FLASH DEVICE_NV_COUNTERS_FLASH_NAME;
53
calc_checksum(const uint32_t * data,size_t len)54 static uint32_t calc_checksum(const uint32_t *data, size_t len)
55 {
56 uint32_t sum = 0;
57
58 for (uint32_t i = 0; i < len/sizeof(uint32_t); i++) {
59 sum ^= data[i];
60 }
61 return sum;
62 }
63
is_valid(const struct nv_counters_t * nv_counters)64 static bool is_valid(const struct nv_counters_t *nv_counters)
65 {
66 return ((nv_counters->init_value == NV_COUNTERS_INITIALIZED) &&
67 (!calc_checksum(&nv_counters->checksum, sizeof(*nv_counters))));
68 }
69
set_checksum(struct nv_counters_t * nv_counters)70 static void set_checksum(struct nv_counters_t *nv_counters)
71 {
72 uint32_t sum = calc_checksum(&nv_counters->init_value,
73 sizeof(*nv_counters)
74 - sizeof(nv_counters->checksum));
75
76 nv_counters->checksum = sum;
77 }
78
79 volatile int once=0;
tfm_plat_init_nv_counter(void)80 enum tfm_plat_err_t tfm_plat_init_nv_counter(void)
81 {
82 int32_t ret;
83 struct nv_counters_t nv_counters;
84 ARM_FLASH_CAPABILITIES DriverCapabilities;
85 uint8_t data_width;
86 /* Valid entries for data item width */
87 uint32_t data_width_byte[] = {
88 sizeof(uint8_t),
89 sizeof(uint16_t),
90 sizeof(uint32_t),
91 };
92 #if defined(NVM_COUNTER_INIT)
93 uint32_t i;
94 #endif
95 ret = DEVICE_NV_COUNTERS_FLASH_NAME.Initialize(NULL);
96 if (ret != ARM_DRIVER_OK) {
97 return TFM_PLAT_ERR_SYSTEM_ERR;
98 }
99 DriverCapabilities = DEVICE_NV_COUNTERS_FLASH_NAME.GetCapabilities();
100 /* Since struct nv_counter is aligned on 32 bits , a single read /write is possible */
101 data_width = data_width_byte[DriverCapabilities.data_width];
102
103 /* Read the whole sector so we can write it back to flash later */
104 ret = DEVICE_NV_COUNTERS_FLASH_NAME.ReadData(VALID_ADDRESS,
105 &nv_counters,
106 sizeof(struct nv_counters_t) / data_width);
107 if (ret != (sizeof(struct nv_counters_t) / data_width)) {
108 return TFM_PLAT_ERR_SYSTEM_ERR;
109 }
110
111 if (is_valid(&nv_counters)) {
112 return TFM_PLAT_ERR_SUCCESS;
113 }
114
115 /* Check the backup watermark */
116 ret = DEVICE_NV_COUNTERS_FLASH_NAME.ReadData(BACKUP_ADDRESS,
117 &nv_counters,
118 sizeof(struct nv_counters_t) / data_width);
119 if (ret != (sizeof(struct nv_counters_t) / data_width)) {
120 return TFM_PLAT_ERR_SYSTEM_ERR;
121 }
122
123 /* Erase sector before writing to it */
124 ret = DEVICE_NV_COUNTERS_FLASH_NAME.EraseSector(VALID_ADDRESS);
125 if (ret != ARM_DRIVER_OK) {
126 return TFM_PLAT_ERR_SYSTEM_ERR;
127 }
128
129 if (is_valid(&nv_counters)) {
130 /* Copy from the backup to the main */
131 ret = DEVICE_NV_COUNTERS_FLASH_NAME.ProgramData(VALID_ADDRESS,
132 &nv_counters,
133 sizeof(struct nv_counters_t) / data_width);
134 if (ret != (sizeof(struct nv_counters_t) / data_width)) {
135 return TFM_PLAT_ERR_SYSTEM_ERR;
136 }
137
138 return TFM_PLAT_ERR_SUCCESS;
139 }
140 #if !defined(NVM_COUNTER_INIT)
141 return TFM_PLAT_ERR_SYSTEM_ERR;
142 #else
143 /* Add watermark to indicate that NV counters have been initialized */
144 nv_counters.init_value = NV_COUNTERS_INITIALIZED;
145
146 /* Initialize all counters to 0 */
147 for (i = 0; i < NUM_NV_COUNTERS; i++) {
148 nv_counters.counters[i] = 0;
149 }
150 set_checksum(&nv_counters);
151 /* Write the in-memory block content after modification to flash */
152 ret = DEVICE_NV_COUNTERS_FLASH_NAME.ProgramData(VALID_ADDRESS,
153 &nv_counters,
154 sizeof(struct nv_counters_t) / data_width);
155 if (ret != (sizeof(struct nv_counters_t) / data_width)) {
156 return TFM_PLAT_ERR_SYSTEM_ERR;
157 }
158
159 return TFM_PLAT_ERR_SUCCESS;
160 #endif
161 }
162
tfm_plat_read_nv_counter(enum tfm_nv_counter_t counter_id,uint32_t size,uint8_t * val)163 enum tfm_plat_err_t tfm_plat_read_nv_counter(enum tfm_nv_counter_t counter_id,
164 uint32_t size, uint8_t *val)
165 {
166 int32_t ret;
167 uint32_t flash_addr = VALID_ADDRESS
168 + offsetof(struct nv_counters_t, counters)
169 + (counter_id * NV_COUNTER_SIZE);
170 ARM_FLASH_CAPABILITIES DriverCapabilities;
171 uint8_t data_width;
172 /* Valid entries for data item width */
173 uint32_t data_width_byte[] = {
174 sizeof(uint8_t),
175 sizeof(uint16_t),
176 sizeof(uint32_t),
177 };
178
179 if (size != NV_COUNTER_SIZE) {
180 return TFM_PLAT_ERR_SYSTEM_ERR;
181 }
182 DriverCapabilities = DEVICE_NV_COUNTERS_FLASH_NAME.GetCapabilities();
183 /* Since struct nv_counter is aligned on 32 bits , a single read /write is possible */
184 data_width = data_width_byte[DriverCapabilities.data_width];
185
186 ret = DEVICE_NV_COUNTERS_FLASH_NAME.ReadData(flash_addr, val, NV_COUNTER_SIZE / data_width);
187 if (ret != (NV_COUNTER_SIZE / data_width)) {
188 return TFM_PLAT_ERR_SYSTEM_ERR;
189 }
190
191 return TFM_PLAT_ERR_SUCCESS;
192 }
193
tfm_plat_set_nv_counter(enum tfm_nv_counter_t counter_id,uint32_t value)194 enum tfm_plat_err_t tfm_plat_set_nv_counter(enum tfm_nv_counter_t counter_id,
195 uint32_t value)
196 {
197 int32_t ret;
198 struct nv_counters_t nv_counters;
199 ARM_FLASH_CAPABILITIES DriverCapabilities;
200 uint8_t data_width;
201 /* Valid entries for data item width */
202 uint32_t data_width_byte[] = {
203 sizeof(uint8_t),
204 sizeof(uint16_t),
205 sizeof(uint32_t),
206 };
207
208 DriverCapabilities = DEVICE_NV_COUNTERS_FLASH_NAME.GetCapabilities();
209 /* Since struct nv_counter is aligned on 32 bits , a single read /write is possible */
210 data_width = data_width_byte[DriverCapabilities.data_width];
211
212 /* Read the whole sector so we can write it back to flash later */
213 ret = DEVICE_NV_COUNTERS_FLASH_NAME.ReadData(VALID_ADDRESS,
214 &nv_counters,
215 sizeof(struct nv_counters_t) / data_width);
216 if (ret != (sizeof(struct nv_counters_t) / data_width)) {
217 return TFM_PLAT_ERR_SYSTEM_ERR;
218 }
219
220 if (value != nv_counters.counters[counter_id]) {
221
222 if (value < nv_counters.counters[counter_id]) {
223 return TFM_PLAT_ERR_INVALID_INPUT;
224 }
225
226 /* Erase backup sector */
227 ret = DEVICE_NV_COUNTERS_FLASH_NAME.EraseSector(BACKUP_ADDRESS);
228 if (ret != ARM_DRIVER_OK) {
229 return TFM_PLAT_ERR_SYSTEM_ERR;
230 }
231
232 nv_counters.counters[counter_id] = value;
233
234 set_checksum(&nv_counters);
235
236 /* write sector data to backup sector */
237 ret = DEVICE_NV_COUNTERS_FLASH_NAME.ProgramData(BACKUP_ADDRESS,
238 &nv_counters,
239 sizeof(struct nv_counters_t) / data_width);
240 if (ret != (sizeof(struct nv_counters_t) / data_width)) {
241 return TFM_PLAT_ERR_SYSTEM_ERR;
242 }
243
244 /* Erase sector before writing to it */
245 ret = DEVICE_NV_COUNTERS_FLASH_NAME.EraseSector(VALID_ADDRESS);
246 if (ret != ARM_DRIVER_OK) {
247 return TFM_PLAT_ERR_SYSTEM_ERR;
248 }
249
250 /* Write the in-memory block content after modification to flash */
251 ret = DEVICE_NV_COUNTERS_FLASH_NAME.ProgramData(VALID_ADDRESS,
252 &nv_counters,
253 sizeof(struct nv_counters_t) / data_width);
254 if (ret != (sizeof(struct nv_counters_t) / data_width)) {
255 return TFM_PLAT_ERR_SYSTEM_ERR;
256 }
257 }
258
259 return TFM_PLAT_ERR_SUCCESS;
260 }
261
tfm_plat_increment_nv_counter(enum tfm_nv_counter_t counter_id)262 enum tfm_plat_err_t tfm_plat_increment_nv_counter(
263 enum tfm_nv_counter_t counter_id)
264 {
265 uint32_t security_cnt;
266 enum tfm_plat_err_t err;
267
268 err = tfm_plat_read_nv_counter(counter_id,
269 sizeof(security_cnt),
270 (uint8_t *)&security_cnt);
271 if (err != TFM_PLAT_ERR_SUCCESS) {
272 return err;
273 }
274
275 if (security_cnt == UINT32_MAX) {
276 return TFM_PLAT_ERR_MAX_VALUE;
277 }
278
279 return tfm_plat_set_nv_counter(counter_id, security_cnt + 1u);
280 }
281