1 // SPDX-License-Identifier: BSD-3-Clause
2 /*
3 * Copyright (C) 2019, Theobroma Systems Design und Consulting GmbH
4 * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
5 */
6
7 #include <assert.h>
8 #include <common.h>
9 #include <drivers/rockchip_otp.h>
10 #include <io.h>
11 #include <kernel/panic.h>
12 #include <kernel/mutex.h>
13 #include <kernel/tee_common_otp.h>
14 #include <mm/core_memprot.h>
15 #include <platform.h>
16 #include <platform_config.h>
17 #include <rng_support.h>
18 #include <stdlib_ext.h>
19 #include <string.h>
20 #include <string_ext.h>
21 #include <utee_defines.h>
22
23 #define FIREWALL_DDR_RGN(i) ((i) * 0x4)
24 #define FIREWALL_DDR_CON 0xf0
25 #define FIREWALL_DSU_RGN(i) ((i) * 0x4)
26 #define FIREWALL_DSU_CON(i) (0xf0 + ((i) * 0x4))
27
28 #define RG_MAP_SECURE(top, base) \
29 (((((top) - 1) & 0x7fff) << 16) | ((base) & 0x7fff))
30
31 #define DDR_CHN_CNT 4
32
33 #define TRNG_S_CTRL 0x0000
34 #define TRNG_S_STAT 0x0004
35 #define TRNG_S_MODE 0x0008
36 #define TRNG_S_IE 0x0010
37 #define TRNG_S_ISTAT 0x0014
38 #define TRNG_S_RAND 0x0020
39 #define TRNG_S_AUTO_RQSTS 0x0060
40
41 #define CMD_NOP 0
42 #define CMD_RAND 1
43 #define CMD_SEED 2
44
45 #define LEN_128BIT 0
46 #define LEN_256BIT 3
47
48 #define TRNG_S_SEEDED_BIT BIT32(9)
49 #define TRNG_S_SEED_DONE_BIT BIT32(1)
50 #define TRNG_S_RAND_RDY_BIT BIT32(0)
51
52 #define TRNG_POLL_PERIOD_US 0
53 #define TRNG_POLL_TIMEOUT_US 1000
54
55 register_phys_mem_pgdir(MEM_AREA_IO_SEC, FIREWALL_DDR_BASE, FIREWALL_DDR_SIZE);
56 register_phys_mem_pgdir(MEM_AREA_IO_SEC, FIREWALL_DSU_BASE, FIREWALL_DSU_SIZE);
57 register_phys_mem_pgdir(MEM_AREA_IO_SEC, TRNG_S_BASE, TRNG_S_SIZE);
58
59 static struct mutex trng_mutex = MUTEX_INITIALIZER;
60 static struct mutex huk_mutex = MUTEX_INITIALIZER;
61
62 /* Cache the HUK in memory */
63 static struct tee_hw_unique_key *huk;
64
platform_secure_ddr_region(int rgn,paddr_t st,size_t sz)65 int platform_secure_ddr_region(int rgn, paddr_t st, size_t sz)
66 {
67 vaddr_t fw_ddr_base = (vaddr_t)phys_to_virt_io(FIREWALL_DDR_BASE,
68 FIREWALL_DDR_SIZE);
69 vaddr_t fw_dsu_base = (vaddr_t)phys_to_virt_io(FIREWALL_DSU_BASE,
70 FIREWALL_DSU_SIZE);
71 paddr_t ed = st + sz;
72 uint32_t st_mb = st / SIZE_M(1);
73 uint32_t ed_mb = ed / SIZE_M(1);
74 uint32_t i = 0;
75
76 if (!fw_ddr_base || !fw_dsu_base)
77 panic();
78
79 assert(rgn <= 16);
80 assert(st < ed);
81
82 /* Check aligned 1MB */
83 assert(st % SIZE_M(1) == 0);
84 assert(ed % SIZE_M(1) == 0);
85
86 DMSG("protecting region %d: 0x%"PRIxPA"-0x%"PRIxPA"", rgn, st, ed);
87
88 /* Map secure region in DDR */
89 io_write32(fw_ddr_base + FIREWALL_DDR_RGN(rgn),
90 RG_MAP_SECURE(ed_mb, st_mb));
91
92 /* Map secure region in each DSU channel and enable */
93 for (i = 0; i < DDR_CHN_CNT; i++) {
94 io_write32(fw_dsu_base + FIREWALL_DSU_RGN(i),
95 RG_MAP_SECURE(ed_mb, st_mb));
96 io_setbits32(fw_dsu_base + FIREWALL_DSU_CON(i), BIT(rgn));
97 }
98
99 /* Enable secure region for DDR */
100 io_setbits32(fw_ddr_base + FIREWALL_DDR_CON, BIT(rgn));
101
102 return 0;
103 }
104
hw_get_random_bytes(void * buf,size_t blen)105 TEE_Result hw_get_random_bytes(void *buf, size_t blen)
106 {
107 vaddr_t trng_s_base = (vaddr_t)phys_to_virt_io(TRNG_S_BASE,
108 TRNG_S_SIZE);
109 size_t remaining = blen;
110 size_t copy_len = 0;
111 uint32_t val = 0;
112 uint32_t rnd = 0;
113
114 mutex_lock(&trng_mutex);
115
116 if (!trng_s_base)
117 panic("TRNG_S base not mapped");
118
119 /* Ensure TRNG is seeded and ready */
120 val = io_read32(trng_s_base + TRNG_S_STAT);
121 if (!(val & TRNG_S_SEEDED_BIT)) {
122 /* TRNG not seeded, issue SEED command */
123 io_write32(trng_s_base + TRNG_S_CTRL, CMD_SEED);
124
125 /* Wait for SEED_DONE flag with timeout */
126 if (IO_READ32_POLL_TIMEOUT(trng_s_base + TRNG_S_ISTAT, val,
127 val & TRNG_S_SEED_DONE_BIT,
128 TRNG_POLL_PERIOD_US,
129 TRNG_POLL_TIMEOUT_US)) {
130 mutex_unlock(&trng_mutex);
131 return TEE_ERROR_BUSY;
132 }
133
134 /* SEED_DONE flag set, clear SEED_DONE */
135 io_write32(trng_s_base + TRNG_S_ISTAT, TRNG_S_SEED_DONE_BIT);
136 }
137
138 /* Set RNG length to 256 bits */
139 io_write32(trng_s_base + TRNG_S_MODE, LEN_256BIT);
140
141 while (remaining > 0) {
142 /* Set RAND command to generate random numbers */
143 io_write32(trng_s_base + TRNG_S_CTRL, CMD_RAND);
144
145 /* Wait for RAND_RDY flag with timeout */
146 if (IO_READ32_POLL_TIMEOUT(trng_s_base + TRNG_S_ISTAT, val,
147 val & TRNG_S_RAND_RDY_BIT,
148 TRNG_POLL_PERIOD_US,
149 TRNG_POLL_TIMEOUT_US)) {
150 mutex_unlock(&trng_mutex);
151 return TEE_ERROR_BUSY;
152 }
153
154 /* Read random data from RAND register */
155 rnd = io_read32(trng_s_base + TRNG_S_RAND);
156
157 /* Copy as many bytes as required */
158 copy_len = MIN(remaining, sizeof(uint32_t));
159 memcpy((uint8_t *)buf + (blen - remaining), &rnd, copy_len);
160 remaining -= copy_len;
161
162 /* Clear RAND_RDY flag */
163 io_write32(trng_s_base + TRNG_S_ISTAT, TRNG_S_RAND_RDY_BIT);
164 }
165
166 /* Reset RNG mode to NOP */
167 io_write32(trng_s_base + TRNG_S_CTRL, CMD_NOP);
168
169 mutex_unlock(&trng_mutex);
170
171 return TEE_SUCCESS;
172 }
173
generate_huk(struct tee_hw_unique_key * hwkey)174 static TEE_Result generate_huk(struct tee_hw_unique_key *hwkey)
175 {
176 TEE_Result res = TEE_SUCCESS;
177 uint8_t buffer[HW_UNIQUE_KEY_LENGTH] = { };
178 size_t i = 0;
179 bool key_is_zero = true;
180
181 /* Generate random 128-bit key from TRNG */
182 res = hw_get_random_bytes(buffer, sizeof(buffer));
183 if (res)
184 return res;
185
186 /* All zero HUK cannot be written to OTP and indicates TRNG failure */
187 for (i = 0; i < ARRAY_SIZE(buffer); i++) {
188 if (buffer[i] != 0)
189 key_is_zero = false;
190 }
191 if (key_is_zero)
192 return TEE_ERROR_NO_DATA;
193
194 memcpy(hwkey->data, buffer, HW_UNIQUE_KEY_LENGTH);
195
196 return res;
197 }
198
persist_huk(struct tee_hw_unique_key * hwkey)199 static TEE_Result persist_huk(struct tee_hw_unique_key *hwkey)
200 {
201 TEE_Result res = TEE_SUCCESS;
202 uint32_t buffer[ROCKCHIP_OTP_HUK_SIZE] = { };
203
204 static_assert(sizeof(buffer) == sizeof(hwkey->data));
205
206 memcpy(buffer, hwkey->data, HW_UNIQUE_KEY_LENGTH);
207
208 /* Write the new HUK into OTP at ROCKCHIP_OTP_HUK_INDEX */
209 res = rockchip_otp_write_secure(buffer, ROCKCHIP_OTP_HUK_INDEX,
210 ROCKCHIP_OTP_HUK_SIZE);
211
212 /* Clear buffer memory */
213 memzero_explicit(buffer, sizeof(buffer));
214
215 return res;
216 }
217
read_huk(struct tee_hw_unique_key * hwkey)218 static TEE_Result read_huk(struct tee_hw_unique_key *hwkey)
219 {
220 TEE_Result res = TEE_SUCCESS;
221 uint32_t buffer[ROCKCHIP_OTP_HUK_SIZE] = { };
222 bool key_is_empty = true;
223 size_t i = 0;
224
225 static_assert(sizeof(buffer) == sizeof(hwkey->data));
226
227 /* Read 4 words (16 bytes) from OTP at ROCKCHIP_OTP_HUK_INDEX */
228 res = rockchip_otp_read_secure(buffer,
229 ROCKCHIP_OTP_HUK_INDEX,
230 ROCKCHIP_OTP_HUK_SIZE);
231 if (res)
232 goto out;
233
234 /* Check if the buffer is all zero => HUK not present */
235 for (i = 0; i < ARRAY_SIZE(buffer); i++) {
236 if (buffer[i] != 0)
237 key_is_empty = false;
238 }
239 if (key_is_empty)
240 return TEE_ERROR_NO_DATA;
241
242 /* Copy HUK into hwkey->data */
243 memcpy(hwkey->data, buffer, HW_UNIQUE_KEY_LENGTH);
244
245 out:
246 /* Clear buffer memory */
247 memzero_explicit(buffer, sizeof(buffer));
248
249 return res;
250 }
251
tee_otp_get_hw_unique_key(struct tee_hw_unique_key * hwkey)252 TEE_Result tee_otp_get_hw_unique_key(struct tee_hw_unique_key *hwkey)
253 {
254 TEE_Result res = TEE_SUCCESS;
255
256 if (!hwkey)
257 return TEE_ERROR_BAD_PARAMETERS;
258
259 mutex_lock(&huk_mutex);
260
261 /* Try to use the cached HUK from memory */
262 if (huk)
263 goto out;
264
265 huk = malloc(sizeof(*huk));
266 if (!huk) {
267 res = TEE_ERROR_OUT_OF_MEMORY;
268 goto out;
269 }
270
271 /* Try to read and cache the HUK persisted in the OTP */
272 res = read_huk(huk);
273 if (res != TEE_ERROR_NO_DATA)
274 goto out;
275
276 /* Try to generate and use a new HUK and persist it in the OTP */
277 res = generate_huk(huk);
278 if (res != TEE_SUCCESS)
279 goto out;
280 res = persist_huk(huk);
281
282 out:
283 if (res == TEE_SUCCESS) {
284 memcpy(hwkey->data, huk->data, HW_UNIQUE_KEY_LENGTH);
285 } else if (huk) {
286 free_wipe(huk);
287 huk = NULL;
288 }
289
290 mutex_unlock(&huk_mutex);
291
292 return res;
293 }
294