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