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