1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (C) Foundries Ltd. 2021
4 * Author: Jorge Ramirez <jorge@foundries.io>
5 */
6 #include <config.h>
7 #include <drivers/zynqmp_csu.h>
8 #include <drivers/zynqmp_csu_aes.h>
9 #include <io.h>
10 #include <kernel/boot.h>
11 #include <kernel/delay.h>
12 #include <kernel/dt.h>
13 #include <libfdt.h>
14 #include <malloc.h>
15 #include <mm/core_memprot.h>
16 #include <string.h>
17 #include <tee/cache.h>
18
19 /* CSU AES registers */
20 #define AES_STS_OFFSET 0x00
21 #define AES_KEY_SRC_OFFSET 0x04
22 #define AES_KEY_LOAD_OFFSET 0x08
23 #define AES_START_MSG_OFFSET 0x0C
24 #define AES_RESET_OFFSET 0x10
25 #define AES_KEY_CLR_OFFSET 0x14
26 #define AES_CFG_OFFSET 0x18
27
28 #define AES_KEY_LOAD 1
29 #define AES_STS_AES_BUSY BIT(0)
30 #define AES_STS_AES_KEY_ZEROED BIT(8)
31 #define AES_STS_KUP_ZEROED BIT(9)
32 #define AES_STS_KEY_INIT_DONE BIT(4)
33 #define AES_STS_GCM_TAG_OK BIT(3)
34 #define AES_START_MSG 1
35 #define AES_CFG_ENC 1
36 #define AES_CFG_DEC 0
37 #define AES_RESET_SET 1
38 #define AES_RESET_CLR 0
39 #define AES_KEY_ZERO BIT(0)
40 #define AES_KUP_ZERO BIT(1)
41
42 #define AES_TIMEOUT_USEC 2000000
43
44 enum aes_op { AES_DEC, AES_ENC };
45
aes_wait(uint32_t event,bool set)46 static TEE_Result aes_wait(uint32_t event, bool set)
47 {
48 vaddr_t aes = core_mmu_get_va(ZYNQMP_CSU_AES_BASE, MEM_AREA_IO_SEC,
49 ZYNQMP_CSU_AES_SIZE);
50 uint64_t tref = timeout_init_us(AES_TIMEOUT_USEC);
51 uint32_t status = 0;
52
53 if (!aes)
54 return TEE_ERROR_GENERIC;
55
56 while (!timeout_elapsed(tref)) {
57 status = io_read32(aes + AES_STS_OFFSET) & event;
58 if ((set && status == event) || (!set && status != event))
59 return TEE_SUCCESS;
60 }
61
62 return TEE_ERROR_GENERIC;
63 }
64
aes_transfer_enc(const void * src,void * dst,size_t dst_len,void * tag,const void * iv)65 static TEE_Result aes_transfer_enc(const void *src, void *dst, size_t dst_len,
66 void *tag, const void *iv)
67 {
68 void *p = (uint8_t *)dst + dst_len - ZYNQMP_GCM_TAG_SIZE;
69 uint8_t iv_padded[ZYNQMP_CSUDMA_MIN_SIZE] __aligned_csudma = { 0 };
70 TEE_Result ret = TEE_SUCCESS;
71
72 if (dst_len < ZYNQMP_GCM_TAG_SIZE) {
73 EMSG("Invalid length");
74 return TEE_ERROR_GENERIC;
75 }
76
77 ret = zynqmp_csudma_prepare();
78 if (ret) {
79 EMSG("DMA can't initialize");
80 return ret;
81 }
82
83 /* Prepare destination */
84 ret = zynqmp_csudma_transfer(ZYNQMP_CSUDMA_DST_CHANNEL, dst, dst_len,
85 0);
86 if (ret) {
87 EMSG("DMA transfer failed, invalid destination buffer");
88 goto out;
89 }
90
91 /* Inputs */
92 memcpy(iv_padded, iv, ZYNQMP_GCM_IV_SIZE);
93 ret = zynqmp_csudma_transfer(ZYNQMP_CSUDMA_SRC_CHANNEL,
94 (void *)iv_padded, ZYNQMP_CSUDMA_MIN_SIZE,
95 0);
96 if (ret) {
97 EMSG("DMA transfer failed, invalid IV buffer");
98 goto out;
99 }
100
101 ret = zynqmp_csudma_sync(ZYNQMP_CSUDMA_SRC_CHANNEL);
102 if (ret) {
103 EMSG("DMA IV transfer timeout");
104 goto out;
105 }
106
107 ret = zynqmp_csudma_transfer(ZYNQMP_CSUDMA_SRC_CHANNEL,
108 (void *)src, dst_len - ZYNQMP_GCM_TAG_SIZE,
109 ZYNQMP_CSUDMA_DONE);
110 if (ret) {
111 EMSG("DMA transfer failed, invalid source buffer");
112 goto out;
113 }
114
115 ret = zynqmp_csudma_sync(ZYNQMP_CSUDMA_SRC_CHANNEL);
116 if (ret) {
117 EMSG("DMA source transfer timeout");
118 goto out;
119 }
120
121 /* Wait for completion */
122 ret = zynqmp_csudma_sync(ZYNQMP_CSUDMA_DST_CHANNEL);
123 if (ret) {
124 EMSG("DMA destination transfer timeout");
125 goto out;
126 }
127
128 /* Transfer the GCM tag */
129 memcpy(tag, p, ZYNQMP_GCM_TAG_SIZE);
130 out:
131 zynqmp_csudma_unprepare();
132
133 return ret;
134 }
135
aes_transfer_dec(const void * src,void * dst,size_t len,const void * tag,const void * iv)136 static TEE_Result aes_transfer_dec(const void *src, void *dst, size_t len,
137 const void *tag, const void *iv)
138 {
139 uint8_t iv_padded[ZYNQMP_CSUDMA_MIN_SIZE] __aligned_csudma = { 0 };
140 TEE_Result ret = TEE_SUCCESS;
141
142 ret = zynqmp_csudma_prepare();
143 if (ret) {
144 EMSG("DMA can't initialize");
145 return ret;
146 }
147
148 /* Prepare destination */
149 ret = zynqmp_csudma_transfer(ZYNQMP_CSUDMA_DST_CHANNEL, dst, len, 0);
150 if (ret) {
151 EMSG("DMA transfer failed, invalid destination buffer");
152 goto out;
153 }
154
155 /* Inputs */
156 memcpy(iv_padded, iv, ZYNQMP_GCM_IV_SIZE);
157 ret = zynqmp_csudma_transfer(ZYNQMP_CSUDMA_SRC_CHANNEL,
158 (void *)iv_padded, ZYNQMP_CSUDMA_MIN_SIZE,
159 0);
160 if (ret) {
161 EMSG("DMA transfer failed, invalid IV buffer");
162 goto out;
163 }
164
165 ret = zynqmp_csudma_sync(ZYNQMP_CSUDMA_SRC_CHANNEL);
166 if (ret) {
167 EMSG("DMA IV transfer timeout");
168 goto out;
169 }
170
171 ret = zynqmp_csudma_transfer(ZYNQMP_CSUDMA_SRC_CHANNEL, (void *)src,
172 len, ZYNQMP_CSUDMA_DONE);
173 if (ret) {
174 EMSG("DMA transfer failed, invalid source buffer");
175 goto out;
176 }
177
178 ret = zynqmp_csudma_sync(ZYNQMP_CSUDMA_SRC_CHANNEL);
179 if (ret) {
180 EMSG("DMA source transfer timeout");
181 goto out;
182 }
183
184 ret = zynqmp_csudma_transfer(ZYNQMP_CSUDMA_SRC_CHANNEL, (void *)tag,
185 ZYNQMP_GCM_TAG_SIZE, ZYNQMP_CSUDMA_DONE);
186 if (ret) {
187 EMSG("DMA transfer failed, invalid tag buffer");
188 goto out;
189 }
190
191 ret = zynqmp_csudma_sync(ZYNQMP_CSUDMA_SRC_CHANNEL);
192 if (ret) {
193 EMSG("DMA tag transfer timeout");
194 goto out;
195 }
196
197 /* Wait for completion*/
198 ret = zynqmp_csudma_sync(ZYNQMP_CSUDMA_DST_CHANNEL);
199 if (ret)
200 EMSG("DMA destination transfer timeout");
201 out:
202 zynqmp_csudma_unprepare();
203
204 return ret;
205 }
206
aes_prepare_op(enum aes_op op,enum zynqmp_csu_key key)207 static TEE_Result aes_prepare_op(enum aes_op op, enum zynqmp_csu_key key)
208 {
209 vaddr_t aes = core_mmu_get_va(ZYNQMP_CSU_AES_BASE, MEM_AREA_IO_SEC,
210 ZYNQMP_CSU_AES_SIZE);
211 vaddr_t csu = core_mmu_get_va(CSU_BASE, MEM_AREA_IO_SEC, CSU_SIZE);
212 TEE_Result ret = TEE_SUCCESS;
213
214 if (!aes || !csu)
215 return TEE_ERROR_GENERIC;
216
217 /* Connect DMA0 in/out to AES */
218 io_write32(csu + ZYNQMP_CSU_SSS_CFG_OFFSET,
219 ZYNQMP_CSU_SSS_DMA0_STREAM_TO_AES);
220
221 /* Reset the AES */
222 io_write32(aes + AES_RESET_OFFSET, AES_RESET_SET);
223 io_write32(aes + AES_RESET_OFFSET, AES_RESET_CLR);
224
225 /* Load the key */
226 io_write32(aes + AES_KEY_CLR_OFFSET, 0);
227 io_write32(aes + AES_KEY_SRC_OFFSET, key);
228 io_write32(aes + AES_KEY_LOAD_OFFSET, AES_KEY_LOAD);
229 ret = aes_wait(AES_STS_KEY_INIT_DONE, true);
230 if (ret) {
231 EMSG("Timeout loading the key");
232 return TEE_ERROR_GENERIC;
233 }
234
235 /* Configure operation */
236 io_write32(aes + AES_CFG_OFFSET,
237 op == AES_DEC ? AES_CFG_DEC : AES_CFG_ENC);
238
239 /* Prepare the CSU for the DMA */
240 io_write32(csu + ZYNQMP_CSU_DMA_RESET_OFFSET, ZYNQMP_CSU_DMA_RESET_SET);
241 io_write32(csu + ZYNQMP_CSU_DMA_RESET_OFFSET, ZYNQMP_CSU_DMA_RESET_CLR);
242
243 /* Start the message */
244 io_write32(aes + AES_START_MSG_OFFSET, AES_START_MSG);
245
246 return TEE_SUCCESS;
247 }
248
aes_done_op(enum aes_op op,TEE_Result ret)249 static TEE_Result aes_done_op(enum aes_op op, TEE_Result ret)
250 {
251 vaddr_t aes = core_mmu_get_va(ZYNQMP_CSU_AES_BASE, MEM_AREA_IO_SEC,
252 ZYNQMP_CSU_AES_SIZE);
253 uint32_t val = 0;
254
255 if (!aes)
256 return TEE_ERROR_GENERIC;
257
258 if (!ret && op == AES_DEC) {
259 /* on decompression we must validate the GCM tag */
260 val = io_read32(aes + AES_STS_OFFSET) & AES_STS_GCM_TAG_OK;
261 if (!val) {
262 EMSG("AES-GCM tag mismatch");
263 return TEE_ERROR_GENERIC;
264 }
265 }
266
267 val = io_read32(aes + AES_KEY_CLR_OFFSET);
268 io_write32(aes + AES_KEY_CLR_OFFSET, val | AES_KEY_ZERO | AES_KUP_ZERO);
269 if (aes_wait(AES_STS_AES_KEY_ZEROED | AES_STS_KUP_ZEROED, true))
270 EMSG("Failed to clear the AES key");
271 io_write32(aes + AES_KEY_CLR_OFFSET, val);
272
273 io_write32(aes + AES_RESET_OFFSET, AES_RESET_SET);
274
275 return ret;
276 }
277
zynqmp_csu_aes_decrypt_data(const void * src,size_t src_len,void * dst,size_t dst_len,const void * tag,size_t tag_len,const void * iv,size_t iv_len,enum zynqmp_csu_key key)278 TEE_Result zynqmp_csu_aes_decrypt_data(const void *src, size_t src_len,
279 void *dst, size_t dst_len,
280 const void *tag, size_t tag_len,
281 const void *iv, size_t iv_len,
282 enum zynqmp_csu_key key)
283 {
284 TEE_Result ret = TEE_SUCCESS;
285
286 if (key != ZYNQMP_CSU_AES_KEY_SRC_DEV) {
287 EMSG("Key type not supported");
288 return TEE_ERROR_NOT_IMPLEMENTED;
289 }
290
291 if (src_len % 4 || dst_len != src_len) {
292 EMSG("Invalid source size");
293 return TEE_ERROR_BAD_PARAMETERS;
294 }
295
296 if (iv_len != ZYNQMP_GCM_IV_SIZE) {
297 EMSG("Invalid IV size");
298 return TEE_ERROR_BAD_PARAMETERS;
299 }
300
301 if (tag_len != ZYNQMP_GCM_TAG_SIZE) {
302 EMSG("Invalid tag size");
303 return TEE_ERROR_BAD_PARAMETERS;
304 }
305
306 if (!src || !dst || !tag || !iv) {
307 EMSG("Invalid input value");
308 return TEE_ERROR_BAD_PARAMETERS;
309 }
310
311 ret = aes_prepare_op(AES_DEC, key);
312 if (ret) {
313 EMSG("Decrypt init failed");
314 goto out;
315 }
316
317 ret = aes_transfer_dec(src, dst, src_len, tag, iv);
318 if (ret) {
319 EMSG("DMA transfer failed");
320 goto out;
321 }
322
323 ret = aes_wait(AES_STS_AES_BUSY, false);
324 if (ret)
325 EMSG("AES-GCM transfer failed");
326 out:
327 return aes_done_op(AES_DEC, ret);
328 }
329
zynqmp_csu_aes_encrypt_data(const void * src,size_t src_len,void * dst,size_t dst_len,void * tag,size_t tag_len,const void * iv,size_t iv_len,enum zynqmp_csu_key key)330 TEE_Result zynqmp_csu_aes_encrypt_data(const void *src, size_t src_len,
331 void *dst, size_t dst_len,
332 void *tag, size_t tag_len,
333 const void *iv, size_t iv_len,
334 enum zynqmp_csu_key key)
335 {
336 TEE_Result ret = TEE_SUCCESS;
337
338 if (key != ZYNQMP_CSU_AES_KEY_SRC_DEV) {
339 EMSG("Key type not supported");
340 return TEE_ERROR_NOT_IMPLEMENTED;
341 }
342
343 if (src_len % 4 || dst_len != ZYNQMP_CSU_AES_DST_LEN(src_len)) {
344 EMSG("Invalid source size");
345 return TEE_ERROR_BAD_PARAMETERS;
346 }
347
348 if (iv_len != ZYNQMP_GCM_IV_SIZE) {
349 EMSG("Invalid IV size");
350 return TEE_ERROR_BAD_PARAMETERS;
351 }
352
353 if (tag_len != ZYNQMP_GCM_TAG_SIZE) {
354 EMSG("Invalid tag size");
355 return TEE_ERROR_BAD_PARAMETERS;
356 }
357
358 if (!src || !dst || !tag || !iv) {
359 EMSG("Invalid input value");
360 return TEE_ERROR_BAD_PARAMETERS;
361 }
362
363 ret = aes_prepare_op(AES_ENC, key);
364 if (ret) {
365 EMSG("Encrypt init failed");
366 goto out;
367 }
368
369 ret = aes_transfer_enc(src, dst, dst_len, tag, iv);
370 if (ret) {
371 EMSG("DMA transfer failed");
372 goto out;
373 }
374
375 ret = aes_wait(AES_STS_AES_BUSY, false);
376 if (ret)
377 EMSG("AES transfer failed");
378 out:
379 return aes_done_op(AES_ENC, ret);
380 }
381
382 static const char *const dt_ctrl_match_table[] = {
383 "xlnx,zynqmp-aes",
384 };
385
zynqmp_csu_aes_dt_enable_secure_status(void)386 TEE_Result zynqmp_csu_aes_dt_enable_secure_status(void)
387 {
388 unsigned int i = 0;
389 void *fdt = NULL;
390 int node = -1;
391
392 fdt = get_external_dt();
393 if (!fdt)
394 return TEE_SUCCESS;
395
396 for (i = 0; i < ARRAY_SIZE(dt_ctrl_match_table); i++) {
397 node = fdt_node_offset_by_compatible(fdt, 0,
398 dt_ctrl_match_table[i]);
399 if (node >= 0)
400 break;
401 }
402
403 if (node < 0)
404 return TEE_SUCCESS;
405
406 if (_fdt_get_status(fdt, node) == DT_STATUS_DISABLED)
407 return TEE_SUCCESS;
408
409 if (dt_enable_secure_status(fdt, node)) {
410 EMSG("Not able to set the AES-GCM DTB entry secure");
411 return TEE_ERROR_NOT_SUPPORTED;
412 }
413
414 return TEE_SUCCESS;
415 }
416