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