xref: /optee_os/core/drivers/crypto/asu_driver/asu_hash.c (revision 74ddb42edbe0ea886661c62476bac147ad3141aa)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2025-2026, Advanced Micro Devices, Inc. All rights reserved.
4  *
5  */
6 
7 #include <assert.h>
8 #include <drivers/amd/asu_client.h>
9 #include <drvcrypt_hash.h>
10 #include <initcall.h>
11 #include <io.h>
12 #include <kernel/mutex.h>
13 #include <kernel/panic.h>
14 #include <kernel/unwind.h>
15 #include <mm/core_memprot.h>
16 #include <stdbool.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <tee/cache.h>
20 #include <trace.h>
21 #include <util.h>
22 
23 #define ASU_SHA_OPERATION_CMD_ID		0U
24 /* SHA modes */
25 #define ASU_SHA_MODE_SHA256			0U
26 #define ASU_SHA_MODE_SHA384			1U
27 #define ASU_SHA_MODE_SHA512			2U
28 #define ASU_SHA_MODE_SHAKE256			4U
29 
30 /* SHA operation mode */
31 #define ASU_SHA_START				0x1U
32 #define ASU_SHA_UPDATE				0x2U
33 #define ASU_SHA_FINISH				0x4U
34 
35 /* SHA hash lengths */
36 #define ASU_SHA_256_HASH_LEN			32U
37 #define ASU_SHA_384_HASH_LEN			48U
38 #define ASU_SHA_512_HASH_LEN			64U
39 #define ASU_SHAKE_256_HASH_LEN			32U
40 #define ASU_SHAKE_256_MAX_HASH_LEN		136U
41 #define ASU_DATA_CHUNK_LEN			4096U
42 
43 struct asu_shadev {
44 	bool sha2_available;
45 	bool sha3_available;
46 	/* Control access to engine*/
47 	struct mutex engine_lock;
48 };
49 
50 struct asu_sha_op_cmd {
51 	uint64_t dataaddr;
52 	uint64_t hashaddr;
53 	uint32_t datasize;
54 	uint32_t hashbufsize;
55 	uint8_t shamode;
56 	uint8_t islast;
57 	uint8_t opflags;
58 	uint8_t shakereserved;
59 };
60 
61 struct asu_hash_ctx {
62 	struct crypto_hash_ctx hash_ctx; /* Crypto Hash API context */
63 	struct asu_client_params cparam;
64 	uint32_t shamode;
65 	uint32_t shastart;
66 	uint8_t uniqueid;
67 	uint8_t module;
68 };
69 
70 struct asu_hash_cbctx {
71 	uint8_t *digest;
72 	size_t len;
73 };
74 
75 static const struct crypto_hash_ops asu_hash_ops;
76 static struct asu_shadev *asu_shadev;
77 static struct asu_hash_ctx *to_hash_ctx(struct crypto_hash_ctx *ctx);
78 
79 /**
80  * asu_hash_get_alg() - Get fw engine module ID and Hash mode.
81  * @algo:	TEE algo type.
82  * @module:	Engine module ID
83  * @mode:	Hash operation mode
84  * Map TEE algo type to fw module ID amd mode.
85  *
86  * Return: TEE_SUCCESS or TEE_ERROR_NOT_IMPLEMENTED
87  */
88 
asu_hash_get_alg(uint32_t algo,uint32_t * module,uint32_t * mode)89 static TEE_Result asu_hash_get_alg(uint32_t algo,
90 				   uint32_t *module,
91 				   uint32_t *mode)
92 {
93 	TEE_Result ret = TEE_SUCCESS;
94 
95 	switch (algo) {
96 	case TEE_ALG_SHA256:
97 		*module = ASU_MODULE_SHA2_ID;
98 		*mode = ASU_SHA_MODE_SHA256;
99 		break;
100 	case TEE_ALG_SHA384:
101 		*module = ASU_MODULE_SHA2_ID;
102 		*mode = ASU_SHA_MODE_SHA384;
103 		break;
104 	case TEE_ALG_SHA512:
105 		*module = ASU_MODULE_SHA2_ID;
106 		*mode = ASU_SHA_MODE_SHA512;
107 		break;
108 	case TEE_ALG_SHA3_256:
109 		*module = ASU_MODULE_SHA3_ID;
110 		*mode = ASU_SHA_MODE_SHA256;
111 		break;
112 	case TEE_ALG_SHA3_384:
113 		*module = ASU_MODULE_SHA3_ID;
114 		*mode = ASU_SHA_MODE_SHA384;
115 		break;
116 	case TEE_ALG_SHA3_512:
117 		*module = ASU_MODULE_SHA3_ID;
118 		*mode = ASU_SHA_MODE_SHA512;
119 		break;
120 	default:
121 		ret = TEE_ERROR_NOT_IMPLEMENTED;
122 		break;
123 	}
124 
125 	return ret;
126 }
127 
128 /**
129  * asu_hash_initialize() - Initialize private asu_hash_ctx for hash operation.
130  * @ctx: crypto context used by the crypto_hash_*() functions
131  * Initialize hash operation request
132  *
133  * Return: TEE_SUCCESS or TEE_ERROR_BAD_PARAMETERS
134  */
135 
asu_hash_initialize(struct crypto_hash_ctx * ctx)136 static TEE_Result asu_hash_initialize(struct crypto_hash_ctx *ctx)
137 {
138 	to_hash_ctx(ctx)->shastart = ASU_SHA_START;
139 
140 	return TEE_SUCCESS;
141 }
142 
143 /**
144  * asu_sha_op() - Perform hash operation.
145  * @asu_hashctx:Request private hash context
146  * @op:		asu_sha_op_cmd parameters for fw engine
147  * @module:	Engine module ID
148  * @data:	Output digest received from engine
149  * Create request header, send and wait for result
150  * from engine.
151  *
152  * Return: TEE_SUCCESS or TEE_ERROR_GENERIC
153  */
154 
asu_sha_op(struct asu_hash_ctx * asu_hashctx,struct asu_sha_op_cmd * op,uint8_t module)155 static TEE_Result asu_sha_op(struct asu_hash_ctx *asu_hashctx,
156 			     struct asu_sha_op_cmd *op,
157 			     uint8_t module)
158 {
159 	TEE_Result ret = TEE_SUCCESS;
160 	uint32_t header = 0;
161 	uint32_t status = 0;
162 
163 	header = asu_create_header(ASU_SHA_OPERATION_CMD_ID,
164 				   asu_hashctx->uniqueid, module, 0U);
165 	ret = asu_update_queue_buffer_n_send_ipi(&asu_hashctx->cparam, op,
166 						 sizeof(*op), header,
167 						 &status);
168 	if (status) {
169 		EMSG("FW error 0x%x\n", status);
170 		ret = TEE_ERROR_GENERIC;
171 	}
172 
173 	return ret;
174 }
175 
176 /**
177  * asu_hash_update() - Send update request to engine.
178  * @asu_hashctx:Request private hash context
179  * @data:	Input data buffer
180  * @len:	Size of data buffer
181  * Send update request to engine
182  * from engine.
183  *
184  * Return: TEE_SUCCESS or TEE_ERROR_GENERIC
185  */
186 
asu_hash_update(struct asu_hash_ctx * asu_hashctx,uint8_t * data,size_t len)187 static TEE_Result asu_hash_update(struct asu_hash_ctx *asu_hashctx,
188 				  uint8_t *data, size_t len)
189 {
190 	TEE_Result ret = TEE_SUCCESS;
191 	struct asu_sha_op_cmd op = {};
192 	struct asu_client_params *cparam = NULL;
193 	uint32_t remaining = 0;
194 
195 	/* Inputs of client request */
196 	cparam = &asu_hashctx->cparam;
197 	cparam->priority = ASU_PRIORITY_HIGH;
198 	cparam->cbhandler = NULL;
199 
200 	/* Inputs of SHA request */
201 	cache_operation(TEE_CACHEFLUSH, data, len);
202 	op.hashaddr = 0;
203 	op.hashbufsize = 0;
204 	op.shamode = asu_hashctx->shamode;
205 	op.islast = 0;
206 	remaining = len;
207 	while (remaining) {
208 		op.datasize = MIN(remaining, ASU_DATA_CHUNK_LEN);
209 		op.opflags = ASU_SHA_UPDATE | asu_hashctx->shastart;
210 		op.dataaddr = virt_to_phys(data);
211 		remaining -= op.datasize;
212 		data += op.datasize;
213 		ret = asu_sha_op(asu_hashctx, &op, asu_hashctx->module);
214 		if (ret)
215 			break;
216 		asu_hashctx->shastart = 0;
217 	}
218 
219 	return ret;
220 }
221 
asu_hash_do_update(struct crypto_hash_ctx * ctx,const uint8_t * data,size_t len)222 static TEE_Result asu_hash_do_update(struct crypto_hash_ctx *ctx,
223 				     const uint8_t *data, size_t len)
224 {
225 	struct asu_hash_ctx *asu_hashctx = NULL;
226 
227 	if (!len) {
228 		DMSG("This is 0 len task, skip");
229 		return TEE_SUCCESS;
230 	}
231 
232 	if (!data && len) {
233 		EMSG("Invalid input parameters");
234 		return TEE_ERROR_BAD_PARAMETERS;
235 	}
236 
237 	asu_hashctx = to_hash_ctx(ctx);
238 	if (asu_hashctx->uniqueid == ASU_UNIQUE_ID_MAX)
239 		return TEE_ERROR_BAD_PARAMETERS;
240 
241 	return asu_hash_update(asu_hashctx, (uint8_t *)data, len);
242 }
243 
asu_hash_cb(void * cbrefptr,struct asu_resp_buf * resp_buf)244 static TEE_Result asu_hash_cb(void *cbrefptr, struct asu_resp_buf *resp_buf)
245 {
246 	struct asu_hash_cbctx *cbctx = NULL;
247 	uint8_t *src_addr = NULL;
248 
249 	cbctx = cbrefptr;
250 	src_addr = (uint8_t *)&resp_buf->arg[ASU_RESPONSE_BUFF_ADDR_INDEX];
251 	memcpy(cbctx->digest, src_addr, cbctx->len);
252 
253 	return TEE_SUCCESS;
254 }
255 
256 /**
257  * asu_hash_final() - Send final request to engine.
258  * @asu_hashctx:Request private hash context
259  * @digest:	Output digest buffer
260  * @len:	Size of digest buffer
261  *
262  * Send final request to engine and populate digest result
263  *
264  * Return: TEE_SUCCESS, TEE_ERROR_BAD_PARAMETERS or TEE_ERROR_GENERIC
265  */
266 
asu_hash_final(struct asu_hash_ctx * asu_hashctx,uint8_t * digest,size_t len)267 static TEE_Result asu_hash_final(struct asu_hash_ctx *asu_hashctx,
268 				 uint8_t *digest, size_t len)
269 {
270 	TEE_Result ret = TEE_SUCCESS;
271 	struct asu_sha_op_cmd op = {};
272 	struct asu_client_params *cparam = NULL;
273 	struct asu_hash_cbctx cbctx = {};
274 
275 	if (!digest || len == 0)
276 		return TEE_ERROR_BAD_PARAMETERS;
277 
278 	cbctx.digest = digest;
279 	cbctx.len = len;
280 	cparam = &asu_hashctx->cparam;
281 	cparam->priority = ASU_PRIORITY_HIGH;
282 	cparam->cbptr = &cbctx;
283 	cparam->cbhandler = asu_hash_cb;
284 
285 	/* Inputs of SHA request */
286 	op.dataaddr = 0;
287 	op.datasize = 0;
288 	op.hashaddr = UINT64_MAX;
289 	op.hashbufsize = len;
290 	if (asu_hashctx->shamode == ASU_SHA_MODE_SHA256)
291 		op.hashbufsize = ASU_SHA_256_HASH_LEN;
292 	else if (asu_hashctx->shamode == ASU_SHA_MODE_SHA384)
293 		op.hashbufsize = ASU_SHA_384_HASH_LEN;
294 	else if (asu_hashctx->shamode == ASU_SHA_MODE_SHA512)
295 		op.hashbufsize = ASU_SHA_512_HASH_LEN;
296 
297 	op.shamode = asu_hashctx->shamode;
298 	op.islast = 1;
299 	op.opflags = ASU_SHA_FINISH | asu_hashctx->shastart;
300 	ret = asu_sha_op(asu_hashctx, &op, asu_hashctx->module);
301 	cache_operation(TEE_CACHEFLUSH, digest, op.hashbufsize);
302 
303 	return ret;
304 }
305 
asu_hash_do_final(struct crypto_hash_ctx * ctx,uint8_t * digest,size_t len)306 static TEE_Result asu_hash_do_final(struct crypto_hash_ctx *ctx,
307 				    uint8_t *digest, size_t len)
308 {
309 	struct asu_hash_ctx *asu_hashctx = NULL;
310 
311 	asu_hashctx = to_hash_ctx(ctx);
312 
313 	return asu_hash_final(asu_hashctx, digest, len);
314 }
315 
316 /**
317  * asu_hash_ctx_free() - Free Private context.
318  * @crypto_hash_ctx: crypto context used by the crypto_hash_*() functions
319  * Release crypto engine and free private context memory.
320  *
321  * Return: void
322  */
323 
asu_hash_ctx_free(struct crypto_hash_ctx * ctx)324 static void asu_hash_ctx_free(struct crypto_hash_ctx *ctx)
325 {
326 	struct asu_hash_ctx *asu_hashctx = NULL;
327 
328 	asu_hashctx = to_hash_ctx(ctx);
329 	asu_free_unique_id(asu_hashctx->uniqueid);
330 	asu_hashctx->uniqueid = ASU_UNIQUE_ID_MAX;
331 	mutex_lock(&asu_shadev->engine_lock);
332 	if (asu_hashctx->module == ASU_MODULE_SHA2_ID) {
333 		assert(!asu_shadev->sha2_available);
334 		asu_shadev->sha2_available = true;
335 	} else if (asu_hashctx->module == ASU_MODULE_SHA3_ID) {
336 		assert(!asu_shadev->sha3_available);
337 		asu_shadev->sha3_available = true;
338 	}
339 	mutex_unlock(&asu_shadev->engine_lock);
340 	free(asu_hashctx);
341 }
342 
343 static const struct crypto_hash_ops asu_hash_ops = {
344 	.init = asu_hash_initialize,
345 	.update = asu_hash_do_update,
346 	.final = asu_hash_do_final,
347 	.free_ctx = asu_hash_ctx_free,
348 	/*
349 	 * Current engine does not support partial state copy operation.
350 	 */
351 	.copy_state = NULL,
352 };
353 
354 /*
355  * Returns the reference to the driver context
356  *
357  * @ctx  API Context
358  */
to_hash_ctx(struct crypto_hash_ctx * ctx)359 static struct asu_hash_ctx *to_hash_ctx(struct crypto_hash_ctx *ctx)
360 {
361 	assert(ctx && ctx->ops == &asu_hash_ops);
362 
363 	return container_of(ctx, struct asu_hash_ctx, hash_ctx);
364 }
365 
366 /**
367  * asu_hash_ctx_allocate() - Allocate Private context.
368  * @crypto_hash_ctx: crypto context used by the crypto_hash_*() functions
369  * @algo:	TEE algo type.
370  * Grab crypto engine and free private context memory.
371  *
372  * Return: TEE_SUCCESS, TEE_ERROR_BAD_PARAMETERS or TEE_ERROR_OUT_OF_MEMORY
373  */
374 
asu_hash_ctx_allocate(struct crypto_hash_ctx ** ctx,uint32_t algo)375 static TEE_Result asu_hash_ctx_allocate(struct crypto_hash_ctx **ctx,
376 					uint32_t algo)
377 {
378 	struct asu_hash_ctx *asu_hashctx = NULL;
379 	uint32_t module = 0;
380 	uint32_t shamode = 0;
381 	TEE_Result ret = TEE_SUCCESS;
382 
383 	ret = asu_hash_get_alg(algo, &module, &shamode);
384 	if (ret)
385 		return ret;
386 	mutex_lock(&asu_shadev->engine_lock);
387 	if (module == ASU_MODULE_SHA2_ID && asu_shadev->sha2_available) {
388 		asu_shadev->sha2_available = false;
389 	} else if (module == ASU_MODULE_SHA3_ID && asu_shadev->sha3_available) {
390 		asu_shadev->sha3_available = false;
391 	} else {
392 		mutex_unlock(&asu_shadev->engine_lock);
393 		return TEE_ERROR_NOT_IMPLEMENTED;
394 	}
395 	mutex_unlock(&asu_shadev->engine_lock);
396 
397 	asu_hashctx = calloc(1, sizeof(*asu_hashctx));
398 	if (!asu_hashctx) {
399 		EMSG("Fail to alloc hash");
400 		ret = TEE_ERROR_OUT_OF_MEMORY;
401 		goto free_dev_mem;
402 	}
403 
404 	asu_hashctx->module = module;
405 	asu_hashctx->shamode = shamode;
406 	asu_hashctx->uniqueid = asu_alloc_unique_id();
407 
408 	if (asu_hashctx->uniqueid == ASU_UNIQUE_ID_MAX) {
409 		EMSG("Fail to get unique ID");
410 		ret = TEE_ERROR_BAD_PARAMETERS;
411 		goto free_dev_mem;
412 	}
413 	asu_hashctx->hash_ctx.ops = &asu_hash_ops;
414 	*ctx = &asu_hashctx->hash_ctx;
415 
416 	return ret;
417 
418 free_dev_mem:
419 	mutex_lock(&asu_shadev->engine_lock);
420 	if (asu_hashctx->module == ASU_MODULE_SHA2_ID &&
421 	    !asu_shadev->sha2_available)
422 		asu_shadev->sha2_available = true;
423 	else if (asu_hashctx->module == ASU_MODULE_SHA3_ID &&
424 		 !asu_shadev->sha3_available)
425 		asu_shadev->sha3_available = true;
426 	mutex_unlock(&asu_shadev->engine_lock);
427 
428 	if (asu_hashctx)
429 		free(asu_hashctx);
430 
431 	return ret;
432 }
433 
asu_hash_init(void)434 static TEE_Result asu_hash_init(void)
435 {
436 	TEE_Result ret = TEE_SUCCESS;
437 
438 	asu_shadev = calloc(1, sizeof(*asu_shadev));
439 	mutex_init(&asu_shadev->engine_lock);
440 	asu_shadev->sha2_available = true;
441 	asu_shadev->sha3_available = true;
442 	ret = drvcrypt_register_hash(&asu_hash_ctx_allocate);
443 	if (ret)
444 		EMSG("ASU hash register to crypto fail ret=%#"PRIx32, ret);
445 
446 	return ret;
447 }
448 driver_init(asu_hash_init);
449