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