1 /*
2 * Copyright (c) 2018-2022, 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 (128u * 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 switch(counter_id) {
79 case (PLAT_NV_COUNTER_BL2_0):
80 return read_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_BL2_0, val);
81 case (PLAT_NV_COUNTER_BL2_1):
82 return read_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_BL2_1, val);
83 case (PLAT_NV_COUNTER_BL2_2):
84 return read_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_BL2_2, val);
85 case (PLAT_NV_COUNTER_BL2_3):
86 return read_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_BL2_3, val);
87
88 case (PLAT_NV_COUNTER_NS_0):
89 return read_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_NS_0, val);
90 case (PLAT_NV_COUNTER_NS_1):
91 return read_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_NS_1, val);
92 case (PLAT_NV_COUNTER_NS_2):
93 return read_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_NS_2, val);
94
95 case (PLAT_NV_COUNTER_BL1_0):
96 return read_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_BL1_0, val);
97
98 default:
99 return TFM_PLAT_ERR_UNSUPPORTED;
100 }
101 }
102
set_nv_counter_otp(enum tfm_otp_element_id_t id,uint32_t value)103 static enum tfm_plat_err_t set_nv_counter_otp(enum tfm_otp_element_id_t id,
104 uint32_t value)
105 {
106 size_t counter_size;
107 enum tfm_plat_err_t err;
108 size_t idx;
109 uint32_t counter_value[OTP_COUNTER_MAX_SIZE / sizeof(uint32_t)] = {0};
110
111 err = tfm_plat_otp_get_size(id, &counter_size);
112 if (err != TFM_PLAT_ERR_SUCCESS) {
113 return err;
114 }
115
116 counter_size = counter_size > OTP_COUNTER_MAX_SIZE ? OTP_COUNTER_MAX_SIZE
117 : counter_size;
118
119 if (value > counter_size) {
120 return TFM_PLAT_ERR_MAX_VALUE;
121 }
122
123 for (idx = 0; idx < value; idx++) {
124 counter_value[idx] = OTP_COUNTER_MAGIC;
125 }
126
127 err = tfm_plat_otp_write(id, sizeof(counter_value),
128 (uint8_t *)counter_value);
129
130 return err;
131 }
132
tfm_plat_set_nv_counter(enum tfm_nv_counter_t counter_id,uint32_t value)133 enum tfm_plat_err_t tfm_plat_set_nv_counter(enum tfm_nv_counter_t counter_id,
134 uint32_t value)
135 {
136 switch(counter_id) {
137 case (PLAT_NV_COUNTER_BL2_0):
138 return set_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_BL2_0, value);
139 case (PLAT_NV_COUNTER_BL2_1):
140 return set_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_BL2_1, value);
141 case (PLAT_NV_COUNTER_BL2_2):
142 return set_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_BL2_2, value);
143 case (PLAT_NV_COUNTER_BL2_3):
144 return set_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_BL2_3, value);
145
146 case (PLAT_NV_COUNTER_NS_0):
147 return set_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_NS_0, value);
148 case (PLAT_NV_COUNTER_NS_1):
149 return set_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_NS_1, value);
150 case (PLAT_NV_COUNTER_NS_2):
151 return set_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_NS_2, value);
152
153 case (PLAT_NV_COUNTER_BL1_0):
154 return set_nv_counter_otp(PLAT_OTP_ID_NV_COUNTER_BL1_0, value);
155
156 default:
157 return TFM_PLAT_ERR_UNSUPPORTED;
158 }
159 }
160
tfm_plat_increment_nv_counter(enum tfm_nv_counter_t counter_id)161 enum tfm_plat_err_t tfm_plat_increment_nv_counter(
162 enum tfm_nv_counter_t counter_id)
163 {
164 uint32_t security_cnt;
165 enum tfm_plat_err_t err;
166
167 err = tfm_plat_read_nv_counter(counter_id,
168 sizeof(security_cnt),
169 (uint8_t *)&security_cnt);
170 if (err != TFM_PLAT_ERR_SUCCESS) {
171 return err;
172 }
173
174 if (security_cnt == UINT32_MAX) {
175 return TFM_PLAT_ERR_MAX_VALUE;
176 }
177
178 return tfm_plat_set_nv_counter(counter_id, security_cnt + 1u);
179 }
180