1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2b9eebfadSRuchika Gupta /*
3b9eebfadSRuchika Gupta * Copyright 2014 Freescale Semiconductor, Inc.
4b9eebfadSRuchika Gupta *
5b9eebfadSRuchika Gupta */
6b9eebfadSRuchika Gupta
7b9eebfadSRuchika Gupta #include <common.h>
8b9eebfadSRuchika Gupta #include <malloc.h>
9d7af2baaSBreno Lima #include <memalign.h>
10b9eebfadSRuchika Gupta #include "jobdesc.h"
11b9eebfadSRuchika Gupta #include "desc.h"
12b9eebfadSRuchika Gupta #include "jr.h"
1394e3c8c4Sgaurav rana #include "fsl_hash.h"
1494e3c8c4Sgaurav rana #include <hw_sha.h>
155d97dff0SMasahiro Yamada #include <linux/errno.h>
16b9eebfadSRuchika Gupta
17b9eebfadSRuchika Gupta #define CRYPTO_MAX_ALG_NAME 80
18b9eebfadSRuchika Gupta #define SHA1_DIGEST_SIZE 20
19b9eebfadSRuchika Gupta #define SHA256_DIGEST_SIZE 32
20b9eebfadSRuchika Gupta
21b9eebfadSRuchika Gupta struct caam_hash_template {
22b9eebfadSRuchika Gupta char name[CRYPTO_MAX_ALG_NAME];
23b9eebfadSRuchika Gupta unsigned int digestsize;
24b9eebfadSRuchika Gupta u32 alg_type;
25b9eebfadSRuchika Gupta };
26b9eebfadSRuchika Gupta
27b9eebfadSRuchika Gupta enum caam_hash_algos {
28b9eebfadSRuchika Gupta SHA1 = 0,
29b9eebfadSRuchika Gupta SHA256
30b9eebfadSRuchika Gupta };
31b9eebfadSRuchika Gupta
32b9eebfadSRuchika Gupta static struct caam_hash_template driver_hash[] = {
33b9eebfadSRuchika Gupta {
34b9eebfadSRuchika Gupta .name = "sha1",
35b9eebfadSRuchika Gupta .digestsize = SHA1_DIGEST_SIZE,
36b9eebfadSRuchika Gupta .alg_type = OP_ALG_ALGSEL_SHA1,
37b9eebfadSRuchika Gupta },
38b9eebfadSRuchika Gupta {
39b9eebfadSRuchika Gupta .name = "sha256",
40b9eebfadSRuchika Gupta .digestsize = SHA256_DIGEST_SIZE,
41b9eebfadSRuchika Gupta .alg_type = OP_ALG_ALGSEL_SHA256,
42b9eebfadSRuchika Gupta },
43b9eebfadSRuchika Gupta };
44b9eebfadSRuchika Gupta
get_hash_type(struct hash_algo * algo)4594e3c8c4Sgaurav rana static enum caam_hash_algos get_hash_type(struct hash_algo *algo)
4694e3c8c4Sgaurav rana {
4794e3c8c4Sgaurav rana if (!strcmp(algo->name, driver_hash[SHA1].name))
4894e3c8c4Sgaurav rana return SHA1;
4994e3c8c4Sgaurav rana else
5094e3c8c4Sgaurav rana return SHA256;
5194e3c8c4Sgaurav rana }
5294e3c8c4Sgaurav rana
5394e3c8c4Sgaurav rana /* Create the context for progressive hashing using h/w acceleration.
5494e3c8c4Sgaurav rana *
5594e3c8c4Sgaurav rana * @ctxp: Pointer to the pointer of the context for hashing
5694e3c8c4Sgaurav rana * @caam_algo: Enum for SHA1 or SHA256
5794e3c8c4Sgaurav rana * @return 0 if ok, -ENOMEM on error
5894e3c8c4Sgaurav rana */
caam_hash_init(void ** ctxp,enum caam_hash_algos caam_algo)5994e3c8c4Sgaurav rana static int caam_hash_init(void **ctxp, enum caam_hash_algos caam_algo)
6094e3c8c4Sgaurav rana {
6194e3c8c4Sgaurav rana *ctxp = calloc(1, sizeof(struct sha_ctx));
6294e3c8c4Sgaurav rana if (*ctxp == NULL) {
6394e3c8c4Sgaurav rana debug("Cannot allocate memory for context\n");
6494e3c8c4Sgaurav rana return -ENOMEM;
6594e3c8c4Sgaurav rana }
6694e3c8c4Sgaurav rana return 0;
6794e3c8c4Sgaurav rana }
6894e3c8c4Sgaurav rana
6994e3c8c4Sgaurav rana /*
7094e3c8c4Sgaurav rana * Update sg table for progressive hashing using h/w acceleration
7194e3c8c4Sgaurav rana *
7294e3c8c4Sgaurav rana * The context is freed by this function if an error occurs.
7394e3c8c4Sgaurav rana * We support at most 32 Scatter/Gather Entries.
7494e3c8c4Sgaurav rana *
7594e3c8c4Sgaurav rana * @hash_ctx: Pointer to the context for hashing
7694e3c8c4Sgaurav rana * @buf: Pointer to the buffer being hashed
7794e3c8c4Sgaurav rana * @size: Size of the buffer being hashed
7894e3c8c4Sgaurav rana * @is_last: 1 if this is the last update; 0 otherwise
7994e3c8c4Sgaurav rana * @caam_algo: Enum for SHA1 or SHA256
8094e3c8c4Sgaurav rana * @return 0 if ok, -EINVAL on error
8194e3c8c4Sgaurav rana */
caam_hash_update(void * hash_ctx,const void * buf,unsigned int size,int is_last,enum caam_hash_algos caam_algo)8294e3c8c4Sgaurav rana static int caam_hash_update(void *hash_ctx, const void *buf,
8394e3c8c4Sgaurav rana unsigned int size, int is_last,
8494e3c8c4Sgaurav rana enum caam_hash_algos caam_algo)
8594e3c8c4Sgaurav rana {
8694e3c8c4Sgaurav rana uint32_t final = 0;
87f59e69cbSAneesh Bansal phys_addr_t addr = virt_to_phys((void *)buf);
8894e3c8c4Sgaurav rana struct sha_ctx *ctx = hash_ctx;
8994e3c8c4Sgaurav rana
9094e3c8c4Sgaurav rana if (ctx->sg_num >= MAX_SG_32) {
9194e3c8c4Sgaurav rana free(ctx);
9294e3c8c4Sgaurav rana return -EINVAL;
9394e3c8c4Sgaurav rana }
9494e3c8c4Sgaurav rana
9594e3c8c4Sgaurav rana #ifdef CONFIG_PHYS_64BIT
96f59e69cbSAneesh Bansal sec_out32(&ctx->sg_tbl[ctx->sg_num].addr_hi, (uint32_t)(addr >> 32));
9794e3c8c4Sgaurav rana #else
98f59e69cbSAneesh Bansal sec_out32(&ctx->sg_tbl[ctx->sg_num].addr_hi, 0x0);
9994e3c8c4Sgaurav rana #endif
100f59e69cbSAneesh Bansal sec_out32(&ctx->sg_tbl[ctx->sg_num].addr_lo, (uint32_t)addr);
10194e3c8c4Sgaurav rana
10294e3c8c4Sgaurav rana sec_out32(&ctx->sg_tbl[ctx->sg_num].len_flag,
10394e3c8c4Sgaurav rana (size & SG_ENTRY_LENGTH_MASK));
10494e3c8c4Sgaurav rana
10594e3c8c4Sgaurav rana ctx->sg_num++;
10694e3c8c4Sgaurav rana
10794e3c8c4Sgaurav rana if (is_last) {
10894e3c8c4Sgaurav rana final = sec_in32(&ctx->sg_tbl[ctx->sg_num - 1].len_flag) |
10994e3c8c4Sgaurav rana SG_ENTRY_FINAL_BIT;
11094e3c8c4Sgaurav rana sec_out32(&ctx->sg_tbl[ctx->sg_num - 1].len_flag, final);
11194e3c8c4Sgaurav rana }
11294e3c8c4Sgaurav rana
11394e3c8c4Sgaurav rana return 0;
11494e3c8c4Sgaurav rana }
11594e3c8c4Sgaurav rana
11694e3c8c4Sgaurav rana /*
11794e3c8c4Sgaurav rana * Perform progressive hashing on the given buffer and copy hash at
11894e3c8c4Sgaurav rana * destination buffer
11994e3c8c4Sgaurav rana *
12094e3c8c4Sgaurav rana * The context is freed after completion of hash operation.
12194e3c8c4Sgaurav rana *
12294e3c8c4Sgaurav rana * @hash_ctx: Pointer to the context for hashing
12394e3c8c4Sgaurav rana * @dest_buf: Pointer to the destination buffer where hash is to be copied
12494e3c8c4Sgaurav rana * @size: Size of the buffer being hashed
12594e3c8c4Sgaurav rana * @caam_algo: Enum for SHA1 or SHA256
12694e3c8c4Sgaurav rana * @return 0 if ok, -EINVAL on error
12794e3c8c4Sgaurav rana */
caam_hash_finish(void * hash_ctx,void * dest_buf,int size,enum caam_hash_algos caam_algo)12894e3c8c4Sgaurav rana static int caam_hash_finish(void *hash_ctx, void *dest_buf,
12994e3c8c4Sgaurav rana int size, enum caam_hash_algos caam_algo)
13094e3c8c4Sgaurav rana {
13194e3c8c4Sgaurav rana uint32_t len = 0;
13294e3c8c4Sgaurav rana struct sha_ctx *ctx = hash_ctx;
13394e3c8c4Sgaurav rana int i = 0, ret = 0;
13494e3c8c4Sgaurav rana
13594e3c8c4Sgaurav rana if (size < driver_hash[caam_algo].digestsize) {
13694e3c8c4Sgaurav rana free(ctx);
13794e3c8c4Sgaurav rana return -EINVAL;
13894e3c8c4Sgaurav rana }
13994e3c8c4Sgaurav rana
14094e3c8c4Sgaurav rana for (i = 0; i < ctx->sg_num; i++)
14194e3c8c4Sgaurav rana len += (sec_in32(&ctx->sg_tbl[i].len_flag) &
14294e3c8c4Sgaurav rana SG_ENTRY_LENGTH_MASK);
14394e3c8c4Sgaurav rana
14494e3c8c4Sgaurav rana inline_cnstr_jobdesc_hash(ctx->sha_desc, (uint8_t *)ctx->sg_tbl, len,
14594e3c8c4Sgaurav rana ctx->hash,
14694e3c8c4Sgaurav rana driver_hash[caam_algo].alg_type,
14794e3c8c4Sgaurav rana driver_hash[caam_algo].digestsize,
14894e3c8c4Sgaurav rana 1);
14994e3c8c4Sgaurav rana
15094e3c8c4Sgaurav rana ret = run_descriptor_jr(ctx->sha_desc);
15194e3c8c4Sgaurav rana
15294e3c8c4Sgaurav rana if (ret)
15394e3c8c4Sgaurav rana debug("Error %x\n", ret);
15494e3c8c4Sgaurav rana else
15594e3c8c4Sgaurav rana memcpy(dest_buf, ctx->hash, sizeof(ctx->hash));
15694e3c8c4Sgaurav rana
15794e3c8c4Sgaurav rana free(ctx);
15894e3c8c4Sgaurav rana return ret;
15994e3c8c4Sgaurav rana }
16094e3c8c4Sgaurav rana
caam_hash(const unsigned char * pbuf,unsigned int buf_len,unsigned char * pout,enum caam_hash_algos algo)161b9eebfadSRuchika Gupta int caam_hash(const unsigned char *pbuf, unsigned int buf_len,
162b9eebfadSRuchika Gupta unsigned char *pout, enum caam_hash_algos algo)
163b9eebfadSRuchika Gupta {
164b9eebfadSRuchika Gupta int ret = 0;
165b9eebfadSRuchika Gupta uint32_t *desc;
166d7af2baaSBreno Lima unsigned int size;
167b9eebfadSRuchika Gupta
168d7af2baaSBreno Lima desc = malloc_cache_aligned(sizeof(int) * MAX_CAAM_DESCSIZE);
169b9eebfadSRuchika Gupta if (!desc) {
170b9eebfadSRuchika Gupta debug("Not enough memory for descriptor allocation\n");
17194e3c8c4Sgaurav rana return -ENOMEM;
172b9eebfadSRuchika Gupta }
173b9eebfadSRuchika Gupta
174d7af2baaSBreno Lima if (!IS_ALIGNED((uintptr_t)pbuf, ARCH_DMA_MINALIGN) ||
175d7af2baaSBreno Lima !IS_ALIGNED((uintptr_t)pout, ARCH_DMA_MINALIGN)) {
176d7af2baaSBreno Lima puts("Error: Address arguments are not aligned\n");
177d7af2baaSBreno Lima return -EINVAL;
178d7af2baaSBreno Lima }
179d7af2baaSBreno Lima
180d7af2baaSBreno Lima size = ALIGN(buf_len, ARCH_DMA_MINALIGN);
181d7af2baaSBreno Lima flush_dcache_range((unsigned long)pbuf, (unsigned long)pbuf + size);
182d7af2baaSBreno Lima
183b9eebfadSRuchika Gupta inline_cnstr_jobdesc_hash(desc, pbuf, buf_len, pout,
184b9eebfadSRuchika Gupta driver_hash[algo].alg_type,
185b9eebfadSRuchika Gupta driver_hash[algo].digestsize,
186b9eebfadSRuchika Gupta 0);
187b9eebfadSRuchika Gupta
188d7af2baaSBreno Lima size = ALIGN(sizeof(int) * MAX_CAAM_DESCSIZE, ARCH_DMA_MINALIGN);
189d7af2baaSBreno Lima flush_dcache_range((unsigned long)desc, (unsigned long)desc + size);
190d7af2baaSBreno Lima
191b9eebfadSRuchika Gupta ret = run_descriptor_jr(desc);
192b9eebfadSRuchika Gupta
193d7af2baaSBreno Lima size = ALIGN(driver_hash[algo].digestsize, ARCH_DMA_MINALIGN);
194d7af2baaSBreno Lima invalidate_dcache_range((unsigned long)pout,
195d7af2baaSBreno Lima (unsigned long)pout + size);
196d7af2baaSBreno Lima
197b9eebfadSRuchika Gupta free(desc);
198b9eebfadSRuchika Gupta return ret;
199b9eebfadSRuchika Gupta }
200b9eebfadSRuchika Gupta
hw_sha256(const unsigned char * pbuf,unsigned int buf_len,unsigned char * pout,unsigned int chunk_size)201b9eebfadSRuchika Gupta void hw_sha256(const unsigned char *pbuf, unsigned int buf_len,
202b9eebfadSRuchika Gupta unsigned char *pout, unsigned int chunk_size)
203b9eebfadSRuchika Gupta {
204b9eebfadSRuchika Gupta if (caam_hash(pbuf, buf_len, pout, SHA256))
205b9eebfadSRuchika Gupta printf("CAAM was not setup properly or it is faulty\n");
206b9eebfadSRuchika Gupta }
207b9eebfadSRuchika Gupta
hw_sha1(const unsigned char * pbuf,unsigned int buf_len,unsigned char * pout,unsigned int chunk_size)208b9eebfadSRuchika Gupta void hw_sha1(const unsigned char *pbuf, unsigned int buf_len,
209b9eebfadSRuchika Gupta unsigned char *pout, unsigned int chunk_size)
210b9eebfadSRuchika Gupta {
211b9eebfadSRuchika Gupta if (caam_hash(pbuf, buf_len, pout, SHA1))
212b9eebfadSRuchika Gupta printf("CAAM was not setup properly or it is faulty\n");
213b9eebfadSRuchika Gupta }
21494e3c8c4Sgaurav rana
hw_sha_init(struct hash_algo * algo,void ** ctxp)21594e3c8c4Sgaurav rana int hw_sha_init(struct hash_algo *algo, void **ctxp)
21694e3c8c4Sgaurav rana {
21794e3c8c4Sgaurav rana return caam_hash_init(ctxp, get_hash_type(algo));
21894e3c8c4Sgaurav rana }
21994e3c8c4Sgaurav rana
hw_sha_update(struct hash_algo * algo,void * ctx,const void * buf,unsigned int size,int is_last)22094e3c8c4Sgaurav rana int hw_sha_update(struct hash_algo *algo, void *ctx, const void *buf,
22194e3c8c4Sgaurav rana unsigned int size, int is_last)
22294e3c8c4Sgaurav rana {
22394e3c8c4Sgaurav rana return caam_hash_update(ctx, buf, size, is_last, get_hash_type(algo));
22494e3c8c4Sgaurav rana }
22594e3c8c4Sgaurav rana
hw_sha_finish(struct hash_algo * algo,void * ctx,void * dest_buf,int size)22694e3c8c4Sgaurav rana int hw_sha_finish(struct hash_algo *algo, void *ctx, void *dest_buf,
22794e3c8c4Sgaurav rana int size)
22894e3c8c4Sgaurav rana {
22994e3c8c4Sgaurav rana return caam_hash_finish(ctx, dest_buf, size, get_hash_type(algo));
23094e3c8c4Sgaurav rana }
231