1 /*
2 * Copyright (c) 2018-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 a internal (in-die) persistent memory for the implementation
11 * of the OTP_NV_COUNTERS flash area (see flash_otp_nv_layout.c).
12 */
13
14 #include "tfm_plat_nv_counters.h"
15
16 #include <limits.h>
17 #include "Driver_Flash.h"
18 #include "flash_layout.h"
19 #include "tfm_plat_otp.h"
20 #include "cmsis_compiler.h"
21
22 #include <string.h>
23
24 #define OTP_COUNTER_MAX_SIZE (16u * sizeof(uint32_t))
25 #define NV_COUNTER_SIZE 4
26 #define OTP_COUNTER_MAGIC 0x3333CAFE
27
tfm_plat_init_nv_counter(void)28 enum tfm_plat_err_t tfm_plat_init_nv_counter(void)
29 {
30 return TFM_PLAT_ERR_SUCCESS;
31 }
32
read_nv_counter_otp(enum tfm_otp_element_id_t id,uint8_t * val)33 static enum tfm_plat_err_t read_nv_counter_otp(enum tfm_otp_element_id_t id,
34 uint8_t *val)
35 {
36 size_t counter_size;
37 enum tfm_plat_err_t err;
38 size_t idx;
39 uint32_t counter_value[OTP_COUNTER_MAX_SIZE / sizeof(uint32_t)] = {0};
40 uint32_t count;
41
42 err = tfm_plat_otp_get_size(id, &counter_size);
43 if (err != TFM_PLAT_ERR_SUCCESS) {
44 return err;
45 }
46
47 counter_size = counter_size > OTP_COUNTER_MAX_SIZE ? OTP_COUNTER_MAX_SIZE
48 : counter_size;
49
50 err = tfm_plat_otp_read(id, counter_size, (uint8_t *)counter_value);
51 if (err != TFM_PLAT_ERR_SUCCESS) {
52 return err;
53 }
54
55 count = 0;
56 for (idx = 0; idx < counter_size / sizeof(uint32_t); idx++) {
57 if (counter_value[idx] == OTP_COUNTER_MAGIC) {
58 count += 1;
59 } else if (counter_value[idx] == 0) {
60 break;
61 } else {
62 return TFM_PLAT_ERR_SYSTEM_ERR;
63 }
64 }
65
66 memcpy(val, &count, NV_COUNTER_SIZE);
67
68 return TFM_PLAT_ERR_SUCCESS;
69 }
70
tfm_plat_read_nv_counter(enum tfm_nv_counter_t counter_id,uint32_t size,uint8_t * val)71 enum tfm_plat_err_t tfm_plat_read_nv_counter(enum tfm_nv_counter_t counter_id,
72 uint32_t size, uint8_t *val)
73 {
74 if (size != NV_COUNTER_SIZE) {
75 return TFM_PLAT_ERR_SYSTEM_ERR;
76 }
77
78 /* Assumes Platform nv counters are contiguous*/
79 if (counter_id >= PLAT_NV_COUNTER_BL2_0 &&
80 counter_id < (PLAT_NV_COUNTER_BL2_0 + MCUBOOT_IMAGE_NUMBER)) {
81 return read_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_BL2_0 +
82 (counter_id - PLAT_NV_COUNTER_BL2_0),
83 val);
84 }
85
86 switch (counter_id) {
87 #ifdef PLATFORM_HAS_PS_NV_OTP_COUNTERS
88 case (PLAT_NV_COUNTER_PS_0):
89 return read_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_PS_0, val);
90 case (PLAT_NV_COUNTER_PS_1):
91 return read_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_PS_1, val);
92 case (PLAT_NV_COUNTER_PS_2):
93 return read_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_PS_2, val);
94 #endif /* PLATFORM_HAS_PS_NV_OTP_COUNTERS */
95 case (PLAT_NV_COUNTER_NS_0):
96 return read_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_NS_0, val);
97 case (PLAT_NV_COUNTER_NS_1):
98 return read_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_NS_1, val);
99 case (PLAT_NV_COUNTER_NS_2):
100 return read_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_NS_2, val);
101
102 case (PLAT_NV_COUNTER_BL1_0):
103 return read_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_BL1_0, val);
104
105 default:
106 return TFM_PLAT_ERR_UNSUPPORTED;
107 }
108 }
109
set_nv_counter_otp(enum tfm_otp_element_id_t id,uint32_t value)110 static enum tfm_plat_err_t set_nv_counter_otp(enum tfm_otp_element_id_t id,
111 uint32_t value)
112 {
113 size_t counter_size;
114 enum tfm_plat_err_t err;
115 size_t idx;
116 uint32_t counter_value[OTP_COUNTER_MAX_SIZE / sizeof(uint32_t)] = {0};
117
118 err = tfm_plat_otp_get_size(id, &counter_size);
119 if (err != TFM_PLAT_ERR_SUCCESS) {
120 return err;
121 }
122
123 counter_size = counter_size > OTP_COUNTER_MAX_SIZE ? OTP_COUNTER_MAX_SIZE
124 : counter_size;
125
126 if (value > counter_size) {
127 return TFM_PLAT_ERR_MAX_VALUE;
128 }
129
130 for (idx = 0; idx < value; idx++) {
131 counter_value[idx] = OTP_COUNTER_MAGIC;
132 }
133
134 err = tfm_plat_otp_write(id, sizeof(counter_value),
135 (uint8_t *)counter_value);
136
137 return err;
138 }
139
tfm_plat_set_nv_counter(enum tfm_nv_counter_t counter_id,uint32_t value)140 enum tfm_plat_err_t tfm_plat_set_nv_counter(enum tfm_nv_counter_t counter_id,
141 uint32_t value)
142 {
143 /* Assumes Platform nv counters are contiguous*/
144 if (counter_id >= PLAT_NV_COUNTER_BL2_0 &&
145 counter_id < (PLAT_NV_COUNTER_BL2_0 + MCUBOOT_IMAGE_NUMBER)) {
146 return set_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_BL2_0 +
147 (counter_id - PLAT_NV_COUNTER_BL2_0),
148 value);
149 }
150
151 switch (counter_id) {
152 #ifdef PLATFORM_HAS_PS_NV_OTP_COUNTERS
153 case (PLAT_NV_COUNTER_PS_0):
154 return set_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_PS_0, value);
155 case (PLAT_NV_COUNTER_PS_1):
156 return set_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_PS_1, value);
157 case (PLAT_NV_COUNTER_PS_2):
158 return set_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_PS_2, value);
159 #endif /* PLATFORM_HAS_PS_NV_OTP_COUNTERS */
160
161 case (PLAT_NV_COUNTER_NS_0):
162 return set_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_NS_0, value);
163 case (PLAT_NV_COUNTER_NS_1):
164 return set_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_NS_1, value);
165 case (PLAT_NV_COUNTER_NS_2):
166 return set_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_NS_2, value);
167
168 case (PLAT_NV_COUNTER_BL1_0):
169 return set_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_BL1_0, value);
170
171 default:
172 return TFM_PLAT_ERR_UNSUPPORTED;
173 }
174 }
175
tfm_plat_increment_nv_counter(enum tfm_nv_counter_t counter_id)176 enum tfm_plat_err_t tfm_plat_increment_nv_counter(
177 enum tfm_nv_counter_t counter_id)
178 {
179 uint32_t security_cnt;
180 enum tfm_plat_err_t err;
181
182 err = tfm_plat_read_nv_counter(counter_id,
183 sizeof(security_cnt),
184 (uint8_t *)&security_cnt);
185 if (err != TFM_PLAT_ERR_SUCCESS) {
186 return err;
187 }
188
189 if (security_cnt == UINT32_MAX) {
190 return TFM_PLAT_ERR_MAX_VALUE;
191 }
192
193 return tfm_plat_set_nv_counter(counter_id, security_cnt + 1u);
194 }
195