Platform: Add NV counters for reference targets

This patch adds dummy NV counters implementation for supported
platforms AN521, AN519 and Musca A1.

Change-Id: I8d830d9bf9abb56ac3aaad6172ef551fac5bebaa
Signed-off-by: Marc Moreno <marc.morenoberengue@arm.com>
diff --git a/platform/ext/Mps2AN519.cmake b/platform/ext/Mps2AN519.cmake
old mode 100755
new mode 100644
index 31f4d15..f1475bf
--- a/platform/ext/Mps2AN519.cmake
+++ b/platform/ext/Mps2AN519.cmake
@@ -125,6 +125,16 @@
   list(APPEND ALL_SRC_C "${PLATFORM_DIR}/target/mps2/an519/dummy_crypto_keys.c")
 endif()
 
+if (NOT DEFINED BUILD_TARGET_NV_COUNTERS)
+  message(FATAL_ERROR "Configuration variable BUILD_TARGET_NV_COUNTERS (true|false) is undefined!")
+elseif(BUILD_TARGET_NV_COUNTERS)
+  # NOTE: This non-volatile counters implementation is a dummy
+  #       implementation. Platform vendors have to implement the
+  #       API ONLY if the target has non-volatile counters.
+  list(APPEND ALL_SRC_C "${PLATFORM_DIR}/target/mps2/an519/dummy_nv_counters.c")
+  set(TARGET_NV_COUNTERS_ENABLE ON)
+endif()
+
 if (NOT DEFINED BUILD_CMSIS_DRIVERS)
   message(FATAL_ERROR "Configuration variable BUILD_CMSIS_DRIVERS (true|false) is undefined!")
 elseif(BUILD_CMSIS_DRIVERS)
diff --git a/platform/ext/Mps2AN521.cmake b/platform/ext/Mps2AN521.cmake
old mode 100755
new mode 100644
index 97d28d8..a0c453f
--- a/platform/ext/Mps2AN521.cmake
+++ b/platform/ext/Mps2AN521.cmake
@@ -126,6 +126,16 @@
   list(APPEND ALL_SRC_C "${PLATFORM_DIR}/target/mps2/an521/dummy_crypto_keys.c")
 endif()
 
+if (NOT DEFINED BUILD_TARGET_NV_COUNTERS)
+  message(FATAL_ERROR "Configuration variable BUILD_TARGET_NV_COUNTERS (true|false) is undefined!")
+elseif(BUILD_TARGET_NV_COUNTERS)
+  # NOTE: This non-volatile counters implementation is a dummy
+  #       implementation. Platform vendors have to implement the
+  #       API ONLY if the target has non-volatile counters.
+  list(APPEND ALL_SRC_C "${PLATFORM_DIR}/target/mps2/an521/dummy_nv_counters.c")
+  set(TARGET_NV_COUNTERS_ENABLE ON)
+endif()
+
 if (NOT DEFINED BUILD_CMSIS_DRIVERS)
   message(FATAL_ERROR "Configuration variable BUILD_CMSIS_DRIVERS (true|false) is undefined!")
 elseif(BUILD_CMSIS_DRIVERS)
diff --git a/platform/ext/musca_a.cmake b/platform/ext/musca_a.cmake
index 78434fe..e9c06c5 100755
--- a/platform/ext/musca_a.cmake
+++ b/platform/ext/musca_a.cmake
@@ -129,6 +129,16 @@
   list(APPEND ALL_SRC_C "${PLATFORM_DIR}/target/musca_a/dummy_crypto_keys.c")
 endif()
 
+if (NOT DEFINED BUILD_TARGET_NV_COUNTERS)
+  message(FATAL_ERROR "Configuration variable BUILD_TARGET_NV_COUNTERS (true|false) is undefined!")
+elseif(BUILD_TARGET_NV_COUNTERS)
+  # NOTE: This non-volatile counters implementation is a dummy
+  #       implementation. Platform vendors have to implement the
+  #       API ONLY if the target has non-volatile counters.
+  list(APPEND ALL_SRC_C "${PLATFORM_DIR}/target/musca_a/dummy_nv_counters.c")
+  set(TARGET_NV_COUNTERS_ENABLE ON)
+endif()
+
 if (NOT DEFINED BUILD_CMSIS_DRIVERS)
   message(FATAL_ERROR "Configuration variable BUILD_CMSIS_DRIVERS (true|false) is undefined!")
 elseif(BUILD_CMSIS_DRIVERS)
diff --git a/platform/ext/target/mps2/an519/armclang/mps2_an519_s.sct b/platform/ext/target/mps2/an519/armclang/mps2_an519_s.sct
index 5216d50..4c043c3 100644
--- a/platform/ext/target/mps2/an519/armclang/mps2_an519_s.sct
+++ b/platform/ext/target/mps2/an519/armclang/mps2_an519_s.sct
@@ -44,6 +44,7 @@
     TFM_UNPRIV_CODE +0 ALIGN 32 {
         tfm_unpriv_api.o (+RO)
         dummy_crypto_keys.o (+RO)
+        dummy_nv_counters.o (+RO)
         platform_retarget_dev.o (+RO)
         *(SFN)
         *armlib*
@@ -91,6 +92,7 @@
     TFM_UNPRIV_RO_DATA +0 ALIGN 32 {
         tfm_unpriv_api.o (+RW +ZI)
         dummy_crypto_keys.o (+RW +ZI)
+        dummy_nv_counters.o (+RW +ZI)
         platform_retarget_dev.o (+RW +ZI)
     }
 
diff --git a/platform/ext/target/mps2/an519/dummy_nv_counters.c b/platform/ext/target/mps2/an519/dummy_nv_counters.c
new file mode 100644
index 0000000..6f8ea62
--- /dev/null
+++ b/platform/ext/target/mps2/an519/dummy_nv_counters.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/* NOTE: This API should be implemented by platform vendor. For the
+ * security of the secure storage system rollback protection and others, it is
+ * CRITICAL to use a internal (in-die) persistent memory for multiple time
+ * programabe (MTP) non-volatile counters or use a One-time Programmable (OTP)
+ * non-volatile counters solution.
+ *
+ * AN519 does not have any available MTP or OTP non-volatile counters, so a
+ * software dummy implementation has been implemented in this case.
+ */
+
+#include "platform/include/tfm_plat_nv_counters.h"
+
+#include <limits.h>
+#include "Driver_Flash.h"
+#include "flash_layout.h"
+
+/* Compilation time checks to be sure the defines are well defined */
+#ifndef TFM_NV_COUNTERS_AREA_ADDR
+#error "TFM_NV_COUNTERS_AREA_ADDR must be defined in flash_layout.h"
+#endif
+
+#ifndef TFM_NV_COUNTERS_AREA_SIZE
+#error "TFM_NV_COUNTERS_AREA_SIZE must be defined in flash_layout.h"
+#endif
+
+#ifndef TFM_NV_COUNTERS_SECTOR_ADDR
+#error "TFM_NV_COUNTERS_SECTOR_ADDR must be defined in flash_layout.h"
+#endif
+
+#ifndef TFM_NV_COUNTERS_SECTOR_SIZE
+#error "TFM_NV_COUNTERS_SECTOR_SIZE must be defined in flash_layout.h"
+#endif
+
+#ifndef FLASH_DEV_NAME
+#error "FLASH_DEV_NAME must be defined in flash_layout.h"
+#endif
+/* End of compilation time checks to be sure the defines are well defined */
+
+#define SECTOR_OFFSET    0
+#define NV_COUNTER_SIZE  sizeof(uint32_t)
+#define INIT_VALUE_SIZE  NV_COUNTER_SIZE
+#define NV_COUNTERS_AREA_OFFSET (TFM_NV_COUNTERS_AREA_ADDR - \
+                                 TFM_NV_COUNTERS_SECTOR_ADDR)
+
+#define NV_COUNTERS_INITIALIZED 0xC0DE0042
+
+/* Import the CMSIS flash device driver */
+extern ARM_DRIVER_FLASH FLASH_DEV_NAME;
+
+enum tfm_plat_err_t tfm_plat_init_nv_counter(void)
+{
+    int32_t  err;
+    uint32_t i;
+    uint32_t nbr_counters = ((TFM_NV_COUNTERS_AREA_SIZE - INIT_VALUE_SIZE)
+                             / NV_COUNTER_SIZE);
+    uint32_t *p_nv_counter;
+    uint8_t sector_data[TFM_NV_COUNTERS_SECTOR_SIZE] = {0};
+
+    /* Read the whole sector to be able to erase and write later in the flash */
+    err = FLASH_DEV_NAME.ReadData(TFM_NV_COUNTERS_SECTOR_ADDR, sector_data,
+                                  TFM_NV_COUNTERS_SECTOR_SIZE);
+    if (err != ARM_DRIVER_OK) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    /* Set the pointer to nv counters position */
+    p_nv_counter = (uint32_t *)(sector_data + NV_COUNTERS_AREA_OFFSET);
+
+    if (p_nv_counter[nbr_counters] == NV_COUNTERS_INITIALIZED) {
+        return TFM_PLAT_ERR_SUCCESS;
+    }
+
+    /* Add watermark, at the end of the NV counters area, to indicate that NV
+     * counters have been initialized.
+     */
+    p_nv_counter[nbr_counters] = NV_COUNTERS_INITIALIZED;
+
+    /* Initialize all counters to 0 */
+    for (i = 0; i < nbr_counters; i++) {
+        p_nv_counter[i] = 0;
+    }
+
+    /* Erase sector before write in it */
+    err = FLASH_DEV_NAME.EraseSector(TFM_NV_COUNTERS_SECTOR_ADDR);
+    if (err != ARM_DRIVER_OK) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    /* Write in flash the in-memory block content after modification */
+    err = FLASH_DEV_NAME.ProgramData(TFM_NV_COUNTERS_SECTOR_ADDR, sector_data,
+                                     TFM_NV_COUNTERS_SECTOR_SIZE);
+    if (err != ARM_DRIVER_OK) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    return TFM_PLAT_ERR_SUCCESS;
+}
+
+enum tfm_plat_err_t tfm_plat_read_nv_counter(enum tfm_nv_counter_t counter_id,
+                                             uint32_t size, uint8_t *val)
+{
+    int32_t  err;
+    uint32_t flash_addr;
+
+    if (size != NV_COUNTER_SIZE) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    flash_addr = TFM_NV_COUNTERS_AREA_ADDR + (counter_id * NV_COUNTER_SIZE);
+
+    err = FLASH_DEV_NAME.ReadData(flash_addr, val, NV_COUNTER_SIZE);
+    if (err != ARM_DRIVER_OK) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    return TFM_PLAT_ERR_SUCCESS;
+}
+
+enum tfm_plat_err_t tfm_plat_increment_nv_counter(
+                                               enum tfm_nv_counter_t counter_id)
+{
+    int32_t  err;
+    uint32_t *p_nv_counter;
+    uint8_t  sector_data[TFM_NV_COUNTERS_SECTOR_SIZE];
+
+    /* Read the whole sector to be able to erase and write later in the flash */
+    err = FLASH_DEV_NAME.ReadData(TFM_NV_COUNTERS_SECTOR_ADDR, sector_data,
+                                  TFM_NV_COUNTERS_SECTOR_SIZE);
+    if (err != ARM_DRIVER_OK) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    /* Set the pointer to nv counter position */
+    p_nv_counter = (uint32_t *)(sector_data + NV_COUNTERS_AREA_OFFSET +
+                                (counter_id * NV_COUNTER_SIZE));
+
+    if (*p_nv_counter == UINT32_MAX) {
+        return TFM_PLAT_ERR_MAX_VALUE;
+    }
+
+    /* Next value is the current value + 1 */
+    *p_nv_counter = *p_nv_counter + 1;
+
+    /* Erase sector before write in it */
+    err = FLASH_DEV_NAME.EraseSector(TFM_NV_COUNTERS_SECTOR_ADDR);
+    if (err != ARM_DRIVER_OK) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    /* Write in flash the in-memory block content after modification */
+    err = FLASH_DEV_NAME.ProgramData(TFM_NV_COUNTERS_SECTOR_ADDR, sector_data,
+                                     TFM_NV_COUNTERS_SECTOR_SIZE);
+    if (err != ARM_DRIVER_OK) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    return TFM_PLAT_ERR_SUCCESS;
+}
diff --git a/platform/ext/target/mps2/an519/gcc/mps2_an519_s.ld b/platform/ext/target/mps2/an519/gcc/mps2_an519_s.ld
index 7b1ea60..9c33da4 100644
--- a/platform/ext/target/mps2/an519/gcc/mps2_an519_s.ld
+++ b/platform/ext/target/mps2/an519/gcc/mps2_an519_s.ld
@@ -170,6 +170,8 @@
         *tfm_unpriv_api.o(.rodata*)
         *dummy_crypto_keys.o(.text*)
         *dummy_crypto_keys.o(.rodata*)
+        *dummy_nv_counters.o(.text*)
+        *dummy_nv_counters.o(.rodata*)
         *platform_retarget_dev.o(.text*)
         *platform_retarget_dev.o(.rodata*)
         *(SFN)
@@ -331,6 +333,7 @@
     {
         */tfm_unpriv_api.o(.data*)
         */dummy_crypto_keys.o(.data*)
+        */dummy_nv_counters.o(.data*)
         */platform_retarget_dev.o(.data*)
         . = ALIGN(32);
     } > RAM AT> FLASH
@@ -342,9 +345,11 @@
         */tfm_unpriv_api.o(.bss*)
         */platform_retarget_dev.o(.bss*)
         */dummy_crypto_keys.o(.bss*)
+        */dummy_nv_counters.o(.bss*)
         */tfm_unpriv_api.o(COMMON)
         */platform_retarget_dev.o(COMMON)
         */dummy_crypto_keys.o(COMMON)
+        */dummy_nv_counters.o(COMMON)
         . = ALIGN(32);
     } > RAM AT> FLASH
     Image$$TFM_UNPRIV_RO_DATA$$ZI$$Base = ADDR(.TFM_UNPRIV_RO_BSS);
diff --git a/platform/ext/target/mps2/an519/gcc/mps2_an519_s.ld.template b/platform/ext/target/mps2/an519/gcc/mps2_an519_s.ld.template
index ededa5c..14f7629 100644
--- a/platform/ext/target/mps2/an519/gcc/mps2_an519_s.ld.template
+++ b/platform/ext/target/mps2/an519/gcc/mps2_an519_s.ld.template
@@ -135,6 +135,8 @@
         *tfm_unpriv_api.o(.rodata*)
         *dummy_crypto_keys.o(.text*)
         *dummy_crypto_keys.o(.rodata*)
+        *dummy_nv_counters.o(.text*)
+        *dummy_nv_counters.o(.rodata*)
         *platform_retarget_dev.o(.text*)
         *platform_retarget_dev.o(.rodata*)
         *(SFN)
@@ -233,6 +235,7 @@
     {
         */tfm_unpriv_api.o(.data*)
         */dummy_crypto_keys.o(.data*)
+        */dummy_nv_counters.o(.data*)
         */platform_retarget_dev.o(.data*)
         . = ALIGN(32);
     } > RAM AT> FLASH
@@ -244,9 +247,11 @@
         */tfm_unpriv_api.o(.bss*)
         */platform_retarget_dev.o(.bss*)
         */dummy_crypto_keys.o(.bss*)
+        */dummy_nv_counters.o(.bss*)
         */tfm_unpriv_api.o(COMMON)
         */platform_retarget_dev.o(COMMON)
         */dummy_crypto_keys.o(COMMON)
+        */dummy_nv_counters.o(COMMON)
         . = ALIGN(32);
     } > RAM AT> FLASH
     Image$$TFM_UNPRIV_RO_DATA$$ZI$$Base = ADDR(.TFM_UNPRIV_RO_BSS);
diff --git a/platform/ext/target/mps2/an519/partition/flash_layout.h b/platform/ext/target/mps2/an519/partition/flash_layout.h
index e792f7b..e953227 100644
--- a/platform/ext/target/mps2/an519/partition/flash_layout.h
+++ b/platform/ext/target/mps2/an519/partition/flash_layout.h
@@ -27,8 +27,9 @@
  *    0x0018_0000 Secure     image secondary
  *    0x0020_0000 Non-secure image secondary
  * 0x0028_0000 Scratch area(1 MB)
- * 0x0038_0000 Secure Storage Area (0.02 MB)
- * 0x0038_5000 Unused(0.482 MB)
+ * 0x0038_0000 Secure Storage Area(0.02 MB)
+ * 0x0038_5000 NV counters area(16 Bytes)
+ * 0x0038_5010 Unused(0.491 MB)
  *
  * Flash layout on MPS2 AN519, if BL2 not defined:
  * 0x0000_0000 Secure     image
@@ -83,6 +84,9 @@
 #define FLASH_SST_AREA_OFFSET           (0x380000)
 #define FLASH_SST_AREA_SIZE             (0x5000)   /* 20 KB */
 
+#define FLASH_NV_COUNTERS_AREA_OFFSET   (0x385000)
+#define FLASH_NV_COUNTERS_AREA_SIZE     (0x10)     /* 16 Bytes */
+
 /* Offset and size definition in flash area, used by assemble.py */
 #define SECURE_IMAGE_OFFSET             0x0
 #define SECURE_IMAGE_MAX_SIZE           0x80000
@@ -106,4 +110,10 @@
 /* Specifies the smallest flash programmable unit in bytes */
 #define SST_FLASH_PROGRAM_UNIT  0x1
 
+/* NV Counters definitions */
+#define TFM_NV_COUNTERS_AREA_ADDR    FLASH_NV_COUNTERS_AREA_OFFSET
+#define TFM_NV_COUNTERS_AREA_SIZE    FLASH_NV_COUNTERS_AREA_SIZE
+#define TFM_NV_COUNTERS_SECTOR_ADDR  FLASH_NV_COUNTERS_AREA_OFFSET
+#define TFM_NV_COUNTERS_SECTOR_SIZE  FLASH_AREA_IMAGE_SECTOR_SIZE
+
 #endif /* __FLASH_LAYOUT_H__ */
diff --git a/platform/ext/target/mps2/an521/armclang/mps2_an521_s.sct b/platform/ext/target/mps2/an521/armclang/mps2_an521_s.sct
index 5216d50..4c043c3 100644
--- a/platform/ext/target/mps2/an521/armclang/mps2_an521_s.sct
+++ b/platform/ext/target/mps2/an521/armclang/mps2_an521_s.sct
@@ -44,6 +44,7 @@
     TFM_UNPRIV_CODE +0 ALIGN 32 {
         tfm_unpriv_api.o (+RO)
         dummy_crypto_keys.o (+RO)
+        dummy_nv_counters.o (+RO)
         platform_retarget_dev.o (+RO)
         *(SFN)
         *armlib*
@@ -91,6 +92,7 @@
     TFM_UNPRIV_RO_DATA +0 ALIGN 32 {
         tfm_unpriv_api.o (+RW +ZI)
         dummy_crypto_keys.o (+RW +ZI)
+        dummy_nv_counters.o (+RW +ZI)
         platform_retarget_dev.o (+RW +ZI)
     }
 
diff --git a/platform/ext/target/mps2/an521/dummy_nv_counters.c b/platform/ext/target/mps2/an521/dummy_nv_counters.c
new file mode 100644
index 0000000..e82cd7c
--- /dev/null
+++ b/platform/ext/target/mps2/an521/dummy_nv_counters.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/* NOTE: This API should be implemented by platform vendor. For the
+ * security of the secure storage system rollback protection and others, it is
+ * CRITICAL to use a internal (in-die) persistent memory for multiple time
+ * programabe (MTP) non-volatile counters or use a One-time Programmable (OTP)
+ * non-volatile counters solution.
+ *
+ * AN521 does not have any available MTP or OTP non-volatile counters, so a
+ * software dummy implementation has been implemented in this case.
+ */
+
+#include "platform/include/tfm_plat_nv_counters.h"
+
+#include <limits.h>
+#include "Driver_Flash.h"
+#include "flash_layout.h"
+
+/* Compilation time checks to be sure the defines are well defined */
+#ifndef TFM_NV_COUNTERS_AREA_ADDR
+#error "TFM_NV_COUNTERS_AREA_ADDR must be defined in flash_layout.h"
+#endif
+
+#ifndef TFM_NV_COUNTERS_AREA_SIZE
+#error "TFM_NV_COUNTERS_AREA_SIZE must be defined in flash_layout.h"
+#endif
+
+#ifndef TFM_NV_COUNTERS_SECTOR_ADDR
+#error "TFM_NV_COUNTERS_SECTOR_ADDR must be defined in flash_layout.h"
+#endif
+
+#ifndef TFM_NV_COUNTERS_SECTOR_SIZE
+#error "TFM_NV_COUNTERS_SECTOR_SIZE must be defined in flash_layout.h"
+#endif
+
+#ifndef FLASH_DEV_NAME
+#error "FLASH_DEV_NAME must be defined in flash_layout.h"
+#endif
+/* End of compilation time checks to be sure the defines are well defined */
+
+#define SECTOR_OFFSET    0
+#define NV_COUNTER_SIZE  sizeof(uint32_t)
+#define INIT_VALUE_SIZE  NV_COUNTER_SIZE
+#define NV_COUNTERS_AREA_OFFSET (TFM_NV_COUNTERS_AREA_ADDR - \
+                                 TFM_NV_COUNTERS_SECTOR_ADDR)
+
+#define NV_COUNTERS_INITIALIZED 0xC0DE0042
+
+/* Import the CMSIS flash device driver */
+extern ARM_DRIVER_FLASH FLASH_DEV_NAME;
+
+enum tfm_plat_err_t tfm_plat_init_nv_counter(void)
+{
+    int32_t  err;
+    uint32_t i;
+    uint32_t nbr_counters = ((TFM_NV_COUNTERS_AREA_SIZE - INIT_VALUE_SIZE)
+                             / NV_COUNTER_SIZE);
+    uint32_t *p_nv_counter;
+    uint8_t sector_data[TFM_NV_COUNTERS_SECTOR_SIZE] = {0};
+
+    /* Read the whole sector to be able to erase and write later in the flash */
+    err = FLASH_DEV_NAME.ReadData(TFM_NV_COUNTERS_SECTOR_ADDR, sector_data,
+                                  TFM_NV_COUNTERS_SECTOR_SIZE);
+    if (err != ARM_DRIVER_OK) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    /* Set the pointer to nv counters position */
+    p_nv_counter = (uint32_t *)(sector_data + NV_COUNTERS_AREA_OFFSET);
+
+    if (p_nv_counter[nbr_counters] == NV_COUNTERS_INITIALIZED) {
+        return TFM_PLAT_ERR_SUCCESS;
+    }
+
+    /* Add watermark, at the end of the NV counters area, to indicate that NV
+     * counters have been initialized.
+     */
+    p_nv_counter[nbr_counters] = NV_COUNTERS_INITIALIZED;
+
+    /* Initialize all counters to 0 */
+    for (i = 0; i < nbr_counters; i++) {
+        p_nv_counter[i] = 0;
+    }
+
+    /* Erase sector before write in it */
+    err = FLASH_DEV_NAME.EraseSector(TFM_NV_COUNTERS_SECTOR_ADDR);
+    if (err != ARM_DRIVER_OK) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    /* Write in flash the in-memory block content after modification */
+    err = FLASH_DEV_NAME.ProgramData(TFM_NV_COUNTERS_SECTOR_ADDR, sector_data,
+                                     TFM_NV_COUNTERS_SECTOR_SIZE);
+    if (err != ARM_DRIVER_OK) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    return TFM_PLAT_ERR_SUCCESS;
+}
+
+enum tfm_plat_err_t tfm_plat_read_nv_counter(enum tfm_nv_counter_t counter_id,
+                                             uint32_t size, uint8_t *val)
+{
+    int32_t  err;
+    uint32_t flash_addr;
+
+    if (size != NV_COUNTER_SIZE) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    flash_addr = TFM_NV_COUNTERS_AREA_ADDR + (counter_id * NV_COUNTER_SIZE);
+
+    err = FLASH_DEV_NAME.ReadData(flash_addr, val, NV_COUNTER_SIZE);
+    if (err != ARM_DRIVER_OK) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    return TFM_PLAT_ERR_SUCCESS;
+}
+
+enum tfm_plat_err_t tfm_plat_increment_nv_counter(
+                                               enum tfm_nv_counter_t counter_id)
+{
+    int32_t  err;
+    uint32_t *p_nv_counter;
+    uint8_t  sector_data[TFM_NV_COUNTERS_SECTOR_SIZE];
+
+    /* Read the whole sector to be able to erase and write later in the flash */
+    err = FLASH_DEV_NAME.ReadData(TFM_NV_COUNTERS_SECTOR_ADDR, sector_data,
+                                  TFM_NV_COUNTERS_SECTOR_SIZE);
+    if (err != ARM_DRIVER_OK) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    /* Set the pointer to nv counter position */
+    p_nv_counter = (uint32_t *)(sector_data + NV_COUNTERS_AREA_OFFSET +
+                                (counter_id * NV_COUNTER_SIZE));
+
+    if (*p_nv_counter == UINT32_MAX) {
+        return TFM_PLAT_ERR_MAX_VALUE;
+    }
+
+    /* Next value is the current value + 1 */
+    *p_nv_counter = *p_nv_counter + 1;
+
+    /* Erase sector before write in it */
+    err = FLASH_DEV_NAME.EraseSector(TFM_NV_COUNTERS_SECTOR_ADDR);
+    if (err != ARM_DRIVER_OK) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    /* Write in flash the in-memory block content after modification */
+    err = FLASH_DEV_NAME.ProgramData(TFM_NV_COUNTERS_SECTOR_ADDR, sector_data,
+                                     TFM_NV_COUNTERS_SECTOR_SIZE);
+    if (err != ARM_DRIVER_OK) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    return TFM_PLAT_ERR_SUCCESS;
+}
diff --git a/platform/ext/target/mps2/an521/gcc/mps2_an521_s.ld b/platform/ext/target/mps2/an521/gcc/mps2_an521_s.ld
index 5012c70..d3cfc21 100644
--- a/platform/ext/target/mps2/an521/gcc/mps2_an521_s.ld
+++ b/platform/ext/target/mps2/an521/gcc/mps2_an521_s.ld
@@ -170,6 +170,8 @@
         *tfm_unpriv_api.o(.rodata*)
         *dummy_crypto_keys.o(.text*)
         *dummy_crypto_keys.o(.rodata*)
+        *dummy_nv_counters.o(.text*)
+        *dummy_nv_counters.o(.rodata*)
         *platform_retarget_dev.o(.text*)
         *platform_retarget_dev.o(.rodata*)
         *(SFN)
@@ -331,6 +333,7 @@
     {
         */tfm_unpriv_api.o(.data*)
         */dummy_crypto_keys.o(.data*)
+        */dummy_nv_counters.o(.data*)
         */platform_retarget_dev.o(.data*)
         . = ALIGN(32);
     } > RAM AT> FLASH
@@ -342,9 +345,11 @@
         */tfm_unpriv_api.o(.bss*)
         */platform_retarget_dev.o(.bss*)
         */dummy_crypto_keys.o(.bss*)
+        */dummy_nv_counters.o(.bss*)
         */tfm_unpriv_api.o(COMMON)
         */platform_retarget_dev.o(COMMON)
         */dummy_crypto_keys.o(COMMON)
+        */dummy_nv_counters.o(COMMON)
         . = ALIGN(32);
     } > RAM AT> FLASH
     Image$$TFM_UNPRIV_RO_DATA$$ZI$$Base = ADDR(.TFM_UNPRIV_RO_BSS);
diff --git a/platform/ext/target/mps2/an521/gcc/mps2_an521_s.ld.template b/platform/ext/target/mps2/an521/gcc/mps2_an521_s.ld.template
index f14457d..bb3db93 100644
--- a/platform/ext/target/mps2/an521/gcc/mps2_an521_s.ld.template
+++ b/platform/ext/target/mps2/an521/gcc/mps2_an521_s.ld.template
@@ -135,6 +135,8 @@
         *tfm_unpriv_api.o(.rodata*)
         *dummy_crypto_keys.o(.text*)
         *dummy_crypto_keys.o(.rodata*)
+        *dummy_nv_counters.o(.text*)
+        *dummy_nv_counters.o(.rodata*)
         *platform_retarget_dev.o(.text*)
         *platform_retarget_dev.o(.rodata*)
         *(SFN)
@@ -233,6 +235,7 @@
     {
         */tfm_unpriv_api.o(.data*)
         */dummy_crypto_keys.o(.data*)
+        */dummy_nv_counters.o(.data*)
         */platform_retarget_dev.o(.data*)
         . = ALIGN(32);
     } > RAM AT> FLASH
@@ -244,9 +247,11 @@
         */tfm_unpriv_api.o(.bss*)
         */platform_retarget_dev.o(.bss*)
         */dummy_crypto_keys.o(.bss*)
+        */dummy_nv_counters.o(.bss*)
         */tfm_unpriv_api.o(COMMON)
         */platform_retarget_dev.o(COMMON)
         */dummy_crypto_keys.o(COMMON)
+        */dummy_nv_counters.o(COMMON)
         . = ALIGN(32);
     } > RAM AT> FLASH
     Image$$TFM_UNPRIV_RO_DATA$$ZI$$Base = ADDR(.TFM_UNPRIV_RO_BSS);
diff --git a/platform/ext/target/mps2/an521/partition/flash_layout.h b/platform/ext/target/mps2/an521/partition/flash_layout.h
index cf0d1ab..c77f012 100644
--- a/platform/ext/target/mps2/an521/partition/flash_layout.h
+++ b/platform/ext/target/mps2/an521/partition/flash_layout.h
@@ -27,8 +27,9 @@
  *    0x0018_0000 Secure     image secondary
  *    0x0020_0000 Non-secure image secondary
  * 0x0028_0000 Scratch area(1 MB)
- * 0x0038_0000 Secure Storage Area (0.02 MB)
- * 0x0038_5000 Unused(0.482 MB)
+ * 0x0038_0000 Secure Storage Area(0.02 MB)
+ * 0x0038_5000 NV counters area(16 Bytes)
+ * 0x0038_5010 Unused(0.491 MB)
  *
  * Flash layout on MPS2 AN521, if BL2 not defined:
  * 0x0000_0000 Secure     image
@@ -83,6 +84,9 @@
 #define FLASH_SST_AREA_OFFSET           (0x380000)
 #define FLASH_SST_AREA_SIZE             (0x5000)   /* 20 KB */
 
+#define FLASH_NV_COUNTERS_AREA_OFFSET   (0x385000)
+#define FLASH_NV_COUNTERS_AREA_SIZE     (0x10)     /* 16 Bytes */
+
 /* Offset and size definition in flash area, used by assemble.py */
 #define SECURE_IMAGE_OFFSET             0x0
 #define SECURE_IMAGE_MAX_SIZE           0x80000
@@ -106,4 +110,10 @@
 /* Specifies the smallest flash programmable unit in bytes */
 #define SST_FLASH_PROGRAM_UNIT  0x1
 
+/* NV Counters definitions */
+#define TFM_NV_COUNTERS_AREA_ADDR    FLASH_NV_COUNTERS_AREA_OFFSET
+#define TFM_NV_COUNTERS_AREA_SIZE    FLASH_NV_COUNTERS_AREA_SIZE
+#define TFM_NV_COUNTERS_SECTOR_ADDR  FLASH_NV_COUNTERS_AREA_OFFSET
+#define TFM_NV_COUNTERS_SECTOR_SIZE  FLASH_AREA_IMAGE_SECTOR_SIZE
+
 #endif /* __FLASH_LAYOUT_H__ */
diff --git a/platform/ext/target/musca_a/Device/Source/armclang/musca_s.sct b/platform/ext/target/musca_a/Device/Source/armclang/musca_s.sct
index abcf4e9..d9d278d 100755
--- a/platform/ext/target/musca_a/Device/Source/armclang/musca_s.sct
+++ b/platform/ext/target/musca_a/Device/Source/armclang/musca_s.sct
@@ -44,6 +44,7 @@
     TFM_UNPRIV_CODE +0 ALIGN 32 {
         tfm_unpriv_api.o (+RO)
         dummy_crypto_keys.o (+RO)
+        dummy_nv_counters.o (+RO)
         platform_retarget_dev.o (+RO)
         *(SFN)
         *armlib*
@@ -92,6 +93,7 @@
     TFM_UNPRIV_RO_DATA +0 ALIGN 32 {
         tfm_unpriv_api.o (+RW +ZI)
         dummy_crypto_keys.o (+RW +ZI)
+        dummy_nv_counters.o (+RW +ZI)
         platform_retarget_dev.o (+RW +ZI)
     }
 
diff --git a/platform/ext/target/musca_a/Device/Source/gcc/musca_s.ld b/platform/ext/target/musca_a/Device/Source/gcc/musca_s.ld
index 32d21a1..04ba26f 100644
--- a/platform/ext/target/musca_a/Device/Source/gcc/musca_s.ld
+++ b/platform/ext/target/musca_a/Device/Source/gcc/musca_s.ld
@@ -170,6 +170,8 @@
         *tfm_unpriv_api.o(.rodata*)
         *dummy_crypto_keys.o(.text*)
         *dummy_crypto_keys.o(.rodata*)
+	*dummy_nv_counters.o(.text*)
+	*dummy_nv_counters.o(.rodata*)
         *platform_retarget_dev.o(.text*)
         *platform_retarget_dev.o(.rodata*)
         *(SFN)
@@ -331,6 +333,7 @@
     {
         */tfm_unpriv_api.o(.data*)
         */dummy_crypto_keys.o(.data*)
+        */dummy_nv_counters.o(.data*)
         */platform_retarget_dev.o(.data*)
         . = ALIGN(32);
     } > RAM AT> FLASH
@@ -342,9 +345,11 @@
         */tfm_unpriv_api.o(.bss*)
         */platform_retarget_dev.o(.bss*)
         */dummy_crypto_keys.o(.bss*)
+        */dummy_nv_counters.o(.bss*)
         */tfm_unpriv_api.o(COMMON)
         */platform_retarget_dev.o(COMMON)
         */dummy_crypto_keys.o(COMMON)
+        */dummy_nv_counters.o(COMMON)
         . = ALIGN(32);
     } > RAM AT> FLASH
     Image$$TFM_UNPRIV_RO_DATA$$ZI$$Base = ADDR(.TFM_UNPRIV_RO_BSS);
diff --git a/platform/ext/target/musca_a/Device/Source/gcc/musca_s.ld.template b/platform/ext/target/musca_a/Device/Source/gcc/musca_s.ld.template
index 4634c8c..4189b56 100644
--- a/platform/ext/target/musca_a/Device/Source/gcc/musca_s.ld.template
+++ b/platform/ext/target/musca_a/Device/Source/gcc/musca_s.ld.template
@@ -135,6 +135,8 @@
         *tfm_unpriv_api.o(.rodata*)
         *dummy_crypto_keys.o(.text*)
         *dummy_crypto_keys.o(.rodata*)
+	*dummy_nv_counters.o(.text*)
+	*dummy_nv_counters.o(.rodata*)
         *platform_retarget_dev.o(.text*)
         *platform_retarget_dev.o(.rodata*)
         *(SFN)
@@ -233,6 +235,7 @@
     {
         */tfm_unpriv_api.o(.data*)
         */dummy_crypto_keys.o(.data*)
+        */dummy_nv_counters.o(.data*)
         */platform_retarget_dev.o(.data*)
         . = ALIGN(32);
     } > RAM AT> FLASH
@@ -244,9 +247,11 @@
         */tfm_unpriv_api.o(.bss*)
         */platform_retarget_dev.o(.bss*)
         */dummy_crypto_keys.o(.bss*)
+        */dummy_nv_counters.o(.bss*)
         */tfm_unpriv_api.o(COMMON)
         */platform_retarget_dev.o(COMMON)
         */dummy_crypto_keys.o(COMMON)
+        */dummy_nv_counters.o(COMMON)
         . = ALIGN(32);
     } > RAM AT> FLASH
     Image$$TFM_UNPRIV_RO_DATA$$ZI$$Base = ADDR(.TFM_UNPRIV_RO_BSS);
diff --git a/platform/ext/target/musca_a/dummy_nv_counters.c b/platform/ext/target/musca_a/dummy_nv_counters.c
new file mode 100644
index 0000000..f2a7801
--- /dev/null
+++ b/platform/ext/target/musca_a/dummy_nv_counters.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/* NOTE: This API should be implemented by platform vendor. For the
+ * security of the secure storage system rollback protection and others, it is
+ * CRITICAL to use a internal (in-die) persistent memory for multiple time
+ * programabe (MTP) non-volatile counters or use a One-time Programmable (OTP)
+ * non-volatile counters solution.
+ *
+ * Musca A1 does not have any available MTP or OTP non-volatile counters, so a
+ * software dummy implementation has been implemented in this case.
+ */
+
+#include "platform/include/tfm_plat_nv_counters.h"
+
+#include <limits.h>
+#include "Driver_Flash.h"
+#include "flash_layout.h"
+
+/* Compilation time checks to be sure the defines are well defined */
+#ifndef TFM_NV_COUNTERS_AREA_ADDR
+#error "TFM_NV_COUNTERS_AREA_ADDR must be defined in flash_layout.h"
+#endif
+
+#ifndef TFM_NV_COUNTERS_AREA_SIZE
+#error "TFM_NV_COUNTERS_AREA_SIZE must be defined in flash_layout.h"
+#endif
+
+#ifndef TFM_NV_COUNTERS_SECTOR_ADDR
+#error "TFM_NV_COUNTERS_SECTOR_ADDR must be defined in flash_layout.h"
+#endif
+
+#ifndef TFM_NV_COUNTERS_SECTOR_SIZE
+#error "TFM_NV_COUNTERS_SECTOR_SIZE must be defined in flash_layout.h"
+#endif
+
+#ifndef FLASH_DEV_NAME
+#error "FLASH_DEV_NAME must be defined in flash_layout.h"
+#endif
+/* End of compilation time checks to be sure the defines are well defined */
+
+#define SECTOR_OFFSET    0
+#define NV_COUNTER_SIZE  sizeof(uint32_t)
+#define INIT_VALUE_SIZE  NV_COUNTER_SIZE
+#define NV_COUNTERS_AREA_OFFSET (TFM_NV_COUNTERS_AREA_ADDR - \
+                                 TFM_NV_COUNTERS_SECTOR_ADDR)
+
+#define NV_COUNTERS_INITIALIZED 0xC0DE0042
+
+/* Import the CMSIS flash device driver */
+extern ARM_DRIVER_FLASH FLASH_DEV_NAME;
+
+enum tfm_plat_err_t tfm_plat_init_nv_counter(void)
+{
+    int32_t  err;
+    uint32_t i;
+    uint32_t nbr_counters = ((TFM_NV_COUNTERS_AREA_SIZE - INIT_VALUE_SIZE)
+                             / NV_COUNTER_SIZE);
+    uint32_t *p_nv_counter;
+    uint8_t sector_data[TFM_NV_COUNTERS_SECTOR_SIZE] = {0};
+
+    /* Read the whole sector to be able to erase and write later in the flash */
+    err = FLASH_DEV_NAME.ReadData(TFM_NV_COUNTERS_SECTOR_ADDR, sector_data,
+                                  TFM_NV_COUNTERS_SECTOR_SIZE);
+    if (err != ARM_DRIVER_OK) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    /* Set the pointer to nv counters position */
+    p_nv_counter = (uint32_t *)(sector_data + NV_COUNTERS_AREA_OFFSET);
+
+    if (p_nv_counter[nbr_counters] == NV_COUNTERS_INITIALIZED) {
+        return TFM_PLAT_ERR_SUCCESS;
+    }
+
+    /* Add watermark, at the end of the NV counters area, to indicate that NV
+     * counters have been initialized.
+     */
+    p_nv_counter[nbr_counters] = NV_COUNTERS_INITIALIZED;
+
+    /* Initialize all counters to 0 */
+    for (i = 0; i < nbr_counters; i++) {
+        p_nv_counter[i] = 0;
+    }
+
+    /* Erase sector before write in it */
+    err = FLASH_DEV_NAME.EraseSector(TFM_NV_COUNTERS_SECTOR_ADDR);
+    if (err != ARM_DRIVER_OK) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    /* Write in flash the in-memory block content after modification */
+    err = FLASH_DEV_NAME.ProgramData(TFM_NV_COUNTERS_SECTOR_ADDR, sector_data,
+                                     TFM_NV_COUNTERS_SECTOR_SIZE);
+    if (err != ARM_DRIVER_OK) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    return TFM_PLAT_ERR_SUCCESS;
+}
+
+enum tfm_plat_err_t tfm_plat_read_nv_counter(enum tfm_nv_counter_t counter_id,
+                                             uint32_t size, uint8_t *val)
+{
+    int32_t  err;
+    uint32_t flash_addr;
+
+    if (size != NV_COUNTER_SIZE) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    flash_addr = TFM_NV_COUNTERS_AREA_ADDR + (counter_id * NV_COUNTER_SIZE);
+
+    err = FLASH_DEV_NAME.ReadData(flash_addr, val, NV_COUNTER_SIZE);
+    if (err != ARM_DRIVER_OK) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    return TFM_PLAT_ERR_SUCCESS;
+}
+
+enum tfm_plat_err_t tfm_plat_increment_nv_counter(
+                                               enum tfm_nv_counter_t counter_id)
+{
+    int32_t  err;
+    uint32_t *p_nv_counter;
+    uint8_t  sector_data[TFM_NV_COUNTERS_SECTOR_SIZE];
+
+    /* Read the whole sector to be able to erase and write later in the flash */
+    err = FLASH_DEV_NAME.ReadData(TFM_NV_COUNTERS_SECTOR_ADDR, sector_data,
+                                  TFM_NV_COUNTERS_SECTOR_SIZE);
+    if (err != ARM_DRIVER_OK) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    /* Set the pointer to nv counter position */
+    p_nv_counter = (uint32_t *)(sector_data + NV_COUNTERS_AREA_OFFSET +
+                                (counter_id * NV_COUNTER_SIZE));
+
+    if (*p_nv_counter == UINT32_MAX) {
+        return TFM_PLAT_ERR_MAX_VALUE;
+    }
+
+    /* Next value is the current value + 1 */
+    *p_nv_counter = *p_nv_counter + 1;
+
+    /* Erase sector before write in it */
+    err = FLASH_DEV_NAME.EraseSector(TFM_NV_COUNTERS_SECTOR_ADDR);
+    if (err != ARM_DRIVER_OK) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    /* Write in flash the in-memory block content after modification */
+    err = FLASH_DEV_NAME.ProgramData(TFM_NV_COUNTERS_SECTOR_ADDR, sector_data,
+                                     TFM_NV_COUNTERS_SECTOR_SIZE);
+    if (err != ARM_DRIVER_OK) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    return TFM_PLAT_ERR_SUCCESS;
+}
diff --git a/platform/ext/target/musca_a/partition/flash_layout.h b/platform/ext/target/musca_a/partition/flash_layout.h
index 2cd435b..3f1d1ce 100755
--- a/platform/ext/target/musca_a/partition/flash_layout.h
+++ b/platform/ext/target/musca_a/partition/flash_layout.h
@@ -25,8 +25,9 @@
  * 0x0032_0000 Flash_area_image_1(1 MB)
  *    0x0032_0000 Secure     image secondary
  *    0x003A_0000 Non-secure image secondary
- * 0x0042_0000 Secure Storage Area (0.02 MB)
- * 0x0042_5000 Unused
+ * 0x0042_0000 Secure Storage Area(0.02 MB)
+ * 0x0042_5000 NV counters area(16 Bytes)
+ * 0x0042_5010 Unused
  */
 
 /* Code SRAM layout on Musca (with BL2, which is mandatory) after the newest
@@ -89,6 +90,10 @@
                                          FLASH_AREA_IMAGE_SCRATCH_SIZE)
 #define FLASH_SST_AREA_SIZE             (0x5000)   /* 20 KB */
 
+#define FLASH_NV_COUNTERS_AREA_OFFSET   (FLASH_SST_AREA_OFFSET + \
+                                         FLASH_SST_AREA_SIZE)
+#define FLASH_NV_COUNTERS_AREA_SIZE     (0x10)     /* 16 Bytes */
+
 /* Offset and size definition in flash area, used by assemble.py */
 #define SECURE_IMAGE_OFFSET             0x0
 #define SECURE_IMAGE_MAX_SIZE           0x80000
@@ -126,4 +131,10 @@
 /* Specifies the smallest flash programmable unit in bytes */
 #define SST_FLASH_PROGRAM_UNIT  0x1
 
+/* NV Counters definitions */
+#define TFM_NV_COUNTERS_AREA_ADDR    FLASH_NV_COUNTERS_AREA_OFFSET
+#define TFM_NV_COUNTERS_AREA_SIZE    FLASH_NV_COUNTERS_AREA_SIZE
+#define TFM_NV_COUNTERS_SECTOR_ADDR  FLASH_NV_COUNTERS_AREA_OFFSET
+#define TFM_NV_COUNTERS_SECTOR_SIZE  FLASH_AREA_IMAGE_SECTOR_SIZE
+
 #endif /* __FLASH_LAYOUT_H__ */