blob: 2764644eb1bfeaea9474fc59f924ec95d31d1d5d [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
Kevin Pengc6d74502020-03-04 16:55:37 +08009 * the protected storage system's and the bootloader's rollback protection etc.
10 * it is CRITICAL to use a internal (in-die) persistent memory for multiple time
David Vincze2ff8c6a2019-05-21 11:53:00 +020011 * 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
Mark Horvath90605b52020-09-23 11:27:55 +020046#ifndef NV_COUNTERS_FLASH_DEV_NAME
47 #ifndef FLASH_DEV_NAME
48 #error "NV_COUNTERS_FLASH_DEV_NAME or FLASH_DEV_NAME must be defined in flash_layout.h"
49 #else
50 #define NV_COUNTERS_FLASH_DEV_NAME FLASH_DEV_NAME
51 #endif
Jamie Fox7a4170d2018-08-15 14:13:42 +010052#endif
53/* End of compilation time checks to be sure the defines are well defined */
54
Jamie Fox7a4170d2018-08-15 14:13:42 +010055#define NV_COUNTER_SIZE sizeof(uint32_t)
56#define INIT_VALUE_SIZE NV_COUNTER_SIZE
Jamie Foxa504c2c2019-08-29 17:39:09 +010057#define NUM_NV_COUNTERS ((TFM_NV_COUNTERS_AREA_SIZE - INIT_VALUE_SIZE) \
58 / NV_COUNTER_SIZE)
Jamie Fox7a4170d2018-08-15 14:13:42 +010059
Jamie Foxa504c2c2019-08-29 17:39:09 +010060#define NV_COUNTERS_INITIALIZED 0xC0DE0042U
61
62/**
63 * \brief Struct representing the NV counter data in flash.
64 */
65struct nv_counters_t {
66 uint32_t counters[NUM_NV_COUNTERS]; /**< Array of NV counters */
67 uint32_t init_value; /**< Watermark to indicate if the NV counters have been
68 * initialised
69 */
70};
Jamie Fox7a4170d2018-08-15 14:13:42 +010071
72/* Import the CMSIS flash device driver */
Mark Horvath90605b52020-09-23 11:27:55 +020073extern ARM_DRIVER_FLASH NV_COUNTERS_FLASH_DEV_NAME;
Jamie Fox7a4170d2018-08-15 14:13:42 +010074
75enum tfm_plat_err_t tfm_plat_init_nv_counter(void)
76{
Jamie Foxa504c2c2019-08-29 17:39:09 +010077 int32_t err;
Jamie Fox7a4170d2018-08-15 14:13:42 +010078 uint32_t i;
Jamie Foxa504c2c2019-08-29 17:39:09 +010079 struct nv_counters_t nv_counters = {{0}};
Jamie Fox7a4170d2018-08-15 14:13:42 +010080
Mark Horvath90605b52020-09-23 11:27:55 +020081 err = NV_COUNTERS_FLASH_DEV_NAME.Initialize(NULL);
Jamie Fox43e80d92019-06-03 17:41:17 +010082 if (err != ARM_DRIVER_OK) {
83 return TFM_PLAT_ERR_SYSTEM_ERR;
84 }
85
Jamie Foxa504c2c2019-08-29 17:39:09 +010086 /* Read the NV counter area to be able to erase the sector and write later
87 * in the flash.
88 */
Mark Horvath90605b52020-09-23 11:27:55 +020089 err = NV_COUNTERS_FLASH_DEV_NAME.ReadData(TFM_NV_COUNTERS_AREA_ADDR,
90 &nv_counters,
91 TFM_NV_COUNTERS_AREA_SIZE);
Jamie Fox7a4170d2018-08-15 14:13:42 +010092 if (err != ARM_DRIVER_OK) {
93 return TFM_PLAT_ERR_SYSTEM_ERR;
94 }
95
Jamie Foxa504c2c2019-08-29 17:39:09 +010096 if (nv_counters.init_value == NV_COUNTERS_INITIALIZED) {
Jamie Fox7a4170d2018-08-15 14:13:42 +010097 return TFM_PLAT_ERR_SUCCESS;
98 }
99
100 /* Add watermark, at the end of the NV counters area, to indicate that NV
101 * counters have been initialized.
102 */
Jamie Foxa504c2c2019-08-29 17:39:09 +0100103 nv_counters.init_value = NV_COUNTERS_INITIALIZED;
Jamie Fox7a4170d2018-08-15 14:13:42 +0100104
105 /* Initialize all counters to 0 */
Jamie Foxa504c2c2019-08-29 17:39:09 +0100106 for (i = 0; i < NUM_NV_COUNTERS; i++) {
107 nv_counters.counters[i] = 0;
Jamie Fox7a4170d2018-08-15 14:13:42 +0100108 }
109
110 /* Erase sector before write in it */
Mark Horvath90605b52020-09-23 11:27:55 +0200111 err = NV_COUNTERS_FLASH_DEV_NAME.EraseSector(TFM_NV_COUNTERS_SECTOR_ADDR);
Jamie Fox7a4170d2018-08-15 14:13:42 +0100112 if (err != ARM_DRIVER_OK) {
113 return TFM_PLAT_ERR_SYSTEM_ERR;
114 }
115
Jamie Foxa504c2c2019-08-29 17:39:09 +0100116 /* Write in flash the in-memory NV counter content after modification */
Mark Horvath90605b52020-09-23 11:27:55 +0200117 err = NV_COUNTERS_FLASH_DEV_NAME.ProgramData(TFM_NV_COUNTERS_AREA_ADDR,
118 &nv_counters,
119 TFM_NV_COUNTERS_AREA_SIZE);
Jamie Fox7a4170d2018-08-15 14:13:42 +0100120 if (err != ARM_DRIVER_OK) {
121 return TFM_PLAT_ERR_SYSTEM_ERR;
122 }
123
124 return TFM_PLAT_ERR_SUCCESS;
125}
126
127enum tfm_plat_err_t tfm_plat_read_nv_counter(enum tfm_nv_counter_t counter_id,
128 uint32_t size, uint8_t *val)
129{
130 int32_t err;
131 uint32_t flash_addr;
132
133 if (size != NV_COUNTER_SIZE) {
134 return TFM_PLAT_ERR_SYSTEM_ERR;
135 }
136
137 flash_addr = TFM_NV_COUNTERS_AREA_ADDR + (counter_id * NV_COUNTER_SIZE);
138
Mark Horvath90605b52020-09-23 11:27:55 +0200139 err = NV_COUNTERS_FLASH_DEV_NAME.ReadData(flash_addr, val, NV_COUNTER_SIZE);
Jamie Fox7a4170d2018-08-15 14:13:42 +0100140 if (err != ARM_DRIVER_OK) {
141 return TFM_PLAT_ERR_SYSTEM_ERR;
142 }
143
144 return TFM_PLAT_ERR_SUCCESS;
145}
146
David Vincze2ff8c6a2019-05-21 11:53:00 +0200147enum tfm_plat_err_t tfm_plat_set_nv_counter(enum tfm_nv_counter_t counter_id,
148 uint32_t value)
Jamie Fox7a4170d2018-08-15 14:13:42 +0100149{
Jamie Foxa504c2c2019-08-29 17:39:09 +0100150 int32_t err;
151 struct nv_counters_t nv_counters = {{0}};
Jamie Fox7a4170d2018-08-15 14:13:42 +0100152
Jamie Foxa504c2c2019-08-29 17:39:09 +0100153 /* Read the NV counter area to be able to erase the sector and write later
154 * in the flash.
155 */
Mark Horvath90605b52020-09-23 11:27:55 +0200156 err = NV_COUNTERS_FLASH_DEV_NAME.ReadData(TFM_NV_COUNTERS_AREA_ADDR,
157 &nv_counters,
158 TFM_NV_COUNTERS_AREA_SIZE);
Jamie Fox7a4170d2018-08-15 14:13:42 +0100159 if (err != ARM_DRIVER_OK) {
160 return TFM_PLAT_ERR_SYSTEM_ERR;
161 }
162
Jamie Foxa504c2c2019-08-29 17:39:09 +0100163 if (value != nv_counters.counters[counter_id]) {
Jamie Fox7a4170d2018-08-15 14:13:42 +0100164
Jamie Foxa504c2c2019-08-29 17:39:09 +0100165 if (value > nv_counters.counters[counter_id]) {
166 nv_counters.counters[counter_id] = value;
David Vincze2ff8c6a2019-05-21 11:53:00 +0200167 } else {
168 return TFM_PLAT_ERR_INVALID_INPUT;
169 }
Jamie Fox7a4170d2018-08-15 14:13:42 +0100170
David Vincze2ff8c6a2019-05-21 11:53:00 +0200171 /* Erase sector before write in it */
Mark Horvath90605b52020-09-23 11:27:55 +0200172 err = NV_COUNTERS_FLASH_DEV_NAME.EraseSector(
173 TFM_NV_COUNTERS_SECTOR_ADDR);
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
Jamie Foxa504c2c2019-08-29 17:39:09 +0100178 /* Write in flash the in-memory NV counter content after modification */
Mark Horvath90605b52020-09-23 11:27:55 +0200179 err = NV_COUNTERS_FLASH_DEV_NAME.ProgramData(TFM_NV_COUNTERS_AREA_ADDR,
180 &nv_counters,
181 TFM_NV_COUNTERS_AREA_SIZE);
David Vincze2ff8c6a2019-05-21 11:53:00 +0200182 if (err != ARM_DRIVER_OK) {
183 return TFM_PLAT_ERR_SYSTEM_ERR;
184 }
Jamie Fox7a4170d2018-08-15 14:13:42 +0100185 }
186
187 return TFM_PLAT_ERR_SUCCESS;
188}
David Vincze2ff8c6a2019-05-21 11:53:00 +0200189
190enum tfm_plat_err_t tfm_plat_increment_nv_counter(
191 enum tfm_nv_counter_t counter_id)
192{
193 uint32_t security_cnt;
194 enum tfm_plat_err_t err;
195
196 err = tfm_plat_read_nv_counter(counter_id,
197 sizeof(security_cnt),
198 (uint8_t *)&security_cnt);
199 if (err != TFM_PLAT_ERR_SUCCESS) {
200 return err;
201 }
202
203 if (security_cnt == UINT32_MAX) {
204 return TFM_PLAT_ERR_MAX_VALUE;
205 }
206
207 return tfm_plat_set_nv_counter(counter_id, security_cnt + 1u);
208}