blob: f1fb28c7ce62bf2a16f54ea2da11208ecbf5a3e7 [file] [log] [blame]
Jamie Fox7a4170d2018-08-15 14:13:42 +01001/*
Mingyang Sunc9bdcd72020-06-04 11:44:49 +08002 * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
Jamie Fox7a4170d2018-08-15 14:13:42 +01003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
David Vincze2ff8c6a2019-05-21 11:53:00 +02008/* NOTE: This API should be implemented by platform vendor. For the security of
9 * the secure storage system's and the bootloader's rollback protection etc. it
10 * is CRITICAL to use a internal (in-die) persistent memory for multiple time
11 * programmable (MTP) non-volatile counters or use a One-time Programmable (OTP)
Jamie Fox7a4170d2018-08-15 14:13:42 +010012 * non-volatile counters solution.
David Vincze2ff8c6a2019-05-21 11:53:00 +020013 *
Jamie Foxa504c2c2019-08-29 17:39:09 +010014 * This dummy implementation assumes that the NV counters are the only data in
15 * the flash sector. To use it, one flash sector should be allocated exclusively
16 * for the NV counters.
17 *
David Vincze2ff8c6a2019-05-21 11:53:00 +020018 * The current software dummy implementation is not resistant to asynchronous
19 * power failures and should not be used in production code. It is exclusively
20 * for testing purposes.
Jamie Fox7a4170d2018-08-15 14:13:42 +010021 */
22
Mingyang Sunc9bdcd72020-06-04 11:44:49 +080023#include "tfm_plat_nv_counters.h"
Jamie Fox7a4170d2018-08-15 14:13:42 +010024
25#include <limits.h>
26#include "Driver_Flash.h"
27#include "flash_layout.h"
28
29/* Compilation time checks to be sure the defines are well defined */
30#ifndef TFM_NV_COUNTERS_AREA_ADDR
31#error "TFM_NV_COUNTERS_AREA_ADDR must be defined in flash_layout.h"
32#endif
33
34#ifndef TFM_NV_COUNTERS_AREA_SIZE
35#error "TFM_NV_COUNTERS_AREA_SIZE must be defined in flash_layout.h"
36#endif
37
38#ifndef TFM_NV_COUNTERS_SECTOR_ADDR
39#error "TFM_NV_COUNTERS_SECTOR_ADDR must be defined in flash_layout.h"
40#endif
41
42#ifndef TFM_NV_COUNTERS_SECTOR_SIZE
43#error "TFM_NV_COUNTERS_SECTOR_SIZE must be defined in flash_layout.h"
44#endif
45
46#ifndef FLASH_DEV_NAME
47#error "FLASH_DEV_NAME must be defined in flash_layout.h"
48#endif
49/* End of compilation time checks to be sure the defines are well defined */
50
Jamie Fox7a4170d2018-08-15 14:13:42 +010051#define NV_COUNTER_SIZE sizeof(uint32_t)
52#define INIT_VALUE_SIZE NV_COUNTER_SIZE
Jamie Foxa504c2c2019-08-29 17:39:09 +010053#define NUM_NV_COUNTERS ((TFM_NV_COUNTERS_AREA_SIZE - INIT_VALUE_SIZE) \
54 / NV_COUNTER_SIZE)
Jamie Fox7a4170d2018-08-15 14:13:42 +010055
Jamie Foxa504c2c2019-08-29 17:39:09 +010056#define NV_COUNTERS_INITIALIZED 0xC0DE0042U
57
58/**
59 * \brief Struct representing the NV counter data in flash.
60 */
61struct nv_counters_t {
62 uint32_t counters[NUM_NV_COUNTERS]; /**< Array of NV counters */
63 uint32_t init_value; /**< Watermark to indicate if the NV counters have been
64 * initialised
65 */
66};
Jamie Fox7a4170d2018-08-15 14:13:42 +010067
68/* Import the CMSIS flash device driver */
69extern ARM_DRIVER_FLASH FLASH_DEV_NAME;
70
71enum tfm_plat_err_t tfm_plat_init_nv_counter(void)
72{
Jamie Foxa504c2c2019-08-29 17:39:09 +010073 int32_t err;
Jamie Fox7a4170d2018-08-15 14:13:42 +010074 uint32_t i;
Jamie Foxa504c2c2019-08-29 17:39:09 +010075 struct nv_counters_t nv_counters = {{0}};
Jamie Fox7a4170d2018-08-15 14:13:42 +010076
Jamie Fox43e80d92019-06-03 17:41:17 +010077 err = FLASH_DEV_NAME.Initialize(NULL);
78 if (err != ARM_DRIVER_OK) {
79 return TFM_PLAT_ERR_SYSTEM_ERR;
80 }
81
Jamie Foxa504c2c2019-08-29 17:39:09 +010082 /* Read the NV counter area to be able to erase the sector and write later
83 * in the flash.
84 */
85 err = FLASH_DEV_NAME.ReadData(TFM_NV_COUNTERS_AREA_ADDR, &nv_counters,
86 TFM_NV_COUNTERS_AREA_SIZE);
Jamie Fox7a4170d2018-08-15 14:13:42 +010087 if (err != ARM_DRIVER_OK) {
88 return TFM_PLAT_ERR_SYSTEM_ERR;
89 }
90
Jamie Foxa504c2c2019-08-29 17:39:09 +010091 if (nv_counters.init_value == NV_COUNTERS_INITIALIZED) {
Jamie Fox7a4170d2018-08-15 14:13:42 +010092 return TFM_PLAT_ERR_SUCCESS;
93 }
94
95 /* Add watermark, at the end of the NV counters area, to indicate that NV
96 * counters have been initialized.
97 */
Jamie Foxa504c2c2019-08-29 17:39:09 +010098 nv_counters.init_value = NV_COUNTERS_INITIALIZED;
Jamie Fox7a4170d2018-08-15 14:13:42 +010099
100 /* Initialize all counters to 0 */
Jamie Foxa504c2c2019-08-29 17:39:09 +0100101 for (i = 0; i < NUM_NV_COUNTERS; i++) {
102 nv_counters.counters[i] = 0;
Jamie Fox7a4170d2018-08-15 14:13:42 +0100103 }
104
105 /* Erase sector before write in it */
106 err = FLASH_DEV_NAME.EraseSector(TFM_NV_COUNTERS_SECTOR_ADDR);
107 if (err != ARM_DRIVER_OK) {
108 return TFM_PLAT_ERR_SYSTEM_ERR;
109 }
110
Jamie Foxa504c2c2019-08-29 17:39:09 +0100111 /* Write in flash the in-memory NV counter content after modification */
112 err = FLASH_DEV_NAME.ProgramData(TFM_NV_COUNTERS_AREA_ADDR, &nv_counters,
113 TFM_NV_COUNTERS_AREA_SIZE);
Jamie Fox7a4170d2018-08-15 14:13:42 +0100114 if (err != ARM_DRIVER_OK) {
115 return TFM_PLAT_ERR_SYSTEM_ERR;
116 }
117
118 return TFM_PLAT_ERR_SUCCESS;
119}
120
121enum tfm_plat_err_t tfm_plat_read_nv_counter(enum tfm_nv_counter_t counter_id,
122 uint32_t size, uint8_t *val)
123{
124 int32_t err;
125 uint32_t flash_addr;
126
127 if (size != NV_COUNTER_SIZE) {
128 return TFM_PLAT_ERR_SYSTEM_ERR;
129 }
130
131 flash_addr = TFM_NV_COUNTERS_AREA_ADDR + (counter_id * NV_COUNTER_SIZE);
132
133 err = FLASH_DEV_NAME.ReadData(flash_addr, val, NV_COUNTER_SIZE);
134 if (err != ARM_DRIVER_OK) {
135 return TFM_PLAT_ERR_SYSTEM_ERR;
136 }
137
138 return TFM_PLAT_ERR_SUCCESS;
139}
140
David Vincze2ff8c6a2019-05-21 11:53:00 +0200141enum tfm_plat_err_t tfm_plat_set_nv_counter(enum tfm_nv_counter_t counter_id,
142 uint32_t value)
Jamie Fox7a4170d2018-08-15 14:13:42 +0100143{
Jamie Foxa504c2c2019-08-29 17:39:09 +0100144 int32_t err;
145 struct nv_counters_t nv_counters = {{0}};
Jamie Fox7a4170d2018-08-15 14:13:42 +0100146
Jamie Foxa504c2c2019-08-29 17:39:09 +0100147 /* Read the NV counter area to be able to erase the sector and write later
148 * in the flash.
149 */
150 err = FLASH_DEV_NAME.ReadData(TFM_NV_COUNTERS_AREA_ADDR, &nv_counters,
151 TFM_NV_COUNTERS_AREA_SIZE);
Jamie Fox7a4170d2018-08-15 14:13:42 +0100152 if (err != ARM_DRIVER_OK) {
153 return TFM_PLAT_ERR_SYSTEM_ERR;
154 }
155
Jamie Foxa504c2c2019-08-29 17:39:09 +0100156 if (value != nv_counters.counters[counter_id]) {
Jamie Fox7a4170d2018-08-15 14:13:42 +0100157
Jamie Foxa504c2c2019-08-29 17:39:09 +0100158 if (value > nv_counters.counters[counter_id]) {
159 nv_counters.counters[counter_id] = value;
David Vincze2ff8c6a2019-05-21 11:53:00 +0200160 } else {
161 return TFM_PLAT_ERR_INVALID_INPUT;
162 }
Jamie Fox7a4170d2018-08-15 14:13:42 +0100163
David Vincze2ff8c6a2019-05-21 11:53:00 +0200164 /* Erase sector before write in it */
165 err = FLASH_DEV_NAME.EraseSector(TFM_NV_COUNTERS_SECTOR_ADDR);
166 if (err != ARM_DRIVER_OK) {
167 return TFM_PLAT_ERR_SYSTEM_ERR;
168 }
Jamie Fox7a4170d2018-08-15 14:13:42 +0100169
Jamie Foxa504c2c2019-08-29 17:39:09 +0100170 /* Write in flash the in-memory NV counter content after modification */
171 err = FLASH_DEV_NAME.ProgramData(TFM_NV_COUNTERS_AREA_ADDR,
172 &nv_counters,
173 TFM_NV_COUNTERS_AREA_SIZE);
David Vincze2ff8c6a2019-05-21 11:53:00 +0200174 if (err != ARM_DRIVER_OK) {
175 return TFM_PLAT_ERR_SYSTEM_ERR;
176 }
Jamie Fox7a4170d2018-08-15 14:13:42 +0100177 }
178
179 return TFM_PLAT_ERR_SUCCESS;
180}
David Vincze2ff8c6a2019-05-21 11:53:00 +0200181
182enum tfm_plat_err_t tfm_plat_increment_nv_counter(
183 enum tfm_nv_counter_t counter_id)
184{
185 uint32_t security_cnt;
186 enum tfm_plat_err_t err;
187
188 err = tfm_plat_read_nv_counter(counter_id,
189 sizeof(security_cnt),
190 (uint8_t *)&security_cnt);
191 if (err != TFM_PLAT_ERR_SUCCESS) {
192 return err;
193 }
194
195 if (security_cnt == UINT32_MAX) {
196 return TFM_PLAT_ERR_MAX_VALUE;
197 }
198
199 return tfm_plat_set_nv_counter(counter_id, security_cnt + 1u);
200}