1 /*
2 * Copyright (c) 2021-2023, 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 an internal (in-die) persistent memory for the implementation
11 * of the OTP_NV_COUNTERS flash area.
12 */
13
14 #include "flash_otp_nv_counters_backend.h"
15
16 #include "tfm_plat_defs.h"
17 #include "Driver_Flash.h"
18 #include "flash_layout.h"
19
20 #include <string.h>
21
22 static enum tfm_plat_err_t create_or_restore_layout(void);
23
24 #ifdef OTP_NV_COUNTERS_RAM_EMULATION
25
26 static struct flash_otp_nv_counters_region_t otp_nv_ram_buf = {0};
27
read_otp_nv_counters_flash(uint32_t offset,void * data,uint32_t cnt)28 enum tfm_plat_err_t read_otp_nv_counters_flash(uint32_t offset, void *data, uint32_t cnt)
29 {
30 memcpy(data, ((void*)&otp_nv_ram_buf) + offset, cnt);
31
32 return TFM_PLAT_ERR_SUCCESS;
33 }
34
init_otp_nv_counters_flash(void)35 enum tfm_plat_err_t init_otp_nv_counters_flash(void)
36 {
37 if (otp_nv_ram_buf.init_value != OTP_NV_COUNTERS_INITIALIZED) {
38 #if defined(OTP_WRITEABLE)
39 err = create_or_restore_layout();
40 #else
41 err = TFM_PLAT_ERR_SYSTEM_ERR;
42 #endif
43 }
44 return TFM_PLAT_ERR_SUCCESS;
45 }
46
47 #if defined(OTP_WRITEABLE)
48 static enum tfm_plat_err_t create_or_restore_layout(void);
49 {
50 memset(&otp_nv_ram_buf, 0, sizeof(otp_nv_ram_buf));
51 otp_nv_ram_buf.init_value = OTP_NV_COUNTERS_INITIALIZED;
52 return TFM_PLAT_ERR_SUCCESS;
53 }
54
write_otp_nv_counters_flash(uint32_t offset,const void * data,uint32_t cnt)55 enum tfm_plat_err_t write_otp_nv_counters_flash(uint32_t offset, const void *data, uint32_t cnt)
56 {
57 memcpy(((void*)&otp_nv_ram_buf) + offset, data, cnt);
58
59 return TFM_PLAT_ERR_SUCCESS;
60 }
61 #endif /* defined(OTP_WRITEABLE)*/
62
63 #else /* OTP_NV_COUNTERS_RAM_EMULATION */
64 /* Valid entries for data item width */
65 static const uint32_t data_width_byte[] = {
66 sizeof(uint8_t),
67 sizeof(uint16_t),
68 sizeof(uint32_t),
69 };
70
71 #if defined(OTP_WRITEABLE)
72 static enum tfm_plat_err_t make_backup(void);
73 #endif
74
75 /* Compilation time checks to be sure the defines are well defined */
76 #ifndef TFM_OTP_NV_COUNTERS_AREA_ADDR
77 #error "TFM_OTP_NV_COUNTERS_AREA_ADDR must be defined in flash_layout.h"
78 #endif
79
80 #if defined(OTP_WRITEABLE)
81 #ifndef TFM_OTP_NV_COUNTERS_BACKUP_AREA_ADDR
82 #error "TFM_OTP_NV_COUNTERS_BACKUP_AREA_ADDR must be defined in flash_layout.h"
83 #endif
84 #endif
85
86 #ifndef TFM_OTP_NV_COUNTERS_AREA_SIZE
87 #error "TFM_OTP_NV_COUNTERS_AREA_SIZE must be defined in flash_layout.h"
88 #endif
89
90 #if defined(OTP_WRITEABLE)
91 #ifndef TFM_OTP_NV_COUNTERS_SECTOR_SIZE
92 #error "TFM_OTP_NV_COUNTERS_SECTOR_SIZE must be defined in flash_layout.h"
93 #endif
94 #endif
95 #ifndef OTP_NV_COUNTERS_FLASH_DEV
96 #ifndef TFM_HAL_ITS_FLASH_DRIVER
97 #error "OTP_NV_COUNTERS_FLASH_DEV or TFM_HAL_ITS_FLASH_DRIVER must be defined in flash_layout.h"
98 #else
99 #define OTP_NV_COUNTERS_FLASH_DEV TFM_HAL_ITS_FLASH_DRIVER
100 #endif
101 #endif
102
103 /* Default flash block size is either the PROGRAM_UNIT if it is > 128, or if the
104 * program unit is < 128, then it is the closest multiple of the PROGRAM_UNIT to
105 * 128. The aim of this is to keep the block size reasonable, to avoid large
106 * amounts of read/write calls, while also keeping sensible alignment.
107 */
108 #ifndef OTP_NV_COUNTERS_WRITE_BLOCK_SIZE
109 #define OTP_NV_COUNTERS_WRITE_BLOCK_SIZE (TFM_HAL_ITS_PROGRAM_UNIT > 128 ? \
110 TFM_HAL_ITS_PROGRAM_UNIT : \
111 (128 / TFM_HAL_ITS_PROGRAM_UNIT) * TFM_HAL_ITS_PROGRAM_UNIT)
112 #endif /* OTP_NV_COUNTERS_WRITE_BLOCK_SIZE */
113
114 #if (TFM_OTP_NV_COUNTERS_SECTOR_SIZE % OTP_NV_COUNTERS_WRITE_BLOCK_SIZE != 0) || \
115 (OTP_NV_COUNTERS_WRITE_BLOCK_SIZE % TFM_HAL_ITS_PROGRAM_UNIT != 0)
116 #error "OTP_NV_COUNTERS_WRITE_BLOCK_SIZE has wrong alignment"
117 #endif
118 /* End of compilation time checks to be sure the defines are well defined */
119
120 static uint8_t block[OTP_NV_COUNTERS_WRITE_BLOCK_SIZE];
121
122 /* Import the CMSIS flash device driver */
123 extern ARM_DRIVER_FLASH OTP_NV_COUNTERS_FLASH_DEV;
124
read_otp_nv_counters_flash(uint32_t offset,void * data,uint32_t cnt)125 enum tfm_plat_err_t read_otp_nv_counters_flash(uint32_t offset, void *data, uint32_t cnt)
126 {
127 enum tfm_plat_err_t err = TFM_PLAT_ERR_SUCCESS;
128 ARM_FLASH_CAPABILITIES DriverCapabilities;
129 uint8_t data_width;
130 uint32_t remaining_cnt, read_cnt;
131 uint8_t temp_buffer[sizeof(uint32_t)];
132
133 DriverCapabilities = OTP_NV_COUNTERS_FLASH_DEV.GetCapabilities();
134 data_width = data_width_byte[DriverCapabilities.data_width];
135
136 if (offset % data_width) {
137 return TFM_PLAT_ERR_INVALID_INPUT;
138 }
139 remaining_cnt = cnt;
140 read_cnt = 0;
141 if (remaining_cnt) {
142 err = (enum tfm_plat_err_t)OTP_NV_COUNTERS_FLASH_DEV.ReadData(
143 TFM_OTP_NV_COUNTERS_AREA_ADDR + offset,
144 data,
145 cnt / data_width);
146 if (err < 0) {
147 return TFM_PLAT_ERR_SYSTEM_ERR;
148 }
149 }
150 read_cnt += (cnt / data_width) * data_width;
151 remaining_cnt -= read_cnt;
152 if (remaining_cnt) {
153 err = (enum tfm_plat_err_t)OTP_NV_COUNTERS_FLASH_DEV.ReadData(
154 TFM_OTP_NV_COUNTERS_AREA_ADDR + offset + read_cnt,
155 temp_buffer,
156 1);
157 if (err < 0) {
158 return TFM_PLAT_ERR_SYSTEM_ERR;
159 }
160 memcpy((uint8_t *)data + read_cnt, temp_buffer, remaining_cnt);
161 }
162 return TFM_PLAT_ERR_SUCCESS;
163 }
164
init_otp_nv_counters_flash(void)165 enum tfm_plat_err_t init_otp_nv_counters_flash(void)
166 {
167 enum tfm_plat_err_t err = TFM_PLAT_ERR_SUCCESS;
168 uint32_t init_value;
169 uint32_t swap_count;
170 uint32_t backup_swap_count;
171
172 if ((TFM_OTP_NV_COUNTERS_AREA_SIZE) < sizeof(struct flash_otp_nv_counters_region_t)) {
173 return TFM_PLAT_ERR_SYSTEM_ERR;
174 }
175
176 err = (enum tfm_plat_err_t)OTP_NV_COUNTERS_FLASH_DEV.Initialize(NULL);
177 if (err != ARM_DRIVER_OK) {
178 return TFM_PLAT_ERR_SYSTEM_ERR;
179 }
180
181 err = read_otp_nv_counters_flash(offsetof(struct flash_otp_nv_counters_region_t, init_value),
182 &init_value, sizeof(init_value));
183 if (err != TFM_PLAT_ERR_SUCCESS) {
184 return err;
185 }
186
187 err = read_otp_nv_counters_flash(offsetof(struct flash_otp_nv_counters_region_t, swap_count),
188 &swap_count, sizeof(swap_count));
189 if (err != TFM_PLAT_ERR_SUCCESS) {
190 return err;
191 }
192
193
194 if (init_value != OTP_NV_COUNTERS_INITIALIZED ||
195 (swap_count == 0 || swap_count == UINT32_MAX)) {
196 #if defined(OTP_WRITEABLE)
197 err = create_or_restore_layout();
198 }
199 else
200 {
201 err = read_otp_nv_counters_flash(offsetof(struct flash_otp_nv_counters_region_t, swap_count)
202 + TFM_OTP_NV_COUNTERS_AREA_SIZE,
203 &backup_swap_count, sizeof(backup_swap_count));
204 if (err != TFM_PLAT_ERR_SUCCESS) {
205 return err;
206 }
207
208 if (backup_swap_count == 0 || backup_swap_count == UINT32_MAX ||
209 backup_swap_count < swap_count ||
210 (backup_swap_count == UINT32_MAX - 1 && swap_count == 1)) {
211 err = make_backup();
212 if (err != TFM_PLAT_ERR_SUCCESS) {
213 return err;
214 }
215 }
216 #else
217 err = TFM_PLAT_ERR_SYSTEM_ERR;
218 #endif
219 }
220
221 return err;
222 }
223
224 #if defined(OTP_WRITEABLE)
round_down(uint32_t num,uint32_t boundary)225 static inline uint32_t round_down(uint32_t num, uint32_t boundary)
226 {
227 return num - (num % boundary);
228 }
229
round_up(uint32_t num,uint32_t boundary)230 static inline uint32_t round_up(uint32_t num, uint32_t boundary)
231 {
232 return (num + boundary - 1) - ((num + boundary - 1) % boundary);
233 }
234
erase_flash_region(size_t start,size_t size)235 static enum tfm_plat_err_t erase_flash_region(size_t start, size_t size)
236 {
237 enum tfm_plat_err_t err = TFM_PLAT_ERR_SUCCESS;
238 size_t idx;
239
240 if ((start % TFM_OTP_NV_COUNTERS_SECTOR_SIZE) != 0) {
241 return TFM_PLAT_ERR_INVALID_INPUT;
242 }
243
244 for (idx = round_down(start, TFM_OTP_NV_COUNTERS_SECTOR_SIZE);
245 idx < start + size;
246 idx += TFM_OTP_NV_COUNTERS_SECTOR_SIZE) {
247 err = (enum tfm_plat_err_t)OTP_NV_COUNTERS_FLASH_DEV.EraseSector(idx);
248 if (err != ARM_DRIVER_OK) {
249 return TFM_PLAT_ERR_SYSTEM_ERR;
250 }
251 }
252
253 return err;
254 }
255
copy_flash_region(size_t from,size_t to,size_t size)256 static enum tfm_plat_err_t copy_flash_region(size_t from, size_t to, size_t size)
257 {
258 enum tfm_plat_err_t err = TFM_PLAT_ERR_SUCCESS;
259 size_t copy_size;
260 size_t idx;
261 size_t end;
262
263 end = size;
264 ARM_FLASH_CAPABILITIES DriverCapabilities;
265 uint8_t data_width;
266
267 DriverCapabilities = OTP_NV_COUNTERS_FLASH_DEV.GetCapabilities();
268 data_width = data_width_byte[DriverCapabilities.data_width];
269
270 for(idx = 0; idx < end; idx += copy_size) {
271 copy_size = (idx + sizeof(block)) <= end ? sizeof(block) : end - idx;
272
273 err = (enum tfm_plat_err_t)OTP_NV_COUNTERS_FLASH_DEV.ReadData(from + idx, block, copy_size / data_width);
274 if (err < 0) {
275 return TFM_PLAT_ERR_SYSTEM_ERR;
276 }
277
278 err = (enum tfm_plat_err_t)OTP_NV_COUNTERS_FLASH_DEV.ProgramData(to + idx, block, copy_size / data_width);
279 if (err < 0) {
280 return TFM_PLAT_ERR_SYSTEM_ERR;
281 }
282 }
283 return TFM_PLAT_ERR_SUCCESS;
284 }
285
make_backup(void)286 static enum tfm_plat_err_t make_backup(void)
287 {
288 enum tfm_plat_err_t err = TFM_PLAT_ERR_SUCCESS;
289
290 err = erase_flash_region(TFM_OTP_NV_COUNTERS_BACKUP_AREA_ADDR,
291 TFM_OTP_NV_COUNTERS_AREA_SIZE);
292 if (err != TFM_PLAT_ERR_SUCCESS) {
293 return err;
294 }
295
296 err = copy_flash_region(TFM_OTP_NV_COUNTERS_AREA_ADDR,
297 TFM_OTP_NV_COUNTERS_BACKUP_AREA_ADDR,
298 TFM_OTP_NV_COUNTERS_AREA_SIZE);
299
300 return err;
301 }
302
copy_data_into_block(uint32_t data_offset,size_t data_size,const uint8_t * data,uint32_t block_offset,size_t block_size,uint8_t * block)303 static enum tfm_plat_err_t copy_data_into_block(uint32_t data_offset,
304 size_t data_size,
305 const uint8_t *data,
306 uint32_t block_offset,
307 size_t block_size,
308 uint8_t *block)
309 {
310 uint32_t copy_start_offset;
311 uint32_t copy_end_offset;
312
313 /* Check if any of our data needs to be copied into this buf */
314 if (data_offset + data_size > block_offset &&
315 data_offset < block_offset + block_size) {
316 if (data_offset > block_offset) {
317 copy_start_offset = data_offset;
318 } else {
319 copy_start_offset = block_offset;
320 }
321
322 if (data_offset + data_size > block_offset + block_size) {
323 copy_end_offset = block_offset + block_size;
324 } else {
325 copy_end_offset = data_offset + data_size;
326 }
327
328 memcpy(block + (copy_start_offset - block_offset),
329 data + (copy_start_offset - data_offset),
330 copy_end_offset - copy_start_offset);
331 }
332
333 return TFM_PLAT_ERR_SUCCESS;
334 }
335
write_otp_nv_counters_flash(uint32_t offset,const void * data,uint32_t cnt)336 enum tfm_plat_err_t write_otp_nv_counters_flash(uint32_t offset, const void *data, uint32_t cnt)
337 {
338 enum tfm_plat_err_t err = TFM_PLAT_ERR_SUCCESS;
339 size_t copy_size;
340 size_t erase_start_offset;
341 size_t erase_end_offset;
342 size_t swap_count_erase_start_offset;
343 size_t swap_count_program_block_start_offset;
344 size_t idx;
345 uint32_t swap_count;
346 uint32_t swap_count_buf_size = TFM_HAL_ITS_PROGRAM_UNIT > sizeof(swap_count) ?
347 TFM_HAL_ITS_PROGRAM_UNIT : sizeof(swap_count);
348
349 erase_start_offset = round_down(offset, TFM_OTP_NV_COUNTERS_SECTOR_SIZE);
350 erase_end_offset = round_up(offset + cnt, TFM_OTP_NV_COUNTERS_SECTOR_SIZE);
351
352 swap_count_erase_start_offset =
353 round_down(offsetof(struct flash_otp_nv_counters_region_t, swap_count),
354 TFM_OTP_NV_COUNTERS_SECTOR_SIZE);
355
356 swap_count_program_block_start_offset =
357 round_down(offsetof(struct flash_otp_nv_counters_region_t, swap_count),
358 TFM_HAL_ITS_PROGRAM_UNIT);
359
360 if (erase_end_offset > TFM_OTP_NV_COUNTERS_AREA_SIZE) {
361 /* Erase is beyond the TFM_OTP_NV_COUNTERS_AREA */
362 return TFM_PLAT_ERR_SYSTEM_ERR;
363 }
364
365 ARM_FLASH_CAPABILITIES DriverCapabilities;
366 uint8_t data_width;
367
368 DriverCapabilities = OTP_NV_COUNTERS_FLASH_DEV.GetCapabilities();
369 data_width = data_width_byte[DriverCapabilities.data_width];
370
371 /* read the swap_count now, to make life easier when writing it later */
372 err = (enum tfm_plat_err_t)OTP_NV_COUNTERS_FLASH_DEV.ReadData(
373 TFM_OTP_NV_COUNTERS_BACKUP_AREA_ADDR +
374 offsetof(struct flash_otp_nv_counters_region_t, swap_count),
375 &swap_count, sizeof(swap_count) / data_width);
376 if (err < 0) {
377 return TFM_PLAT_ERR_SYSTEM_ERR;
378 }
379
380 swap_count += 1;
381 if (swap_count == UINT32_MAX) {
382 swap_count = 1;
383 }
384
385 /* If it's not part of the sectors that are being erased, first erase the
386 * sector with the swap_count flag.
387 */
388 if (erase_end_offset <= swap_count_erase_start_offset) {
389 err = erase_flash_region(TFM_OTP_NV_COUNTERS_AREA_ADDR +
390 swap_count_erase_start_offset,
391 TFM_OTP_NV_COUNTERS_SECTOR_SIZE);
392 if (err != TFM_PLAT_ERR_SUCCESS) {
393 return err;
394 }
395 }
396
397 /* Erase the region we want to write */
398 err = erase_flash_region(TFM_OTP_NV_COUNTERS_AREA_ADDR + erase_start_offset,
399 erase_end_offset - erase_start_offset);
400 if (err != TFM_PLAT_ERR_SUCCESS) {
401 return err;
402 }
403
404 /* Don't write the swap count, as this is done at the end */
405 if (erase_end_offset > swap_count_program_block_start_offset) {
406 erase_end_offset = swap_count_program_block_start_offset;
407 }
408
409 for (idx = erase_start_offset; idx < erase_end_offset; idx += copy_size) {
410 if ((idx + sizeof(block)) <= erase_end_offset) {
411 copy_size = sizeof(block);
412 } else {
413 copy_size = erase_end_offset - idx;
414 }
415
416 err = (enum tfm_plat_err_t)OTP_NV_COUNTERS_FLASH_DEV.ReadData(
417 TFM_OTP_NV_COUNTERS_BACKUP_AREA_ADDR + idx, block,
418 copy_size / data_width);
419 if (err < 0) {
420 return TFM_PLAT_ERR_SYSTEM_ERR;
421 }
422
423 err = copy_data_into_block(offset, cnt, data, idx, copy_size, block);
424 if (err != TFM_PLAT_ERR_SUCCESS) {
425 return err;
426 }
427
428 uint32_t num_items = copy_size / data_width;
429
430 err = (enum tfm_plat_err_t)OTP_NV_COUNTERS_FLASH_DEV.ProgramData(
431 TFM_OTP_NV_COUNTERS_AREA_ADDR + idx, block, num_items);
432 if (err < 0) {
433 return TFM_PLAT_ERR_SYSTEM_ERR;
434 }
435
436 /* When err is positive it contains the number of data items
437 * successfully programmed. Check that every byte of
438 * programming succeeded.
439 */
440 if (err > 0 && err != num_items) {
441 return TFM_PLAT_ERR_SYSTEM_ERR;
442 }
443 }
444
445 /* If we've not already restored most of the last sector (except the swap
446 * count), do it now. */
447 if (erase_end_offset < swap_count_program_block_start_offset) {
448 err = copy_flash_region(
449 TFM_OTP_NV_COUNTERS_BACKUP_AREA_ADDR + swap_count_erase_start_offset,
450 TFM_OTP_NV_COUNTERS_AREA_ADDR + swap_count_erase_start_offset,
451 swap_count_program_block_start_offset - swap_count_erase_start_offset);
452 if (err != TFM_PLAT_ERR_SUCCESS) {
453 return err;
454 }
455 }
456
457 /* Copy the last program-unit. This _may_ contain the data that we needed to
458 * write on platforms that have large program-units, so attempt to write
459 * into the buffer still (and let copy_data_into_block() check if it needs
460 * to actually copy).
461 */
462 err = (enum tfm_plat_err_t)OTP_NV_COUNTERS_FLASH_DEV.ReadData(
463 TFM_OTP_NV_COUNTERS_BACKUP_AREA_ADDR + swap_count_program_block_start_offset,
464 block, swap_count_buf_size / data_width);
465 if (err < 0) {
466 return TFM_PLAT_ERR_SYSTEM_ERR;
467 }
468
469 err = copy_data_into_block(offset, cnt, data,
470 swap_count_program_block_start_offset,
471 swap_count_buf_size, block);
472 if (err != TFM_PLAT_ERR_SUCCESS) {
473 return err;
474 }
475
476 err = copy_data_into_block(
477 offsetof(struct flash_otp_nv_counters_region_t, swap_count),
478 sizeof(swap_count), (uint8_t *)&swap_count,
479 swap_count_program_block_start_offset, swap_count_buf_size, block);
480 if (err != TFM_PLAT_ERR_SUCCESS) {
481 return err;
482 }
483
484 uint32_t num_items = swap_count_buf_size / data_width;
485
486 err = (enum tfm_plat_err_t)OTP_NV_COUNTERS_FLASH_DEV.ProgramData(
487 TFM_OTP_NV_COUNTERS_AREA_ADDR + swap_count_program_block_start_offset,
488 block, num_items);
489 if (err < 0) {
490 return TFM_PLAT_ERR_SYSTEM_ERR;
491 }
492
493 /* When err is positive it contains the number of data items
494 * successfully programmed. Check that every byte of
495 * programming succeeded.
496 */
497 if (err > 0 && err != num_items) {
498 return TFM_PLAT_ERR_SYSTEM_ERR;
499 }
500
501 err = make_backup();
502 if (err != TFM_PLAT_ERR_SUCCESS) {
503 return err;
504 }
505 return err;
506 }
507
restore_backup(void)508 static enum tfm_plat_err_t restore_backup(void)
509 {
510 enum tfm_plat_err_t err = TFM_PLAT_ERR_SUCCESS;
511
512 err = erase_flash_region(TFM_OTP_NV_COUNTERS_AREA_ADDR,
513 TFM_OTP_NV_COUNTERS_AREA_SIZE);
514 if (err != TFM_PLAT_ERR_SUCCESS) {
515 return err;
516 }
517
518 err = copy_flash_region(TFM_OTP_NV_COUNTERS_BACKUP_AREA_ADDR,
519 TFM_OTP_NV_COUNTERS_AREA_ADDR,
520 TFM_OTP_NV_COUNTERS_AREA_SIZE);
521
522 return err;
523 }
524
create_or_restore_layout(void)525 static enum tfm_plat_err_t create_or_restore_layout(void)
526 {
527 enum tfm_plat_err_t err = TFM_PLAT_ERR_SUCCESS;
528 uint32_t init_value;
529 uint32_t swap_count;
530 uint32_t backup_init_value;
531 uint32_t backup_swap_count;
532 size_t idx;
533 size_t end;
534 size_t copy_size;
535 ARM_FLASH_CAPABILITIES DriverCapabilities;
536 uint8_t data_width;
537
538 DriverCapabilities = OTP_NV_COUNTERS_FLASH_DEV.GetCapabilities();
539 data_width = data_width_byte[DriverCapabilities.data_width];
540
541 err = read_otp_nv_counters_flash(offsetof(struct flash_otp_nv_counters_region_t, init_value)
542 + TFM_OTP_NV_COUNTERS_AREA_SIZE,
543 &backup_init_value, sizeof(init_value));
544 if (err != TFM_PLAT_ERR_SUCCESS) {
545 return err;
546 }
547 err = read_otp_nv_counters_flash(offsetof(struct flash_otp_nv_counters_region_t, swap_count)
548 + TFM_OTP_NV_COUNTERS_AREA_SIZE,
549 &backup_swap_count, sizeof(swap_count));
550 if (err != TFM_PLAT_ERR_SUCCESS) {
551 return err;
552 }
553
554 if (backup_init_value == OTP_NV_COUNTERS_INITIALIZED &&
555 /* valid backup, restore */
556 backup_swap_count != 0 && backup_swap_count != UINT32_MAX) {
557 err = restore_backup();
558 if (err != TFM_PLAT_ERR_SUCCESS) {
559 return err;
560 }
561 } else {
562 /* No valid layouts, create from scratch */
563 err = erase_flash_region(TFM_OTP_NV_COUNTERS_AREA_ADDR,
564 TFM_OTP_NV_COUNTERS_AREA_SIZE);
565 if (err != TFM_PLAT_ERR_SUCCESS) {
566 return err;
567 }
568
569 memset(block, 0, sizeof(block));
570 end = TFM_OTP_NV_COUNTERS_AREA_SIZE;
571 for(idx = 0; idx < end; idx += copy_size) {
572 copy_size = (idx + sizeof(block)) <= end ? sizeof(block) : end - idx;
573
574 err = (enum tfm_plat_err_t)OTP_NV_COUNTERS_FLASH_DEV.ProgramData(TFM_OTP_NV_COUNTERS_AREA_ADDR + idx,
575 block, copy_size / data_width);
576 if (err < 0) {
577 return TFM_PLAT_ERR_SYSTEM_ERR;
578 }
579 }
580
581 err = make_backup();
582 if (err != TFM_PLAT_ERR_SUCCESS) {
583 return err;
584 }
585
586 init_value = OTP_NV_COUNTERS_INITIALIZED;
587 err = write_otp_nv_counters_flash(offsetof(struct flash_otp_nv_counters_region_t, init_value),
588 &init_value, sizeof(init_value));
589 if (err != ARM_DRIVER_OK) {
590 return TFM_PLAT_ERR_SYSTEM_ERR;
591 }
592
593 swap_count = 1;
594 err = write_otp_nv_counters_flash(offsetof(struct flash_otp_nv_counters_region_t, swap_count),
595 &swap_count, sizeof(swap_count));
596 if (err != ARM_DRIVER_OK) {
597 return TFM_PLAT_ERR_SYSTEM_ERR;
598 }
599 }
600 return err;
601 }
602 #endif /* OTP_WRITEABLE */
603
604 #endif /* OTP_NV_COUNTERS_RAM_EMULATION */
605