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