1 /*
2  * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 /* NOTE: For the security of the protected storage system, the bootloader
9  * rollback protection, and the protection of cryptographic material  it is
10  * CRITICAL to use a internal (in-die) persistent memory for the implementation
11  * of the OTP_NV_COUNTERS flash area (see flash_otp_nv_layout.c).
12  */
13 
14 #include "tfm_plat_nv_counters.h"
15 
16 #include <limits.h>
17 #include "Driver_Flash.h"
18 #include "flash_layout.h"
19 #include "tfm_plat_otp.h"
20 #include "cmsis_compiler.h"
21 #ifdef TFM_PARTITION_PROTECTED_STORAGE
22 #include "flash_otp_nv_counters_backend.h"
23 #endif
24 
25 #include <string.h>
26 
27 #define OTP_COUNTER_MAX_SIZE    128u
28 #define NV_COUNTER_SIZE         4
29 
30 #ifdef TFM_PARTITION_PROTECTED_STORAGE
31 enum flash_nv_counter_id_t {
32     FLASH_NV_COUNTER_ID_PS_0 = 0,
33     FLASH_NV_COUNTER_ID_PS_1,
34     FLASH_NV_COUNTER_ID_PS_2,
35     FLASH_NV_COUNTER_ID_MAX,
36 };
37 #endif
38 
tfm_plat_init_nv_counter(void)39 enum tfm_plat_err_t tfm_plat_init_nv_counter(void)
40 {
41 #ifdef TFM_PARTITION_PROTECTED_STORAGE
42     if (FLASH_NV_COUNTER_ID_MAX > FLASH_NV_COUNTER_AM) {
43         return TFM_PLAT_ERR_SYSTEM_ERR;
44     }
45 
46     return init_otp_nv_counters_flash();
47 #else
48     return TFM_PLAT_ERR_SUCCESS;
49 #endif
50 }
51 
52 #if defined(BL2) || defined(BL1)
read_nv_counter_otp(enum tfm_otp_element_id_t id,uint32_t size,uint8_t * val)53 static enum tfm_plat_err_t read_nv_counter_otp(enum tfm_otp_element_id_t id,
54                                                uint32_t size, uint8_t *val)
55 {
56     size_t counter_size;
57     enum tfm_plat_err_t err;
58     size_t byte_idx;
59     uint8_t bit_idx;
60     uint8_t counter_value[OTP_COUNTER_MAX_SIZE];
61     uint32_t count;
62 
63     err = tfm_plat_otp_get_size(id, &counter_size);
64     if (err != TFM_PLAT_ERR_SUCCESS) {
65         return err;
66     }
67 
68     counter_size = counter_size > OTP_COUNTER_MAX_SIZE ? OTP_COUNTER_MAX_SIZE : counter_size;
69 
70     err = tfm_plat_otp_read(id, counter_size, counter_value);
71     if (err != TFM_PLAT_ERR_SUCCESS) {
72         return err;
73     }
74 
75     count = 0;
76     for (byte_idx = 0; byte_idx < counter_size; byte_idx++) {
77         for (bit_idx = 0; bit_idx < 8; bit_idx++) {
78             count += (counter_value[byte_idx] >> bit_idx) & 1;
79         }
80     }
81 
82     memcpy(val, &count, NV_COUNTER_SIZE);
83 
84     return TFM_PLAT_ERR_SUCCESS;
85 }
86 #endif /* BL2 || BL1 */
87 
88 #ifdef TFM_PARTITION_PROTECTED_STORAGE
read_nv_counter_flash(enum flash_nv_counter_id_t counter_id,uint32_t size,uint8_t * val)89 static enum tfm_plat_err_t read_nv_counter_flash(enum flash_nv_counter_id_t counter_id,
90                                                  uint32_t size, uint8_t *val)
91 {
92     enum tfm_plat_err_t err = TFM_PLAT_ERR_SUCCESS;
93 
94     if (size != NV_COUNTER_SIZE) {
95         return TFM_PLAT_ERR_INVALID_INPUT;
96     }
97 
98     err = read_otp_nv_counters_flash(offsetof(struct flash_otp_nv_counters_region_t,
99                                               flash_nv_counters)
100                                      + counter_id * sizeof(uint32_t),
101                                      val, size);
102     if (err != TFM_PLAT_ERR_SUCCESS) {
103         return err;
104     }
105 
106     return TFM_PLAT_ERR_SUCCESS;
107 }
108 #endif /* TFM_PARTITION_PROTECTED_STORAGE */
109 
tfm_plat_read_nv_counter(enum tfm_nv_counter_t counter_id,uint32_t size,uint8_t * val)110 enum tfm_plat_err_t tfm_plat_read_nv_counter(enum tfm_nv_counter_t counter_id,
111                                              uint32_t size, uint8_t *val)
112 {
113     if (size != NV_COUNTER_SIZE) {
114         return TFM_PLAT_ERR_SYSTEM_ERR;
115     }
116 
117     switch(counter_id) {
118 #ifdef TFM_PARTITION_PROTECTED_STORAGE
119     case (PLAT_NV_COUNTER_PS_0):
120         return read_nv_counter_flash(FLASH_NV_COUNTER_ID_PS_0, size, val);
121     case (PLAT_NV_COUNTER_PS_1):
122         return read_nv_counter_flash(FLASH_NV_COUNTER_ID_PS_1, size, val);
123     case (PLAT_NV_COUNTER_PS_2):
124         return read_nv_counter_flash(FLASH_NV_COUNTER_ID_PS_2, size, val);
125 #endif /* TFM_PARTITION_PROTECTED_STORAGE */
126 
127 #ifdef BL2
128     case (PLAT_NV_COUNTER_BL2_0):
129         return read_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_BL2_0, size, val);
130     case (PLAT_NV_COUNTER_BL2_1):
131         return read_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_BL2_1, size, val);
132     case (PLAT_NV_COUNTER_BL2_2):
133         return read_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_BL2_2, size, val);
134     case (PLAT_NV_COUNTER_BL2_3):
135         return read_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_BL2_3, size, val);
136 #endif /* BL2 */
137 
138 #ifdef BL1
139     case (PLAT_NV_COUNTER_BL1_0):
140         return read_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_BL1_0, size, val);
141 #endif /* BL1 */
142 
143 #if (PLATFORM_NS_NV_COUNTERS > 0)
144     case (PLAT_NV_COUNTER_NS_0):
145         return read_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_NS_0, size, val);
146 #endif
147 #if (PLATFORM_NS_NV_COUNTERS > 1)
148     case (PLAT_NV_COUNTER_NS_1):
149         return read_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_NS_1, size, val);
150 #endif
151 #if (PLATFORM_NS_NV_COUNTERS > 2)
152     case (PLAT_NV_COUNTER_NS_2):
153         return read_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_NS_2, size, val);
154 #endif
155 
156     default:
157         return TFM_PLAT_ERR_UNSUPPORTED;
158     }
159 }
160 
161 #if defined(BL2) || defined(BL1)
set_nv_counter_otp(enum tfm_otp_element_id_t id,uint32_t value)162 static enum tfm_plat_err_t set_nv_counter_otp(enum tfm_otp_element_id_t id,
163                                               uint32_t value)
164 {
165     size_t counter_size;
166     enum tfm_plat_err_t err;
167     size_t byte_idx;
168     uint8_t counter_value[OTP_COUNTER_MAX_SIZE];
169 
170     err = tfm_plat_otp_get_size(id, &counter_size);
171     if (err != TFM_PLAT_ERR_SUCCESS) {
172         return err;
173     }
174 
175     counter_size = counter_size > OTP_COUNTER_MAX_SIZE ? OTP_COUNTER_MAX_SIZE : counter_size;
176 
177     if (value > (8 * counter_size)) {
178         return TFM_PLAT_ERR_MAX_VALUE;
179     }
180 
181     memset(counter_value, 0, OTP_COUNTER_MAX_SIZE);
182     for (byte_idx = 0; byte_idx < (value / 8); byte_idx++) {
183         counter_value[byte_idx] = UINT8_MAX;
184     }
185     counter_value[byte_idx] = (1 << (value % 8)) - 1;
186 
187     err = tfm_plat_otp_write(id, counter_size, counter_value);
188     if (err != TFM_PLAT_ERR_SUCCESS) {
189         return err;
190     }
191 
192     return TFM_PLAT_ERR_SUCCESS;
193 }
194 #endif /* BL2 || BL1 */
195 
196 #ifdef TFM_PARTITION_PROTECTED_STORAGE
set_nv_counter_flash(enum flash_nv_counter_id_t counter_id,uint32_t value)197 static enum tfm_plat_err_t set_nv_counter_flash(enum flash_nv_counter_id_t counter_id,
198                                                 uint32_t value)
199 {
200     enum tfm_plat_err_t err = TFM_PLAT_ERR_SUCCESS;
201     uint32_t counter_value;
202 
203     err = read_otp_nv_counters_flash(offsetof(struct flash_otp_nv_counters_region_t,
204                                               flash_nv_counters)
205                                      + counter_id * sizeof(uint32_t),
206                                      &counter_value, sizeof(counter_value));
207     if (err != TFM_PLAT_ERR_SUCCESS) {
208         return err;
209     }
210 
211     if (counter_value == UINT32_MAX) {
212         return TFM_PLAT_ERR_MAX_VALUE;
213     }
214 
215     if (counter_value > value) {
216         return TFM_PLAT_ERR_INVALID_INPUT;
217     }
218 
219     counter_value = value;
220 
221     err = write_otp_nv_counters_flash(offsetof(struct flash_otp_nv_counters_region_t,
222                                                flash_nv_counters)
223                                       + counter_id * sizeof(uint32_t),
224                                       &counter_value, sizeof(counter_value));
225     if (err != TFM_PLAT_ERR_SUCCESS) {
226         return err;
227     }
228 
229     return TFM_PLAT_ERR_SUCCESS;
230 }
231 #endif /* TFM_PARTITION_PROTECTED_STORAGE */
232 
tfm_plat_set_nv_counter(enum tfm_nv_counter_t counter_id,uint32_t value)233 enum tfm_plat_err_t tfm_plat_set_nv_counter(enum tfm_nv_counter_t counter_id,
234                                             uint32_t value)
235 {
236     uint32_t new_value;
237     enum tfm_plat_err_t err;
238 
239     switch(counter_id) {
240 #ifdef TFM_PARTITION_PROTECTED_STORAGE
241     case (PLAT_NV_COUNTER_PS_0):
242         err = set_nv_counter_flash(FLASH_NV_COUNTER_ID_PS_0, value);
243         break;
244     case (PLAT_NV_COUNTER_PS_1):
245         err = set_nv_counter_flash(FLASH_NV_COUNTER_ID_PS_1, value);
246         break;
247     case (PLAT_NV_COUNTER_PS_2):
248         err = set_nv_counter_flash(FLASH_NV_COUNTER_ID_PS_2, value);
249         break;
250 #endif /* TFM_PARTITION_PROTECTED_STORAGE */
251 
252 #ifdef BL2
253     case (PLAT_NV_COUNTER_BL2_0):
254         err = set_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_BL2_0, value);
255         break;
256     case (PLAT_NV_COUNTER_BL2_1):
257         err = set_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_BL2_1, value);
258         break;
259     case (PLAT_NV_COUNTER_BL2_2):
260         err = set_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_BL2_2, value);
261         break;
262     case (PLAT_NV_COUNTER_BL2_3):
263         err = set_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_BL2_3, value);
264         break;
265 #endif /* BL2 */
266 
267 #ifdef BL1
268     case (PLAT_NV_COUNTER_BL1_0):
269         err = set_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_BL1_0, value);
270         break;
271 #endif /* BL1 */
272 
273 #if (PLATFORM_NS_NV_COUNTERS > 0)
274     case (PLAT_NV_COUNTER_NS_0):
275         err = set_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_NS_0, value);
276         break;
277 #endif
278 #if (PLATFORM_NS_NV_COUNTERS > 1)
279     case (PLAT_NV_COUNTER_NS_1):
280         err = set_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_NS_1, value);
281         break;
282 #endif
283 #if (PLATFORM_NS_NV_COUNTERS > 2)
284     case (PLAT_NV_COUNTER_NS_2):
285         err = set_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_NS_2, value);
286         break;
287 #endif
288 
289     default:
290         return TFM_PLAT_ERR_UNSUPPORTED;
291     }
292     if (err != TFM_PLAT_ERR_SUCCESS) {
293         return err;
294     }
295 
296     /* Check that the NV counter write hasn't failed (in case the driver doesn't
297      * have a check.
298      */
299     err = tfm_plat_read_nv_counter(counter_id, sizeof(new_value),
300                                    (uint8_t *)&new_value);
301     if (err != TFM_PLAT_ERR_SUCCESS) {
302         return err;
303     }
304 
305     if(new_value != value) {
306         return TFM_PLAT_ERR_SYSTEM_ERR;
307     }
308 
309     return TFM_PLAT_ERR_SUCCESS;
310 }
311 
tfm_plat_increment_nv_counter(enum tfm_nv_counter_t counter_id)312 enum tfm_plat_err_t tfm_plat_increment_nv_counter(
313                                            enum tfm_nv_counter_t counter_id)
314 {
315     uint32_t security_cnt;
316     enum tfm_plat_err_t err;
317 
318     err = tfm_plat_read_nv_counter(counter_id,
319                                    sizeof(security_cnt),
320                                    (uint8_t *)&security_cnt);
321     if (err != TFM_PLAT_ERR_SUCCESS) {
322         return err;
323     }
324 
325     if (security_cnt == UINT32_MAX) {
326         return TFM_PLAT_ERR_MAX_VALUE;
327     }
328 
329     return tfm_plat_set_nv_counter(counter_id, security_cnt + 1u);
330 }
331