xref: /openbmc/u-boot/drivers/crypto/fsl/fsl_hash.c (revision e8f80a5a)
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