1061 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2// SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.3/*4 * Crypto driver to handle HASH algorithms using NVIDIA Security Engine.5 */6 7#include <linux/clk.h>8#include <linux/dma-mapping.h>9#include <linux/module.h>10#include <linux/of_device.h>11#include <linux/platform_device.h>12 13#include <crypto/aes.h>14#include <crypto/sha1.h>15#include <crypto/sha2.h>16#include <crypto/sha3.h>17#include <crypto/internal/des.h>18#include <crypto/engine.h>19#include <crypto/scatterwalk.h>20#include <crypto/internal/hash.h>21 22#include "tegra-se.h"23 24struct tegra_sha_ctx {25 struct tegra_se *se;26 unsigned int alg;27 bool fallback;28 u32 key_id;29 struct crypto_ahash *fallback_tfm;30};31 32struct tegra_sha_reqctx {33 struct scatterlist *src_sg;34 struct tegra_se_datbuf datbuf;35 struct tegra_se_datbuf residue;36 struct tegra_se_datbuf digest;37 unsigned int alg;38 unsigned int config;39 unsigned int total_len;40 unsigned int blk_size;41 unsigned int task;42 u32 key_id;43 u32 result[HASH_RESULT_REG_COUNT];44 struct ahash_request fallback_req;45};46 47static int tegra_sha_get_config(u32 alg)48{49 int cfg = 0;50 51 switch (alg) {52 case SE_ALG_SHA1:53 cfg |= SE_SHA_ENC_ALG_SHA;54 cfg |= SE_SHA_ENC_MODE_SHA1;55 break;56 57 case SE_ALG_HMAC_SHA224:58 cfg |= SE_SHA_ENC_ALG_HMAC;59 fallthrough;60 case SE_ALG_SHA224:61 cfg |= SE_SHA_ENC_ALG_SHA;62 cfg |= SE_SHA_ENC_MODE_SHA224;63 break;64 65 case SE_ALG_HMAC_SHA256:66 cfg |= SE_SHA_ENC_ALG_HMAC;67 fallthrough;68 case SE_ALG_SHA256:69 cfg |= SE_SHA_ENC_ALG_SHA;70 cfg |= SE_SHA_ENC_MODE_SHA256;71 break;72 73 case SE_ALG_HMAC_SHA384:74 cfg |= SE_SHA_ENC_ALG_HMAC;75 fallthrough;76 case SE_ALG_SHA384:77 cfg |= SE_SHA_ENC_ALG_SHA;78 cfg |= SE_SHA_ENC_MODE_SHA384;79 break;80 81 case SE_ALG_HMAC_SHA512:82 cfg |= SE_SHA_ENC_ALG_HMAC;83 fallthrough;84 case SE_ALG_SHA512:85 cfg |= SE_SHA_ENC_ALG_SHA;86 cfg |= SE_SHA_ENC_MODE_SHA512;87 break;88 89 case SE_ALG_SHA3_224:90 cfg |= SE_SHA_ENC_ALG_SHA;91 cfg |= SE_SHA_ENC_MODE_SHA3_224;92 break;93 case SE_ALG_SHA3_256:94 cfg |= SE_SHA_ENC_ALG_SHA;95 cfg |= SE_SHA_ENC_MODE_SHA3_256;96 break;97 case SE_ALG_SHA3_384:98 cfg |= SE_SHA_ENC_ALG_SHA;99 cfg |= SE_SHA_ENC_MODE_SHA3_384;100 break;101 case SE_ALG_SHA3_512:102 cfg |= SE_SHA_ENC_ALG_SHA;103 cfg |= SE_SHA_ENC_MODE_SHA3_512;104 break;105 default:106 return -EINVAL;107 }108 109 return cfg;110}111 112static int tegra_sha_fallback_init(struct ahash_request *req)113{114 struct tegra_sha_reqctx *rctx = ahash_request_ctx(req);115 struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);116 struct tegra_sha_ctx *ctx = crypto_ahash_ctx(tfm);117 118 ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);119 rctx->fallback_req.base.flags = req->base.flags &120 CRYPTO_TFM_REQ_MAY_SLEEP;121 122 return crypto_ahash_init(&rctx->fallback_req);123}124 125static int tegra_sha_fallback_update(struct ahash_request *req)126{127 struct tegra_sha_reqctx *rctx = ahash_request_ctx(req);128 struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);129 struct tegra_sha_ctx *ctx = crypto_ahash_ctx(tfm);130 131 ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);132 rctx->fallback_req.base.flags = req->base.flags &133 CRYPTO_TFM_REQ_MAY_SLEEP;134 rctx->fallback_req.nbytes = req->nbytes;135 rctx->fallback_req.src = req->src;136 137 return crypto_ahash_update(&rctx->fallback_req);138}139 140static int tegra_sha_fallback_final(struct ahash_request *req)141{142 struct tegra_sha_reqctx *rctx = ahash_request_ctx(req);143 struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);144 struct tegra_sha_ctx *ctx = crypto_ahash_ctx(tfm);145 146 ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);147 rctx->fallback_req.base.flags = req->base.flags &148 CRYPTO_TFM_REQ_MAY_SLEEP;149 rctx->fallback_req.result = req->result;150 151 return crypto_ahash_final(&rctx->fallback_req);152}153 154static int tegra_sha_fallback_finup(struct ahash_request *req)155{156 struct tegra_sha_reqctx *rctx = ahash_request_ctx(req);157 struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);158 struct tegra_sha_ctx *ctx = crypto_ahash_ctx(tfm);159 160 ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);161 rctx->fallback_req.base.flags = req->base.flags &162 CRYPTO_TFM_REQ_MAY_SLEEP;163 164 rctx->fallback_req.nbytes = req->nbytes;165 rctx->fallback_req.src = req->src;166 rctx->fallback_req.result = req->result;167 168 return crypto_ahash_finup(&rctx->fallback_req);169}170 171static int tegra_sha_fallback_digest(struct ahash_request *req)172{173 struct tegra_sha_reqctx *rctx = ahash_request_ctx(req);174 struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);175 struct tegra_sha_ctx *ctx = crypto_ahash_ctx(tfm);176 177 ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);178 rctx->fallback_req.base.flags = req->base.flags &179 CRYPTO_TFM_REQ_MAY_SLEEP;180 181 rctx->fallback_req.nbytes = req->nbytes;182 rctx->fallback_req.src = req->src;183 rctx->fallback_req.result = req->result;184 185 return crypto_ahash_digest(&rctx->fallback_req);186}187 188static int tegra_sha_fallback_import(struct ahash_request *req, const void *in)189{190 struct tegra_sha_reqctx *rctx = ahash_request_ctx(req);191 struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);192 struct tegra_sha_ctx *ctx = crypto_ahash_ctx(tfm);193 194 ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);195 rctx->fallback_req.base.flags = req->base.flags &196 CRYPTO_TFM_REQ_MAY_SLEEP;197 198 return crypto_ahash_import(&rctx->fallback_req, in);199}200 201static int tegra_sha_fallback_export(struct ahash_request *req, void *out)202{203 struct tegra_sha_reqctx *rctx = ahash_request_ctx(req);204 struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);205 struct tegra_sha_ctx *ctx = crypto_ahash_ctx(tfm);206 207 ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);208 rctx->fallback_req.base.flags = req->base.flags &209 CRYPTO_TFM_REQ_MAY_SLEEP;210 211 return crypto_ahash_export(&rctx->fallback_req, out);212}213 214static int tegra_sha_prep_cmd(struct tegra_se *se, u32 *cpuvaddr,215 struct tegra_sha_reqctx *rctx)216{217 u64 msg_len, msg_left;218 int i = 0;219 220 msg_len = rctx->total_len * 8;221 msg_left = rctx->datbuf.size * 8;222 223 /*224 * If IN_ADDR_HI_0.SZ > SHA_MSG_LEFT_[0-3] to the HASH engine,225 * HW treats it as the last buffer and process the data.226 * Therefore, add an extra byte to msg_left if it is not the227 * last buffer.228 */229 if (rctx->task & SHA_UPDATE) {230 msg_left += 8;231 msg_len += 8;232 }233 234 cpuvaddr[i++] = host1x_opcode_setpayload(8);235 cpuvaddr[i++] = se_host1x_opcode_incr_w(SE_SHA_MSG_LENGTH);236 cpuvaddr[i++] = lower_32_bits(msg_len);237 cpuvaddr[i++] = upper_32_bits(msg_len);238 cpuvaddr[i++] = 0;239 cpuvaddr[i++] = 0;240 cpuvaddr[i++] = lower_32_bits(msg_left);241 cpuvaddr[i++] = upper_32_bits(msg_left);242 cpuvaddr[i++] = 0;243 cpuvaddr[i++] = 0;244 cpuvaddr[i++] = host1x_opcode_setpayload(6);245 cpuvaddr[i++] = se_host1x_opcode_incr_w(SE_SHA_CFG);246 cpuvaddr[i++] = rctx->config;247 248 if (rctx->task & SHA_FIRST) {249 cpuvaddr[i++] = SE_SHA_TASK_HASH_INIT;250 rctx->task &= ~SHA_FIRST;251 } else {252 cpuvaddr[i++] = 0;253 }254 255 cpuvaddr[i++] = rctx->datbuf.addr;256 cpuvaddr[i++] = (u32)(SE_ADDR_HI_MSB(upper_32_bits(rctx->datbuf.addr)) |257 SE_ADDR_HI_SZ(rctx->datbuf.size));258 cpuvaddr[i++] = rctx->digest.addr;259 cpuvaddr[i++] = (u32)(SE_ADDR_HI_MSB(upper_32_bits(rctx->digest.addr)) |260 SE_ADDR_HI_SZ(rctx->digest.size));261 if (rctx->key_id) {262 cpuvaddr[i++] = host1x_opcode_setpayload(1);263 cpuvaddr[i++] = se_host1x_opcode_nonincr_w(SE_SHA_CRYPTO_CFG);264 cpuvaddr[i++] = SE_AES_KEY_INDEX(rctx->key_id);265 }266 267 cpuvaddr[i++] = host1x_opcode_setpayload(1);268 cpuvaddr[i++] = se_host1x_opcode_nonincr_w(SE_SHA_OPERATION);269 cpuvaddr[i++] = SE_SHA_OP_WRSTALL |270 SE_SHA_OP_START |271 SE_SHA_OP_LASTBUF;272 cpuvaddr[i++] = se_host1x_opcode_nonincr(host1x_uclass_incr_syncpt_r(), 1);273 cpuvaddr[i++] = host1x_uclass_incr_syncpt_cond_f(1) |274 host1x_uclass_incr_syncpt_indx_f(se->syncpt_id);275 276 dev_dbg(se->dev, "msg len %llu msg left %llu cfg %#x",277 msg_len, msg_left, rctx->config);278 279 return i;280}281 282static void tegra_sha_copy_hash_result(struct tegra_se *se, struct tegra_sha_reqctx *rctx)283{284 int i;285 286 for (i = 0; i < HASH_RESULT_REG_COUNT; i++)287 rctx->result[i] = readl(se->base + se->hw->regs->result + (i * 4));288}289 290static void tegra_sha_paste_hash_result(struct tegra_se *se, struct tegra_sha_reqctx *rctx)291{292 int i;293 294 for (i = 0; i < HASH_RESULT_REG_COUNT; i++)295 writel(rctx->result[i],296 se->base + se->hw->regs->result + (i * 4));297}298 299static int tegra_sha_do_update(struct ahash_request *req)300{301 struct tegra_sha_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req));302 struct tegra_sha_reqctx *rctx = ahash_request_ctx(req);303 unsigned int nblks, nresidue, size, ret;304 u32 *cpuvaddr = ctx->se->cmdbuf->addr;305 306 nresidue = (req->nbytes + rctx->residue.size) % rctx->blk_size;307 nblks = (req->nbytes + rctx->residue.size) / rctx->blk_size;308 309 /*310 * If nbytes is a multiple of block size and there is no residue,311 * then reserve the last block as residue during final() to process.312 */313 if (!nresidue && nblks) {314 nresidue = rctx->blk_size;315 nblks--;316 }317 318 rctx->src_sg = req->src;319 rctx->datbuf.size = (req->nbytes + rctx->residue.size) - nresidue;320 rctx->total_len += rctx->datbuf.size;321 322 /*323 * If nbytes are less than a block size, copy it residue and324 * return. The bytes will be processed in final()325 */326 if (nblks < 1) {327 scatterwalk_map_and_copy(rctx->residue.buf + rctx->residue.size,328 rctx->src_sg, 0, req->nbytes, 0);329 330 rctx->residue.size += req->nbytes;331 return 0;332 }333 334 /* Copy the previous residue first */335 if (rctx->residue.size)336 memcpy(rctx->datbuf.buf, rctx->residue.buf, rctx->residue.size);337 338 scatterwalk_map_and_copy(rctx->datbuf.buf + rctx->residue.size,339 rctx->src_sg, 0, req->nbytes - nresidue, 0);340 341 scatterwalk_map_and_copy(rctx->residue.buf, rctx->src_sg,342 req->nbytes - nresidue, nresidue, 0);343 344 /* Update residue value with the residue after current block */345 rctx->residue.size = nresidue;346 347 rctx->config = tegra_sha_get_config(rctx->alg) |348 SE_SHA_DST_HASH_REG;349 350 /*351 * If this is not the first 'update' call, paste the previous copied352 * intermediate results to the registers so that it gets picked up.353 * This is to support the import/export functionality.354 */355 if (!(rctx->task & SHA_FIRST))356 tegra_sha_paste_hash_result(ctx->se, rctx);357 358 size = tegra_sha_prep_cmd(ctx->se, cpuvaddr, rctx);359 360 ret = tegra_se_host1x_submit(ctx->se, size);361 362 /*363 * If this is not the final update, copy the intermediate results364 * from the registers so that it can be used in the next 'update'365 * call. This is to support the import/export functionality.366 */367 if (!(rctx->task & SHA_FINAL))368 tegra_sha_copy_hash_result(ctx->se, rctx);369 370 return ret;371}372 373static int tegra_sha_do_final(struct ahash_request *req)374{375 struct tegra_sha_reqctx *rctx = ahash_request_ctx(req);376 struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);377 struct tegra_sha_ctx *ctx = crypto_ahash_ctx(tfm);378 struct tegra_se *se = ctx->se;379 u32 *cpuvaddr = se->cmdbuf->addr;380 int size, ret = 0;381 382 memcpy(rctx->datbuf.buf, rctx->residue.buf, rctx->residue.size);383 rctx->datbuf.size = rctx->residue.size;384 rctx->total_len += rctx->residue.size;385 386 rctx->config = tegra_sha_get_config(rctx->alg) |387 SE_SHA_DST_MEMORY;388 389 size = tegra_sha_prep_cmd(se, cpuvaddr, rctx);390 391 ret = tegra_se_host1x_submit(se, size);392 if (ret)393 goto out;394 395 /* Copy result */396 memcpy(req->result, rctx->digest.buf, rctx->digest.size);397 398out:399 dma_free_coherent(se->dev, SE_SHA_BUFLEN,400 rctx->datbuf.buf, rctx->datbuf.addr);401 dma_free_coherent(se->dev, crypto_ahash_blocksize(tfm),402 rctx->residue.buf, rctx->residue.addr);403 dma_free_coherent(se->dev, rctx->digest.size, rctx->digest.buf,404 rctx->digest.addr);405 return ret;406}407 408static int tegra_sha_do_one_req(struct crypto_engine *engine, void *areq)409{410 struct ahash_request *req = ahash_request_cast(areq);411 struct tegra_sha_reqctx *rctx = ahash_request_ctx(req);412 struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);413 struct tegra_sha_ctx *ctx = crypto_ahash_ctx(tfm);414 struct tegra_se *se = ctx->se;415 int ret = 0;416 417 if (rctx->task & SHA_UPDATE) {418 ret = tegra_sha_do_update(req);419 rctx->task &= ~SHA_UPDATE;420 }421 422 if (rctx->task & SHA_FINAL) {423 ret = tegra_sha_do_final(req);424 rctx->task &= ~SHA_FINAL;425 }426 427 crypto_finalize_hash_request(se->engine, req, ret);428 429 return 0;430}431 432static void tegra_sha_init_fallback(struct crypto_ahash *tfm, struct tegra_sha_ctx *ctx,433 const char *algname)434{435 unsigned int statesize;436 437 ctx->fallback_tfm = crypto_alloc_ahash(algname, 0, CRYPTO_ALG_ASYNC |438 CRYPTO_ALG_NEED_FALLBACK);439 440 if (IS_ERR(ctx->fallback_tfm)) {441 dev_warn(ctx->se->dev,442 "failed to allocate fallback for %s\n", algname);443 ctx->fallback_tfm = NULL;444 return;445 }446 447 statesize = crypto_ahash_statesize(ctx->fallback_tfm);448 449 if (statesize > sizeof(struct tegra_sha_reqctx))450 crypto_ahash_set_statesize(tfm, statesize);451 452 /* Update reqsize if fallback is added */453 crypto_ahash_set_reqsize(tfm,454 sizeof(struct tegra_sha_reqctx) +455 crypto_ahash_reqsize(ctx->fallback_tfm));456}457 458static int tegra_sha_cra_init(struct crypto_tfm *tfm)459{460 struct tegra_sha_ctx *ctx = crypto_tfm_ctx(tfm);461 struct crypto_ahash *ahash_tfm = __crypto_ahash_cast(tfm);462 struct ahash_alg *alg = __crypto_ahash_alg(tfm->__crt_alg);463 struct tegra_se_alg *se_alg;464 const char *algname;465 int ret;466 467 algname = crypto_tfm_alg_name(tfm);468 se_alg = container_of(alg, struct tegra_se_alg, alg.ahash.base);469 470 crypto_ahash_set_reqsize(ahash_tfm, sizeof(struct tegra_sha_reqctx));471 472 ctx->se = se_alg->se_dev;473 ctx->fallback = false;474 ctx->key_id = 0;475 476 ret = se_algname_to_algid(algname);477 if (ret < 0) {478 dev_err(ctx->se->dev, "invalid algorithm\n");479 return ret;480 }481 482 if (se_alg->alg_base)483 tegra_sha_init_fallback(ahash_tfm, ctx, algname);484 485 ctx->alg = ret;486 487 return 0;488}489 490static void tegra_sha_cra_exit(struct crypto_tfm *tfm)491{492 struct tegra_sha_ctx *ctx = crypto_tfm_ctx(tfm);493 494 if (ctx->fallback_tfm)495 crypto_free_ahash(ctx->fallback_tfm);496 497 tegra_key_invalidate(ctx->se, ctx->key_id, ctx->alg);498}499 500static int tegra_sha_init(struct ahash_request *req)501{502 struct tegra_sha_reqctx *rctx = ahash_request_ctx(req);503 struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);504 struct tegra_sha_ctx *ctx = crypto_ahash_ctx(tfm);505 struct tegra_se *se = ctx->se;506 507 if (ctx->fallback)508 return tegra_sha_fallback_init(req);509 510 rctx->total_len = 0;511 rctx->datbuf.size = 0;512 rctx->residue.size = 0;513 rctx->key_id = ctx->key_id;514 rctx->task = SHA_FIRST;515 rctx->alg = ctx->alg;516 rctx->blk_size = crypto_ahash_blocksize(tfm);517 rctx->digest.size = crypto_ahash_digestsize(tfm);518 519 rctx->digest.buf = dma_alloc_coherent(se->dev, rctx->digest.size,520 &rctx->digest.addr, GFP_KERNEL);521 if (!rctx->digest.buf)522 goto digbuf_fail;523 524 rctx->residue.buf = dma_alloc_coherent(se->dev, rctx->blk_size,525 &rctx->residue.addr, GFP_KERNEL);526 if (!rctx->residue.buf)527 goto resbuf_fail;528 529 rctx->datbuf.buf = dma_alloc_coherent(se->dev, SE_SHA_BUFLEN,530 &rctx->datbuf.addr, GFP_KERNEL);531 if (!rctx->datbuf.buf)532 goto datbuf_fail;533 534 return 0;535 536datbuf_fail:537 dma_free_coherent(se->dev, rctx->blk_size, rctx->residue.buf,538 rctx->residue.addr);539resbuf_fail:540 dma_free_coherent(se->dev, SE_SHA_BUFLEN, rctx->datbuf.buf,541 rctx->datbuf.addr);542digbuf_fail:543 return -ENOMEM;544}545 546static int tegra_hmac_fallback_setkey(struct tegra_sha_ctx *ctx, const u8 *key,547 unsigned int keylen)548{549 if (!ctx->fallback_tfm) {550 dev_dbg(ctx->se->dev, "invalid key length (%d)\n", keylen);551 return -EINVAL;552 }553 554 ctx->fallback = true;555 return crypto_ahash_setkey(ctx->fallback_tfm, key, keylen);556}557 558static int tegra_hmac_setkey(struct crypto_ahash *tfm, const u8 *key,559 unsigned int keylen)560{561 struct tegra_sha_ctx *ctx = crypto_ahash_ctx(tfm);562 563 if (aes_check_keylen(keylen))564 return tegra_hmac_fallback_setkey(ctx, key, keylen);565 566 ctx->fallback = false;567 568 return tegra_key_submit(ctx->se, key, keylen, ctx->alg, &ctx->key_id);569}570 571static int tegra_sha_update(struct ahash_request *req)572{573 struct tegra_sha_reqctx *rctx = ahash_request_ctx(req);574 struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);575 struct tegra_sha_ctx *ctx = crypto_ahash_ctx(tfm);576 577 if (ctx->fallback)578 return tegra_sha_fallback_update(req);579 580 rctx->task |= SHA_UPDATE;581 582 return crypto_transfer_hash_request_to_engine(ctx->se->engine, req);583}584 585static int tegra_sha_final(struct ahash_request *req)586{587 struct tegra_sha_reqctx *rctx = ahash_request_ctx(req);588 struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);589 struct tegra_sha_ctx *ctx = crypto_ahash_ctx(tfm);590 591 if (ctx->fallback)592 return tegra_sha_fallback_final(req);593 594 rctx->task |= SHA_FINAL;595 596 return crypto_transfer_hash_request_to_engine(ctx->se->engine, req);597}598 599static int tegra_sha_finup(struct ahash_request *req)600{601 struct tegra_sha_reqctx *rctx = ahash_request_ctx(req);602 struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);603 struct tegra_sha_ctx *ctx = crypto_ahash_ctx(tfm);604 605 if (ctx->fallback)606 return tegra_sha_fallback_finup(req);607 608 rctx->task |= SHA_UPDATE | SHA_FINAL;609 610 return crypto_transfer_hash_request_to_engine(ctx->se->engine, req);611}612 613static int tegra_sha_digest(struct ahash_request *req)614{615 struct tegra_sha_reqctx *rctx = ahash_request_ctx(req);616 struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);617 struct tegra_sha_ctx *ctx = crypto_ahash_ctx(tfm);618 619 if (ctx->fallback)620 return tegra_sha_fallback_digest(req);621 622 tegra_sha_init(req);623 rctx->task |= SHA_UPDATE | SHA_FINAL;624 625 return crypto_transfer_hash_request_to_engine(ctx->se->engine, req);626}627 628static int tegra_sha_export(struct ahash_request *req, void *out)629{630 struct tegra_sha_reqctx *rctx = ahash_request_ctx(req);631 struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);632 struct tegra_sha_ctx *ctx = crypto_ahash_ctx(tfm);633 634 if (ctx->fallback)635 return tegra_sha_fallback_export(req, out);636 637 memcpy(out, rctx, sizeof(*rctx));638 639 return 0;640}641 642static int tegra_sha_import(struct ahash_request *req, const void *in)643{644 struct tegra_sha_reqctx *rctx = ahash_request_ctx(req);645 struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);646 struct tegra_sha_ctx *ctx = crypto_ahash_ctx(tfm);647 648 if (ctx->fallback)649 return tegra_sha_fallback_import(req, in);650 651 memcpy(rctx, in, sizeof(*rctx));652 653 return 0;654}655 656static struct tegra_se_alg tegra_hash_algs[] = {657 {658 .alg.ahash.op.do_one_request = tegra_sha_do_one_req,659 .alg.ahash.base = {660 .init = tegra_sha_init,661 .update = tegra_sha_update,662 .final = tegra_sha_final,663 .finup = tegra_sha_finup,664 .digest = tegra_sha_digest,665 .export = tegra_sha_export,666 .import = tegra_sha_import,667 .halg.digestsize = SHA1_DIGEST_SIZE,668 .halg.statesize = sizeof(struct tegra_sha_reqctx),669 .halg.base = {670 .cra_name = "sha1",671 .cra_driver_name = "tegra-se-sha1",672 .cra_priority = 300,673 .cra_flags = CRYPTO_ALG_TYPE_AHASH,674 .cra_blocksize = SHA1_BLOCK_SIZE,675 .cra_ctxsize = sizeof(struct tegra_sha_ctx),676 .cra_alignmask = 0,677 .cra_module = THIS_MODULE,678 .cra_init = tegra_sha_cra_init,679 .cra_exit = tegra_sha_cra_exit,680 }681 }682 }, {683 .alg.ahash.op.do_one_request = tegra_sha_do_one_req,684 .alg.ahash.base = {685 .init = tegra_sha_init,686 .update = tegra_sha_update,687 .final = tegra_sha_final,688 .finup = tegra_sha_finup,689 .digest = tegra_sha_digest,690 .export = tegra_sha_export,691 .import = tegra_sha_import,692 .halg.digestsize = SHA224_DIGEST_SIZE,693 .halg.statesize = sizeof(struct tegra_sha_reqctx),694 .halg.base = {695 .cra_name = "sha224",696 .cra_driver_name = "tegra-se-sha224",697 .cra_priority = 300,698 .cra_flags = CRYPTO_ALG_TYPE_AHASH,699 .cra_blocksize = SHA224_BLOCK_SIZE,700 .cra_ctxsize = sizeof(struct tegra_sha_ctx),701 .cra_alignmask = 0,702 .cra_module = THIS_MODULE,703 .cra_init = tegra_sha_cra_init,704 .cra_exit = tegra_sha_cra_exit,705 }706 }707 }, {708 .alg.ahash.op.do_one_request = tegra_sha_do_one_req,709 .alg.ahash.base = {710 .init = tegra_sha_init,711 .update = tegra_sha_update,712 .final = tegra_sha_final,713 .finup = tegra_sha_finup,714 .digest = tegra_sha_digest,715 .export = tegra_sha_export,716 .import = tegra_sha_import,717 .halg.digestsize = SHA256_DIGEST_SIZE,718 .halg.statesize = sizeof(struct tegra_sha_reqctx),719 .halg.base = {720 .cra_name = "sha256",721 .cra_driver_name = "tegra-se-sha256",722 .cra_priority = 300,723 .cra_flags = CRYPTO_ALG_TYPE_AHASH,724 .cra_blocksize = SHA256_BLOCK_SIZE,725 .cra_ctxsize = sizeof(struct tegra_sha_ctx),726 .cra_alignmask = 0,727 .cra_module = THIS_MODULE,728 .cra_init = tegra_sha_cra_init,729 .cra_exit = tegra_sha_cra_exit,730 }731 }732 }, {733 .alg.ahash.op.do_one_request = tegra_sha_do_one_req,734 .alg.ahash.base = {735 .init = tegra_sha_init,736 .update = tegra_sha_update,737 .final = tegra_sha_final,738 .finup = tegra_sha_finup,739 .digest = tegra_sha_digest,740 .export = tegra_sha_export,741 .import = tegra_sha_import,742 .halg.digestsize = SHA384_DIGEST_SIZE,743 .halg.statesize = sizeof(struct tegra_sha_reqctx),744 .halg.base = {745 .cra_name = "sha384",746 .cra_driver_name = "tegra-se-sha384",747 .cra_priority = 300,748 .cra_flags = CRYPTO_ALG_TYPE_AHASH,749 .cra_blocksize = SHA384_BLOCK_SIZE,750 .cra_ctxsize = sizeof(struct tegra_sha_ctx),751 .cra_alignmask = 0,752 .cra_module = THIS_MODULE,753 .cra_init = tegra_sha_cra_init,754 .cra_exit = tegra_sha_cra_exit,755 }756 }757 }, {758 .alg.ahash.op.do_one_request = tegra_sha_do_one_req,759 .alg.ahash.base = {760 .init = tegra_sha_init,761 .update = tegra_sha_update,762 .final = tegra_sha_final,763 .finup = tegra_sha_finup,764 .digest = tegra_sha_digest,765 .export = tegra_sha_export,766 .import = tegra_sha_import,767 .halg.digestsize = SHA512_DIGEST_SIZE,768 .halg.statesize = sizeof(struct tegra_sha_reqctx),769 .halg.base = {770 .cra_name = "sha512",771 .cra_driver_name = "tegra-se-sha512",772 .cra_priority = 300,773 .cra_flags = CRYPTO_ALG_TYPE_AHASH,774 .cra_blocksize = SHA512_BLOCK_SIZE,775 .cra_ctxsize = sizeof(struct tegra_sha_ctx),776 .cra_alignmask = 0,777 .cra_module = THIS_MODULE,778 .cra_init = tegra_sha_cra_init,779 .cra_exit = tegra_sha_cra_exit,780 }781 }782 }, {783 .alg.ahash.op.do_one_request = tegra_sha_do_one_req,784 .alg.ahash.base = {785 .init = tegra_sha_init,786 .update = tegra_sha_update,787 .final = tegra_sha_final,788 .finup = tegra_sha_finup,789 .digest = tegra_sha_digest,790 .export = tegra_sha_export,791 .import = tegra_sha_import,792 .halg.digestsize = SHA3_224_DIGEST_SIZE,793 .halg.statesize = sizeof(struct tegra_sha_reqctx),794 .halg.base = {795 .cra_name = "sha3-224",796 .cra_driver_name = "tegra-se-sha3-224",797 .cra_priority = 300,798 .cra_flags = CRYPTO_ALG_TYPE_AHASH,799 .cra_blocksize = SHA3_224_BLOCK_SIZE,800 .cra_ctxsize = sizeof(struct tegra_sha_ctx),801 .cra_alignmask = 0,802 .cra_module = THIS_MODULE,803 .cra_init = tegra_sha_cra_init,804 .cra_exit = tegra_sha_cra_exit,805 }806 }807 }, {808 .alg.ahash.op.do_one_request = tegra_sha_do_one_req,809 .alg.ahash.base = {810 .init = tegra_sha_init,811 .update = tegra_sha_update,812 .final = tegra_sha_final,813 .finup = tegra_sha_finup,814 .digest = tegra_sha_digest,815 .export = tegra_sha_export,816 .import = tegra_sha_import,817 .halg.digestsize = SHA3_256_DIGEST_SIZE,818 .halg.statesize = sizeof(struct tegra_sha_reqctx),819 .halg.base = {820 .cra_name = "sha3-256",821 .cra_driver_name = "tegra-se-sha3-256",822 .cra_priority = 300,823 .cra_flags = CRYPTO_ALG_TYPE_AHASH,824 .cra_blocksize = SHA3_256_BLOCK_SIZE,825 .cra_ctxsize = sizeof(struct tegra_sha_ctx),826 .cra_alignmask = 0,827 .cra_module = THIS_MODULE,828 .cra_init = tegra_sha_cra_init,829 .cra_exit = tegra_sha_cra_exit,830 }831 }832 }, {833 .alg.ahash.op.do_one_request = tegra_sha_do_one_req,834 .alg.ahash.base = {835 .init = tegra_sha_init,836 .update = tegra_sha_update,837 .final = tegra_sha_final,838 .finup = tegra_sha_finup,839 .digest = tegra_sha_digest,840 .export = tegra_sha_export,841 .import = tegra_sha_import,842 .halg.digestsize = SHA3_384_DIGEST_SIZE,843 .halg.statesize = sizeof(struct tegra_sha_reqctx),844 .halg.base = {845 .cra_name = "sha3-384",846 .cra_driver_name = "tegra-se-sha3-384",847 .cra_priority = 300,848 .cra_flags = CRYPTO_ALG_TYPE_AHASH,849 .cra_blocksize = SHA3_384_BLOCK_SIZE,850 .cra_ctxsize = sizeof(struct tegra_sha_ctx),851 .cra_alignmask = 0,852 .cra_module = THIS_MODULE,853 .cra_init = tegra_sha_cra_init,854 .cra_exit = tegra_sha_cra_exit,855 }856 }857 }, {858 .alg.ahash.op.do_one_request = tegra_sha_do_one_req,859 .alg.ahash.base = {860 .init = tegra_sha_init,861 .update = tegra_sha_update,862 .final = tegra_sha_final,863 .finup = tegra_sha_finup,864 .digest = tegra_sha_digest,865 .export = tegra_sha_export,866 .import = tegra_sha_import,867 .halg.digestsize = SHA3_512_DIGEST_SIZE,868 .halg.statesize = sizeof(struct tegra_sha_reqctx),869 .halg.base = {870 .cra_name = "sha3-512",871 .cra_driver_name = "tegra-se-sha3-512",872 .cra_priority = 300,873 .cra_flags = CRYPTO_ALG_TYPE_AHASH,874 .cra_blocksize = SHA3_512_BLOCK_SIZE,875 .cra_ctxsize = sizeof(struct tegra_sha_ctx),876 .cra_alignmask = 0,877 .cra_module = THIS_MODULE,878 .cra_init = tegra_sha_cra_init,879 .cra_exit = tegra_sha_cra_exit,880 }881 }882 }, {883 .alg_base = "sha224",884 .alg.ahash.op.do_one_request = tegra_sha_do_one_req,885 .alg.ahash.base = {886 .init = tegra_sha_init,887 .update = tegra_sha_update,888 .final = tegra_sha_final,889 .finup = tegra_sha_finup,890 .digest = tegra_sha_digest,891 .export = tegra_sha_export,892 .import = tegra_sha_import,893 .setkey = tegra_hmac_setkey,894 .halg.digestsize = SHA224_DIGEST_SIZE,895 .halg.statesize = sizeof(struct tegra_sha_reqctx),896 .halg.base = {897 .cra_name = "hmac(sha224)",898 .cra_driver_name = "tegra-se-hmac-sha224",899 .cra_priority = 300,900 .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_NEED_FALLBACK,901 .cra_blocksize = SHA224_BLOCK_SIZE,902 .cra_ctxsize = sizeof(struct tegra_sha_ctx),903 .cra_alignmask = 0,904 .cra_module = THIS_MODULE,905 .cra_init = tegra_sha_cra_init,906 .cra_exit = tegra_sha_cra_exit,907 }908 }909 }, {910 .alg_base = "sha256",911 .alg.ahash.op.do_one_request = tegra_sha_do_one_req,912 .alg.ahash.base = {913 .init = tegra_sha_init,914 .update = tegra_sha_update,915 .final = tegra_sha_final,916 .finup = tegra_sha_finup,917 .digest = tegra_sha_digest,918 .export = tegra_sha_export,919 .import = tegra_sha_import,920 .setkey = tegra_hmac_setkey,921 .halg.digestsize = SHA256_DIGEST_SIZE,922 .halg.statesize = sizeof(struct tegra_sha_reqctx),923 .halg.base = {924 .cra_name = "hmac(sha256)",925 .cra_driver_name = "tegra-se-hmac-sha256",926 .cra_priority = 300,927 .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_NEED_FALLBACK,928 .cra_blocksize = SHA256_BLOCK_SIZE,929 .cra_ctxsize = sizeof(struct tegra_sha_ctx),930 .cra_alignmask = 0,931 .cra_module = THIS_MODULE,932 .cra_init = tegra_sha_cra_init,933 .cra_exit = tegra_sha_cra_exit,934 }935 }936 }, {937 .alg_base = "sha384",938 .alg.ahash.op.do_one_request = tegra_sha_do_one_req,939 .alg.ahash.base = {940 .init = tegra_sha_init,941 .update = tegra_sha_update,942 .final = tegra_sha_final,943 .finup = tegra_sha_finup,944 .digest = tegra_sha_digest,945 .export = tegra_sha_export,946 .import = tegra_sha_import,947 .setkey = tegra_hmac_setkey,948 .halg.digestsize = SHA384_DIGEST_SIZE,949 .halg.statesize = sizeof(struct tegra_sha_reqctx),950 .halg.base = {951 .cra_name = "hmac(sha384)",952 .cra_driver_name = "tegra-se-hmac-sha384",953 .cra_priority = 300,954 .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_NEED_FALLBACK,955 .cra_blocksize = SHA384_BLOCK_SIZE,956 .cra_ctxsize = sizeof(struct tegra_sha_ctx),957 .cra_alignmask = 0,958 .cra_module = THIS_MODULE,959 .cra_init = tegra_sha_cra_init,960 .cra_exit = tegra_sha_cra_exit,961 }962 }963 }, {964 .alg_base = "sha512",965 .alg.ahash.op.do_one_request = tegra_sha_do_one_req,966 .alg.ahash.base = {967 .init = tegra_sha_init,968 .update = tegra_sha_update,969 .final = tegra_sha_final,970 .finup = tegra_sha_finup,971 .digest = tegra_sha_digest,972 .export = tegra_sha_export,973 .import = tegra_sha_import,974 .setkey = tegra_hmac_setkey,975 .halg.digestsize = SHA512_DIGEST_SIZE,976 .halg.statesize = sizeof(struct tegra_sha_reqctx),977 .halg.base = {978 .cra_name = "hmac(sha512)",979 .cra_driver_name = "tegra-se-hmac-sha512",980 .cra_priority = 300,981 .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_NEED_FALLBACK,982 .cra_blocksize = SHA512_BLOCK_SIZE,983 .cra_ctxsize = sizeof(struct tegra_sha_ctx),984 .cra_alignmask = 0,985 .cra_module = THIS_MODULE,986 .cra_init = tegra_sha_cra_init,987 .cra_exit = tegra_sha_cra_exit,988 }989 }990 }991};992 993static int tegra_hash_kac_manifest(u32 user, u32 alg, u32 keylen)994{995 int manifest;996 997 manifest = SE_KAC_USER_NS;998 999 switch (alg) {1000 case SE_ALG_HMAC_SHA224:1001 case SE_ALG_HMAC_SHA256:1002 case SE_ALG_HMAC_SHA384:1003 case SE_ALG_HMAC_SHA512:1004 manifest |= SE_KAC_HMAC;1005 break;1006 default:1007 return -EINVAL;1008 }1009 1010 switch (keylen) {1011 case AES_KEYSIZE_128:1012 manifest |= SE_KAC_SIZE_128;1013 break;1014 case AES_KEYSIZE_192:1015 manifest |= SE_KAC_SIZE_192;1016 break;1017 case AES_KEYSIZE_256:1018 default:1019 manifest |= SE_KAC_SIZE_256;1020 break;1021 }1022 1023 return manifest;1024}1025 1026int tegra_init_hash(struct tegra_se *se)1027{1028 struct ahash_engine_alg *alg;1029 int i, ret;1030 1031 se->manifest = tegra_hash_kac_manifest;1032 1033 for (i = 0; i < ARRAY_SIZE(tegra_hash_algs); i++) {1034 tegra_hash_algs[i].se_dev = se;1035 alg = &tegra_hash_algs[i].alg.ahash;1036 1037 ret = crypto_engine_register_ahash(alg);1038 if (ret) {1039 dev_err(se->dev, "failed to register %s\n",1040 alg->base.halg.base.cra_name);1041 goto sha_err;1042 }1043 }1044 1045 return 0;1046 1047sha_err:1048 while (i--)1049 crypto_engine_unregister_ahash(&tegra_hash_algs[i].alg.ahash);1050 1051 return ret;1052}1053 1054void tegra_deinit_hash(struct tegra_se *se)1055{1056 int i;1057 1058 for (i = 0; i < ARRAY_SIZE(tegra_hash_algs); i++)1059 crypto_engine_unregister_ahash(&tegra_hash_algs[i].alg.ahash);1060}1061