1 /*
2  *  SPDX-License-Identifier: BSD-3-Clause
3  *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
4  *
5  */
6 
7 #include "tfm_plat_nv_counters.h"
8 #include "tfm_plat_otp.h"
9 
10 #if (PS_NS_NV_COUNTER_IN_ITS == 1)
11 #include "psa/internal_trusted_storage.h"
12 #endif
13 
14 #include <limits.h>
15 #include <string.h>
16 
17 #define OTP_COUNTER_MAX_SIZE    64
18 #define NV_COUNTER_SIZE         4
19 #define OTP_COUNTER_MAGIC       0xAEC7
20 #define ITS_NV_COUNTER_UID_BASE 0xFFFFFFFFFFFFA000
21 
tfm_plat_init_nv_counter(void)22 enum tfm_plat_err_t tfm_plat_init_nv_counter(void)
23 {
24     return TFM_PLAT_ERR_SUCCESS;
25 }
26 
read_otp_counter(enum tfm_otp_element_id_t id,uint8_t * val)27 static enum tfm_plat_err_t read_otp_counter(enum tfm_otp_element_id_t id,
28                                             uint8_t *val)
29 {
30     size_t counter_size;
31     enum tfm_plat_err_t err;
32     size_t idx;
33     uint16_t counter_value[OTP_COUNTER_MAX_SIZE / sizeof(uint16_t)] = {0};
34     uint32_t count;
35 
36     err = tfm_plat_otp_get_size(id, &counter_size);
37     if (err != TFM_PLAT_ERR_SUCCESS) {
38         return err;
39     }
40 
41     counter_size = counter_size > OTP_COUNTER_MAX_SIZE ? OTP_COUNTER_MAX_SIZE
42                                                        : counter_size;
43 
44     err = tfm_plat_otp_read(id, counter_size, (uint8_t *)counter_value);
45     if (err != TFM_PLAT_ERR_SUCCESS) {
46         return err;
47     }
48 
49     count = 0;
50     for (idx = 0; idx < counter_size / sizeof(uint16_t); idx++) {
51         if (counter_value[idx] == OTP_COUNTER_MAGIC) {
52             count += 1;
53         } else if (counter_value[idx] == 0) {
54             break;
55         } else {
56             return TFM_PLAT_ERR_SYSTEM_ERR;
57         }
58     }
59 
60     memcpy(val, &count, NV_COUNTER_SIZE);
61 
62     return TFM_PLAT_ERR_SUCCESS;
63 }
64 
65 #if (PS_NS_NV_COUNTER_IN_ITS == 1)
read_its_nv_counter(enum tfm_otp_element_id_t id,uint8_t * val)66 static enum tfm_plat_err_t read_its_nv_counter(enum tfm_otp_element_id_t id,
67                                             uint8_t *val)
68 {
69     psa_storage_uid_t uid = (ITS_NV_COUNTER_UID_BASE + id);
70     psa_status_t status;
71     size_t data_length = 0;
72 
73     status = psa_its_get(uid, 0, NV_COUNTER_SIZE, val, &data_length);
74 
75     if (status == PSA_ERROR_DOES_NOT_EXIST) {
76         memset(val, 0, NV_COUNTER_SIZE);
77     }
78 
79     if (((status == PSA_SUCCESS) && (data_length == NV_COUNTER_SIZE)) ||
80         (status == PSA_ERROR_DOES_NOT_EXIST)) {
81         return TFM_PLAT_ERR_SUCCESS;
82     } else {
83         return TFM_PLAT_ERR_SYSTEM_ERR;
84     }
85 }
86 #endif /* (PS_NS_NV_COUNTER_IN_ITS == 1) */
87 
tfm_plat_read_nv_counter(enum tfm_nv_counter_t counter_id,uint32_t size,uint8_t * val)88 enum tfm_plat_err_t tfm_plat_read_nv_counter(enum tfm_nv_counter_t counter_id,
89                                              uint32_t size, uint8_t *val)
90 {
91     if (size != NV_COUNTER_SIZE) {
92         return TFM_PLAT_ERR_INVALID_INPUT;
93     }
94 
95     /* Assumes Platform nv counters are contiguous*/
96     if (counter_id >= PLAT_NV_COUNTER_BL2_0 &&
97         counter_id < (PLAT_NV_COUNTER_BL2_0 + MCUBOOT_IMAGE_NUMBER)) {
98         return read_otp_counter(PLAT_OTP_ID_NV_COUNTER_BL2_0 +
99                                        (counter_id - PLAT_NV_COUNTER_BL2_0),
100                                    val);
101     }
102 
103     switch (counter_id) {
104 #if (PS_NS_NV_COUNTER_IN_ITS == 0)
105     case (PLAT_NV_COUNTER_NS_0):
106         return read_otp_counter(PLAT_OTP_ID_NV_COUNTER_NS_0, val);
107     case (PLAT_NV_COUNTER_NS_1):
108         return read_otp_counter(PLAT_OTP_ID_NV_COUNTER_NS_1, val);
109     case (PLAT_NV_COUNTER_NS_2):
110         return read_otp_counter(PLAT_OTP_ID_NV_COUNTER_NS_2, val);
111     case (PLAT_NV_COUNTER_PS_0):
112         return read_otp_counter(PLAT_OTP_ID_NV_COUNTER_PS_0, val);
113     case (PLAT_NV_COUNTER_PS_1):
114         return read_otp_counter(PLAT_OTP_ID_NV_COUNTER_PS_1, val);
115     case (PLAT_NV_COUNTER_PS_2):
116         return read_otp_counter(PLAT_OTP_ID_NV_COUNTER_PS_2, val);
117 #else
118     case (PLAT_NV_COUNTER_NS_0):
119         return read_its_nv_counter(PLAT_OTP_ID_NV_COUNTER_NS_0, val);
120     case (PLAT_NV_COUNTER_NS_1):
121         return read_its_nv_counter(PLAT_OTP_ID_NV_COUNTER_NS_1, val);
122     case (PLAT_NV_COUNTER_NS_2):
123         return read_its_nv_counter(PLAT_OTP_ID_NV_COUNTER_NS_2, val);
124     case (PLAT_NV_COUNTER_PS_0):
125         return read_its_nv_counter(PLAT_OTP_ID_NV_COUNTER_PS_0, val);
126     case (PLAT_NV_COUNTER_PS_1):
127         return read_its_nv_counter(PLAT_OTP_ID_NV_COUNTER_PS_1, val);
128     case (PLAT_NV_COUNTER_PS_2):
129         return read_its_nv_counter(PLAT_OTP_ID_NV_COUNTER_PS_2, val);
130 #endif /* (PS_NS_NV_COUNTER_IN_ITS == 0) */
131 
132     default:
133         return TFM_PLAT_ERR_UNSUPPORTED;
134     }
135 }
136 
set_otp_counter(enum tfm_otp_element_id_t id,uint32_t val)137 static enum tfm_plat_err_t set_otp_counter(enum tfm_otp_element_id_t id,
138                                            uint32_t val)
139 {
140     size_t counter_size;
141     enum tfm_plat_err_t err;
142     size_t idx;
143     uint16_t counter_value[OTP_COUNTER_MAX_SIZE / sizeof(uint16_t)] = {0};
144 
145     err = tfm_plat_otp_get_size(id, &counter_size);
146     if (err != TFM_PLAT_ERR_SUCCESS) {
147         return err;
148     }
149 
150     counter_size = counter_size > OTP_COUNTER_MAX_SIZE ? OTP_COUNTER_MAX_SIZE
151                                                        : counter_size;
152 
153     if (val > (counter_size / sizeof(uint16_t))) {
154         return TFM_PLAT_ERR_INVALID_INPUT;
155     }
156 
157     for (idx = 0; idx < val; idx++) {
158         counter_value[idx] = OTP_COUNTER_MAGIC;
159     }
160 
161     err = tfm_plat_otp_write(id, counter_size,
162                              (uint8_t *)counter_value);
163 
164     return err;
165 }
166 
167 #if (PS_NS_NV_COUNTER_IN_ITS == 1)
set_its_nv_counter(enum tfm_otp_element_id_t id,uint32_t val)168 static enum tfm_plat_err_t set_its_nv_counter(enum tfm_otp_element_id_t id,
169                                            uint32_t val)
170 {
171     psa_storage_uid_t uid = (ITS_NV_COUNTER_UID_BASE + id);
172     psa_status_t status;
173 
174     status = psa_its_set(uid, NV_COUNTER_SIZE, &val, PSA_STORAGE_FLAG_NONE);
175 
176     if (status == PSA_SUCCESS) {
177         return TFM_PLAT_ERR_SUCCESS;
178     } else {
179         return TFM_PLAT_ERR_SYSTEM_ERR;
180     }
181 }
182 #endif /* (PS_NS_NV_COUNTER_IN_ITS == 1) */
183 
tfm_plat_set_nv_counter(enum tfm_nv_counter_t counter_id,uint32_t value)184 enum tfm_plat_err_t tfm_plat_set_nv_counter(enum tfm_nv_counter_t counter_id,
185                                             uint32_t value)
186 {
187     /* Assumes Platform nv counters are contiguous*/
188     if (counter_id >= PLAT_NV_COUNTER_BL2_0 &&
189         counter_id < (PLAT_NV_COUNTER_BL2_0 + MCUBOOT_IMAGE_NUMBER)) {
190         return set_otp_counter(PLAT_OTP_ID_NV_COUNTER_BL2_0 +
191                                       (counter_id - PLAT_NV_COUNTER_BL2_0),
192                                   value);
193     }
194 
195     switch (counter_id) {
196 #if (PS_NS_NV_COUNTER_IN_ITS == 0)
197     case (PLAT_NV_COUNTER_NS_0):
198         return set_otp_counter(PLAT_OTP_ID_NV_COUNTER_NS_0, value);
199     case (PLAT_NV_COUNTER_NS_1):
200         return set_otp_counter(PLAT_OTP_ID_NV_COUNTER_NS_1, value);
201     case (PLAT_NV_COUNTER_NS_2):
202         return set_otp_counter(PLAT_OTP_ID_NV_COUNTER_NS_2, value);
203     case (PLAT_NV_COUNTER_PS_0):
204         return set_otp_counter(PLAT_OTP_ID_NV_COUNTER_PS_0, value);
205     case (PLAT_NV_COUNTER_PS_1):
206         return set_otp_counter(PLAT_OTP_ID_NV_COUNTER_PS_1, value);
207     case (PLAT_NV_COUNTER_PS_2):
208         return set_otp_counter(PLAT_OTP_ID_NV_COUNTER_PS_2, value);
209 #else
210     case (PLAT_NV_COUNTER_NS_0):
211         return set_its_nv_counter(PLAT_OTP_ID_NV_COUNTER_NS_0, value);
212     case (PLAT_NV_COUNTER_NS_1):
213         return set_its_nv_counter(PLAT_OTP_ID_NV_COUNTER_NS_1, value);
214     case (PLAT_NV_COUNTER_NS_2):
215         return set_its_nv_counter(PLAT_OTP_ID_NV_COUNTER_NS_2, value);
216     case (PLAT_NV_COUNTER_PS_0):
217         return set_its_nv_counter(PLAT_OTP_ID_NV_COUNTER_PS_0, value);
218     case (PLAT_NV_COUNTER_PS_1):
219         return set_its_nv_counter(PLAT_OTP_ID_NV_COUNTER_PS_1, value);
220     case (PLAT_NV_COUNTER_PS_2):
221         return set_its_nv_counter(PLAT_OTP_ID_NV_COUNTER_PS_2, value);
222 #endif /* (PS_NS_NV_COUNTER_IN_ITS == 0) */
223 
224     default:
225         return TFM_PLAT_ERR_UNSUPPORTED;
226     }
227 }
228 
tfm_plat_increment_nv_counter(enum tfm_nv_counter_t counter_id)229 enum tfm_plat_err_t tfm_plat_increment_nv_counter(
230                                            enum tfm_nv_counter_t counter_id)
231 {
232     uint32_t security_cnt;
233     enum tfm_plat_err_t err;
234 
235     err = tfm_plat_read_nv_counter(counter_id,
236                                    sizeof(security_cnt),
237                                    (uint8_t *)&security_cnt);
238     if (err != TFM_PLAT_ERR_SUCCESS) {
239         return err;
240     }
241 
242     return tfm_plat_set_nv_counter(counter_id, security_cnt + 1u);
243 }
244