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