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