xref: /openbmc/linux/arch/sparc/crypto/aes_glue.c (revision 09c434b8)
109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
29bf4852dSDavid S. Miller /* Glue code for AES encryption optimized for sparc64 crypto opcodes.
39bf4852dSDavid S. Miller  *
49bf4852dSDavid S. Miller  * This is based largely upon arch/x86/crypto/aesni-intel_glue.c
59bf4852dSDavid S. Miller  *
69bf4852dSDavid S. Miller  * Copyright (C) 2008, Intel Corp.
79bf4852dSDavid S. Miller  *    Author: Huang Ying <ying.huang@intel.com>
89bf4852dSDavid S. Miller  *
99bf4852dSDavid S. Miller  * Added RFC4106 AES-GCM support for 128-bit keys under the AEAD
109bf4852dSDavid S. Miller  * interface for 64-bit kernels.
119bf4852dSDavid S. Miller  *    Authors: Adrian Hoban <adrian.hoban@intel.com>
129bf4852dSDavid S. Miller  *             Gabriele Paoloni <gabriele.paoloni@intel.com>
139bf4852dSDavid S. Miller  *             Tadeusz Struk (tadeusz.struk@intel.com)
149bf4852dSDavid S. Miller  *             Aidan O'Mahony (aidan.o.mahony@intel.com)
159bf4852dSDavid S. Miller  *    Copyright (c) 2010, Intel Corporation.
169bf4852dSDavid S. Miller  */
179bf4852dSDavid S. Miller 
1871741680SDavid S. Miller #define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
1971741680SDavid S. Miller 
209bf4852dSDavid S. Miller #include <linux/crypto.h>
219bf4852dSDavid S. Miller #include <linux/init.h>
229bf4852dSDavid S. Miller #include <linux/module.h>
239bf4852dSDavid S. Miller #include <linux/mm.h>
249bf4852dSDavid S. Miller #include <linux/types.h>
259bf4852dSDavid S. Miller #include <crypto/algapi.h>
269bf4852dSDavid S. Miller #include <crypto/aes.h>
279bf4852dSDavid S. Miller 
289bf4852dSDavid S. Miller #include <asm/fpumacro.h>
299bf4852dSDavid S. Miller #include <asm/pstate.h>
309bf4852dSDavid S. Miller #include <asm/elf.h>
319bf4852dSDavid S. Miller 
3210803624SDavid S. Miller #include "opcodes.h"
3310803624SDavid S. Miller 
340bdcaf74SDavid S. Miller struct aes_ops {
350bdcaf74SDavid S. Miller 	void (*encrypt)(const u64 *key, const u32 *input, u32 *output);
360bdcaf74SDavid S. Miller 	void (*decrypt)(const u64 *key, const u32 *input, u32 *output);
370bdcaf74SDavid S. Miller 	void (*load_encrypt_keys)(const u64 *key);
380bdcaf74SDavid S. Miller 	void (*load_decrypt_keys)(const u64 *key);
390bdcaf74SDavid S. Miller 	void (*ecb_encrypt)(const u64 *key, const u64 *input, u64 *output,
400bdcaf74SDavid S. Miller 			    unsigned int len);
410bdcaf74SDavid S. Miller 	void (*ecb_decrypt)(const u64 *key, const u64 *input, u64 *output,
420bdcaf74SDavid S. Miller 			    unsigned int len);
430bdcaf74SDavid S. Miller 	void (*cbc_encrypt)(const u64 *key, const u64 *input, u64 *output,
440bdcaf74SDavid S. Miller 			    unsigned int len, u64 *iv);
450bdcaf74SDavid S. Miller 	void (*cbc_decrypt)(const u64 *key, const u64 *input, u64 *output,
460bdcaf74SDavid S. Miller 			    unsigned int len, u64 *iv);
479fd130ecSDavid S. Miller 	void (*ctr_crypt)(const u64 *key, const u64 *input, u64 *output,
489fd130ecSDavid S. Miller 			  unsigned int len, u64 *iv);
490bdcaf74SDavid S. Miller };
500bdcaf74SDavid S. Miller 
519bf4852dSDavid S. Miller struct crypto_sparc64_aes_ctx {
520bdcaf74SDavid S. Miller 	struct aes_ops *ops;
539bf4852dSDavid S. Miller 	u64 key[AES_MAX_KEYLENGTH / sizeof(u64)];
549bf4852dSDavid S. Miller 	u32 key_length;
559bf4852dSDavid S. Miller 	u32 expanded_key_length;
569bf4852dSDavid S. Miller };
579bf4852dSDavid S. Miller 
580bdcaf74SDavid S. Miller extern void aes_sparc64_encrypt_128(const u64 *key, const u32 *input,
590bdcaf74SDavid S. Miller 				    u32 *output);
600bdcaf74SDavid S. Miller extern void aes_sparc64_encrypt_192(const u64 *key, const u32 *input,
610bdcaf74SDavid S. Miller 				    u32 *output);
620bdcaf74SDavid S. Miller extern void aes_sparc64_encrypt_256(const u64 *key, const u32 *input,
630bdcaf74SDavid S. Miller 				    u32 *output);
640bdcaf74SDavid S. Miller 
650bdcaf74SDavid S. Miller extern void aes_sparc64_decrypt_128(const u64 *key, const u32 *input,
660bdcaf74SDavid S. Miller 				    u32 *output);
670bdcaf74SDavid S. Miller extern void aes_sparc64_decrypt_192(const u64 *key, const u32 *input,
680bdcaf74SDavid S. Miller 				    u32 *output);
690bdcaf74SDavid S. Miller extern void aes_sparc64_decrypt_256(const u64 *key, const u32 *input,
700bdcaf74SDavid S. Miller 				    u32 *output);
710bdcaf74SDavid S. Miller 
720bdcaf74SDavid S. Miller extern void aes_sparc64_load_encrypt_keys_128(const u64 *key);
730bdcaf74SDavid S. Miller extern void aes_sparc64_load_encrypt_keys_192(const u64 *key);
740bdcaf74SDavid S. Miller extern void aes_sparc64_load_encrypt_keys_256(const u64 *key);
750bdcaf74SDavid S. Miller 
760bdcaf74SDavid S. Miller extern void aes_sparc64_load_decrypt_keys_128(const u64 *key);
770bdcaf74SDavid S. Miller extern void aes_sparc64_load_decrypt_keys_192(const u64 *key);
780bdcaf74SDavid S. Miller extern void aes_sparc64_load_decrypt_keys_256(const u64 *key);
790bdcaf74SDavid S. Miller 
800bdcaf74SDavid S. Miller extern void aes_sparc64_ecb_encrypt_128(const u64 *key, const u64 *input,
810bdcaf74SDavid S. Miller 					u64 *output, unsigned int len);
820bdcaf74SDavid S. Miller extern void aes_sparc64_ecb_encrypt_192(const u64 *key, const u64 *input,
830bdcaf74SDavid S. Miller 					u64 *output, unsigned int len);
840bdcaf74SDavid S. Miller extern void aes_sparc64_ecb_encrypt_256(const u64 *key, const u64 *input,
850bdcaf74SDavid S. Miller 					u64 *output, unsigned int len);
860bdcaf74SDavid S. Miller 
870bdcaf74SDavid S. Miller extern void aes_sparc64_ecb_decrypt_128(const u64 *key, const u64 *input,
880bdcaf74SDavid S. Miller 					u64 *output, unsigned int len);
890bdcaf74SDavid S. Miller extern void aes_sparc64_ecb_decrypt_192(const u64 *key, const u64 *input,
900bdcaf74SDavid S. Miller 					u64 *output, unsigned int len);
910bdcaf74SDavid S. Miller extern void aes_sparc64_ecb_decrypt_256(const u64 *key, const u64 *input,
920bdcaf74SDavid S. Miller 					u64 *output, unsigned int len);
930bdcaf74SDavid S. Miller 
940bdcaf74SDavid S. Miller extern void aes_sparc64_cbc_encrypt_128(const u64 *key, const u64 *input,
950bdcaf74SDavid S. Miller 					u64 *output, unsigned int len,
960bdcaf74SDavid S. Miller 					u64 *iv);
970bdcaf74SDavid S. Miller 
980bdcaf74SDavid S. Miller extern void aes_sparc64_cbc_encrypt_192(const u64 *key, const u64 *input,
990bdcaf74SDavid S. Miller 					u64 *output, unsigned int len,
1000bdcaf74SDavid S. Miller 					u64 *iv);
1010bdcaf74SDavid S. Miller 
1020bdcaf74SDavid S. Miller extern void aes_sparc64_cbc_encrypt_256(const u64 *key, const u64 *input,
1030bdcaf74SDavid S. Miller 					u64 *output, unsigned int len,
1040bdcaf74SDavid S. Miller 					u64 *iv);
1050bdcaf74SDavid S. Miller 
1060bdcaf74SDavid S. Miller extern void aes_sparc64_cbc_decrypt_128(const u64 *key, const u64 *input,
1070bdcaf74SDavid S. Miller 					u64 *output, unsigned int len,
1080bdcaf74SDavid S. Miller 					u64 *iv);
1090bdcaf74SDavid S. Miller 
1100bdcaf74SDavid S. Miller extern void aes_sparc64_cbc_decrypt_192(const u64 *key, const u64 *input,
1110bdcaf74SDavid S. Miller 					u64 *output, unsigned int len,
1120bdcaf74SDavid S. Miller 					u64 *iv);
1130bdcaf74SDavid S. Miller 
1140bdcaf74SDavid S. Miller extern void aes_sparc64_cbc_decrypt_256(const u64 *key, const u64 *input,
1150bdcaf74SDavid S. Miller 					u64 *output, unsigned int len,
1160bdcaf74SDavid S. Miller 					u64 *iv);
1170bdcaf74SDavid S. Miller 
1189fd130ecSDavid S. Miller extern void aes_sparc64_ctr_crypt_128(const u64 *key, const u64 *input,
1199fd130ecSDavid S. Miller 				      u64 *output, unsigned int len,
1209fd130ecSDavid S. Miller 				      u64 *iv);
1219fd130ecSDavid S. Miller extern void aes_sparc64_ctr_crypt_192(const u64 *key, const u64 *input,
1229fd130ecSDavid S. Miller 				      u64 *output, unsigned int len,
1239fd130ecSDavid S. Miller 				      u64 *iv);
1249fd130ecSDavid S. Miller extern void aes_sparc64_ctr_crypt_256(const u64 *key, const u64 *input,
1259fd130ecSDavid S. Miller 				      u64 *output, unsigned int len,
1269fd130ecSDavid S. Miller 				      u64 *iv);
1279fd130ecSDavid S. Miller 
128756382cbSSam Ravnborg static struct aes_ops aes128_ops = {
1290bdcaf74SDavid S. Miller 	.encrypt		= aes_sparc64_encrypt_128,
1300bdcaf74SDavid S. Miller 	.decrypt		= aes_sparc64_decrypt_128,
1310bdcaf74SDavid S. Miller 	.load_encrypt_keys	= aes_sparc64_load_encrypt_keys_128,
1320bdcaf74SDavid S. Miller 	.load_decrypt_keys	= aes_sparc64_load_decrypt_keys_128,
1330bdcaf74SDavid S. Miller 	.ecb_encrypt		= aes_sparc64_ecb_encrypt_128,
1340bdcaf74SDavid S. Miller 	.ecb_decrypt		= aes_sparc64_ecb_decrypt_128,
1350bdcaf74SDavid S. Miller 	.cbc_encrypt		= aes_sparc64_cbc_encrypt_128,
1360bdcaf74SDavid S. Miller 	.cbc_decrypt		= aes_sparc64_cbc_decrypt_128,
1379fd130ecSDavid S. Miller 	.ctr_crypt		= aes_sparc64_ctr_crypt_128,
1380bdcaf74SDavid S. Miller };
1390bdcaf74SDavid S. Miller 
140756382cbSSam Ravnborg static struct aes_ops aes192_ops = {
1410bdcaf74SDavid S. Miller 	.encrypt		= aes_sparc64_encrypt_192,
1420bdcaf74SDavid S. Miller 	.decrypt		= aes_sparc64_decrypt_192,
1430bdcaf74SDavid S. Miller 	.load_encrypt_keys	= aes_sparc64_load_encrypt_keys_192,
1440bdcaf74SDavid S. Miller 	.load_decrypt_keys	= aes_sparc64_load_decrypt_keys_192,
1450bdcaf74SDavid S. Miller 	.ecb_encrypt		= aes_sparc64_ecb_encrypt_192,
1460bdcaf74SDavid S. Miller 	.ecb_decrypt		= aes_sparc64_ecb_decrypt_192,
1470bdcaf74SDavid S. Miller 	.cbc_encrypt		= aes_sparc64_cbc_encrypt_192,
1480bdcaf74SDavid S. Miller 	.cbc_decrypt		= aes_sparc64_cbc_decrypt_192,
1499fd130ecSDavid S. Miller 	.ctr_crypt		= aes_sparc64_ctr_crypt_192,
1500bdcaf74SDavid S. Miller };
1510bdcaf74SDavid S. Miller 
152756382cbSSam Ravnborg static struct aes_ops aes256_ops = {
1530bdcaf74SDavid S. Miller 	.encrypt		= aes_sparc64_encrypt_256,
1540bdcaf74SDavid S. Miller 	.decrypt		= aes_sparc64_decrypt_256,
1550bdcaf74SDavid S. Miller 	.load_encrypt_keys	= aes_sparc64_load_encrypt_keys_256,
1560bdcaf74SDavid S. Miller 	.load_decrypt_keys	= aes_sparc64_load_decrypt_keys_256,
1570bdcaf74SDavid S. Miller 	.ecb_encrypt		= aes_sparc64_ecb_encrypt_256,
1580bdcaf74SDavid S. Miller 	.ecb_decrypt		= aes_sparc64_ecb_decrypt_256,
1590bdcaf74SDavid S. Miller 	.cbc_encrypt		= aes_sparc64_cbc_encrypt_256,
1600bdcaf74SDavid S. Miller 	.cbc_decrypt		= aes_sparc64_cbc_decrypt_256,
1619fd130ecSDavid S. Miller 	.ctr_crypt		= aes_sparc64_ctr_crypt_256,
1620bdcaf74SDavid S. Miller };
1630bdcaf74SDavid S. Miller 
1649bf4852dSDavid S. Miller extern void aes_sparc64_key_expand(const u32 *in_key, u64 *output_key,
1659bf4852dSDavid S. Miller 				   unsigned int key_len);
1669bf4852dSDavid S. Miller 
1679bf4852dSDavid S. Miller static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
1689bf4852dSDavid S. Miller 		       unsigned int key_len)
1699bf4852dSDavid S. Miller {
1709bf4852dSDavid S. Miller 	struct crypto_sparc64_aes_ctx *ctx = crypto_tfm_ctx(tfm);
1719bf4852dSDavid S. Miller 	u32 *flags = &tfm->crt_flags;
1729bf4852dSDavid S. Miller 
1739bf4852dSDavid S. Miller 	switch (key_len) {
1749bf4852dSDavid S. Miller 	case AES_KEYSIZE_128:
1759bf4852dSDavid S. Miller 		ctx->expanded_key_length = 0xb0;
1760bdcaf74SDavid S. Miller 		ctx->ops = &aes128_ops;
1779bf4852dSDavid S. Miller 		break;
1789bf4852dSDavid S. Miller 
1799bf4852dSDavid S. Miller 	case AES_KEYSIZE_192:
1809bf4852dSDavid S. Miller 		ctx->expanded_key_length = 0xd0;
1810bdcaf74SDavid S. Miller 		ctx->ops = &aes192_ops;
1829bf4852dSDavid S. Miller 		break;
1839bf4852dSDavid S. Miller 
1849bf4852dSDavid S. Miller 	case AES_KEYSIZE_256:
1859bf4852dSDavid S. Miller 		ctx->expanded_key_length = 0xf0;
1860bdcaf74SDavid S. Miller 		ctx->ops = &aes256_ops;
1879bf4852dSDavid S. Miller 		break;
1889bf4852dSDavid S. Miller 
1899bf4852dSDavid S. Miller 	default:
1909bf4852dSDavid S. Miller 		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
1919bf4852dSDavid S. Miller 		return -EINVAL;
1929bf4852dSDavid S. Miller 	}
1939bf4852dSDavid S. Miller 
1949bf4852dSDavid S. Miller 	aes_sparc64_key_expand((const u32 *)in_key, &ctx->key[0], key_len);
1959bf4852dSDavid S. Miller 	ctx->key_length = key_len;
1969bf4852dSDavid S. Miller 
1979bf4852dSDavid S. Miller 	return 0;
1989bf4852dSDavid S. Miller }
1999bf4852dSDavid S. Miller 
2009bf4852dSDavid S. Miller static void aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
2019bf4852dSDavid S. Miller {
2029bf4852dSDavid S. Miller 	struct crypto_sparc64_aes_ctx *ctx = crypto_tfm_ctx(tfm);
2039bf4852dSDavid S. Miller 
2040bdcaf74SDavid S. Miller 	ctx->ops->encrypt(&ctx->key[0], (const u32 *) src, (u32 *) dst);
2059bf4852dSDavid S. Miller }
2069bf4852dSDavid S. Miller 
2079bf4852dSDavid S. Miller static void aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
2089bf4852dSDavid S. Miller {
2099bf4852dSDavid S. Miller 	struct crypto_sparc64_aes_ctx *ctx = crypto_tfm_ctx(tfm);
2109bf4852dSDavid S. Miller 
2110bdcaf74SDavid S. Miller 	ctx->ops->decrypt(&ctx->key[0], (const u32 *) src, (u32 *) dst);
2129bf4852dSDavid S. Miller }
2139bf4852dSDavid S. Miller 
2149bf4852dSDavid S. Miller #define AES_BLOCK_MASK	(~(AES_BLOCK_SIZE-1))
2159bf4852dSDavid S. Miller 
2169bf4852dSDavid S. Miller static int ecb_encrypt(struct blkcipher_desc *desc,
2179bf4852dSDavid S. Miller 		       struct scatterlist *dst, struct scatterlist *src,
2189bf4852dSDavid S. Miller 		       unsigned int nbytes)
2199bf4852dSDavid S. Miller {
2209bf4852dSDavid S. Miller 	struct crypto_sparc64_aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
2219bf4852dSDavid S. Miller 	struct blkcipher_walk walk;
2229bf4852dSDavid S. Miller 	int err;
2239bf4852dSDavid S. Miller 
2249bf4852dSDavid S. Miller 	blkcipher_walk_init(&walk, dst, src, nbytes);
2259bf4852dSDavid S. Miller 	err = blkcipher_walk_virt(desc, &walk);
226b35d282eSDavid S. Miller 	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
2279bf4852dSDavid S. Miller 
2280bdcaf74SDavid S. Miller 	ctx->ops->load_encrypt_keys(&ctx->key[0]);
2299bf4852dSDavid S. Miller 	while ((nbytes = walk.nbytes)) {
2309bf4852dSDavid S. Miller 		unsigned int block_len = nbytes & AES_BLOCK_MASK;
2319bf4852dSDavid S. Miller 
2329bf4852dSDavid S. Miller 		if (likely(block_len)) {
2330bdcaf74SDavid S. Miller 			ctx->ops->ecb_encrypt(&ctx->key[0],
2340bdcaf74SDavid S. Miller 					      (const u64 *)walk.src.virt.addr,
2350bdcaf74SDavid S. Miller 					      (u64 *) walk.dst.virt.addr,
2360bdcaf74SDavid S. Miller 					      block_len);
2379bf4852dSDavid S. Miller 		}
2389bf4852dSDavid S. Miller 		nbytes &= AES_BLOCK_SIZE - 1;
2399bf4852dSDavid S. Miller 		err = blkcipher_walk_done(desc, &walk, nbytes);
2409bf4852dSDavid S. Miller 	}
2419bf4852dSDavid S. Miller 	fprs_write(0);
2429bf4852dSDavid S. Miller 	return err;
2439bf4852dSDavid S. Miller }
2449bf4852dSDavid S. Miller 
2459bf4852dSDavid S. Miller static int ecb_decrypt(struct blkcipher_desc *desc,
2469bf4852dSDavid S. Miller 		       struct scatterlist *dst, struct scatterlist *src,
2479bf4852dSDavid S. Miller 		       unsigned int nbytes)
2489bf4852dSDavid S. Miller {
2499bf4852dSDavid S. Miller 	struct crypto_sparc64_aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
2509bf4852dSDavid S. Miller 	struct blkcipher_walk walk;
2519bf4852dSDavid S. Miller 	u64 *key_end;
2529bf4852dSDavid S. Miller 	int err;
2539bf4852dSDavid S. Miller 
2549bf4852dSDavid S. Miller 	blkcipher_walk_init(&walk, dst, src, nbytes);
2559bf4852dSDavid S. Miller 	err = blkcipher_walk_virt(desc, &walk);
256b35d282eSDavid S. Miller 	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
2579bf4852dSDavid S. Miller 
2580bdcaf74SDavid S. Miller 	ctx->ops->load_decrypt_keys(&ctx->key[0]);
2599bf4852dSDavid S. Miller 	key_end = &ctx->key[ctx->expanded_key_length / sizeof(u64)];
2609bf4852dSDavid S. Miller 	while ((nbytes = walk.nbytes)) {
2619bf4852dSDavid S. Miller 		unsigned int block_len = nbytes & AES_BLOCK_MASK;
2629bf4852dSDavid S. Miller 
2630bdcaf74SDavid S. Miller 		if (likely(block_len)) {
2640bdcaf74SDavid S. Miller 			ctx->ops->ecb_decrypt(key_end,
2650bdcaf74SDavid S. Miller 					      (const u64 *) walk.src.virt.addr,
2660bdcaf74SDavid S. Miller 					      (u64 *) walk.dst.virt.addr, block_len);
2670bdcaf74SDavid S. Miller 		}
2689bf4852dSDavid S. Miller 		nbytes &= AES_BLOCK_SIZE - 1;
2699bf4852dSDavid S. Miller 		err = blkcipher_walk_done(desc, &walk, nbytes);
2709bf4852dSDavid S. Miller 	}
2719bf4852dSDavid S. Miller 	fprs_write(0);
2729bf4852dSDavid S. Miller 
2739bf4852dSDavid S. Miller 	return err;
2749bf4852dSDavid S. Miller }
2759bf4852dSDavid S. Miller 
2769bf4852dSDavid S. Miller static int cbc_encrypt(struct blkcipher_desc *desc,
2779bf4852dSDavid S. Miller 		       struct scatterlist *dst, struct scatterlist *src,
2789bf4852dSDavid S. Miller 		       unsigned int nbytes)
2799bf4852dSDavid S. Miller {
2809bf4852dSDavid S. Miller 	struct crypto_sparc64_aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
2819bf4852dSDavid S. Miller 	struct blkcipher_walk walk;
2829bf4852dSDavid S. Miller 	int err;
2839bf4852dSDavid S. Miller 
2849bf4852dSDavid S. Miller 	blkcipher_walk_init(&walk, dst, src, nbytes);
2859bf4852dSDavid S. Miller 	err = blkcipher_walk_virt(desc, &walk);
286b35d282eSDavid S. Miller 	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
2879bf4852dSDavid S. Miller 
2880bdcaf74SDavid S. Miller 	ctx->ops->load_encrypt_keys(&ctx->key[0]);
2899bf4852dSDavid S. Miller 	while ((nbytes = walk.nbytes)) {
2909bf4852dSDavid S. Miller 		unsigned int block_len = nbytes & AES_BLOCK_MASK;
2919bf4852dSDavid S. Miller 
2929bf4852dSDavid S. Miller 		if (likely(block_len)) {
2930bdcaf74SDavid S. Miller 			ctx->ops->cbc_encrypt(&ctx->key[0],
2940bdcaf74SDavid S. Miller 					      (const u64 *)walk.src.virt.addr,
2950bdcaf74SDavid S. Miller 					      (u64 *) walk.dst.virt.addr,
2960bdcaf74SDavid S. Miller 					      block_len, (u64 *) walk.iv);
2979bf4852dSDavid S. Miller 		}
2989bf4852dSDavid S. Miller 		nbytes &= AES_BLOCK_SIZE - 1;
2999bf4852dSDavid S. Miller 		err = blkcipher_walk_done(desc, &walk, nbytes);
3009bf4852dSDavid S. Miller 	}
3019bf4852dSDavid S. Miller 	fprs_write(0);
3029bf4852dSDavid S. Miller 	return err;
3039bf4852dSDavid S. Miller }
3049bf4852dSDavid S. Miller 
3059bf4852dSDavid S. Miller static int cbc_decrypt(struct blkcipher_desc *desc,
3069bf4852dSDavid S. Miller 		       struct scatterlist *dst, struct scatterlist *src,
3079bf4852dSDavid S. Miller 		       unsigned int nbytes)
3089bf4852dSDavid S. Miller {
3099bf4852dSDavid S. Miller 	struct crypto_sparc64_aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
3109bf4852dSDavid S. Miller 	struct blkcipher_walk walk;
3119bf4852dSDavid S. Miller 	u64 *key_end;
3129bf4852dSDavid S. Miller 	int err;
3139bf4852dSDavid S. Miller 
3149bf4852dSDavid S. Miller 	blkcipher_walk_init(&walk, dst, src, nbytes);
3159bf4852dSDavid S. Miller 	err = blkcipher_walk_virt(desc, &walk);
316b35d282eSDavid S. Miller 	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
3179bf4852dSDavid S. Miller 
3180bdcaf74SDavid S. Miller 	ctx->ops->load_decrypt_keys(&ctx->key[0]);
3199bf4852dSDavid S. Miller 	key_end = &ctx->key[ctx->expanded_key_length / sizeof(u64)];
3209bf4852dSDavid S. Miller 	while ((nbytes = walk.nbytes)) {
3219bf4852dSDavid S. Miller 		unsigned int block_len = nbytes & AES_BLOCK_MASK;
3229bf4852dSDavid S. Miller 
3230bdcaf74SDavid S. Miller 		if (likely(block_len)) {
3240bdcaf74SDavid S. Miller 			ctx->ops->cbc_decrypt(key_end,
3250bdcaf74SDavid S. Miller 					      (const u64 *) walk.src.virt.addr,
3260bdcaf74SDavid S. Miller 					      (u64 *) walk.dst.virt.addr,
3279bf4852dSDavid S. Miller 					      block_len, (u64 *) walk.iv);
3280bdcaf74SDavid S. Miller 		}
3299bf4852dSDavid S. Miller 		nbytes &= AES_BLOCK_SIZE - 1;
3309bf4852dSDavid S. Miller 		err = blkcipher_walk_done(desc, &walk, nbytes);
3319bf4852dSDavid S. Miller 	}
3329bf4852dSDavid S. Miller 	fprs_write(0);
3339bf4852dSDavid S. Miller 
3349bf4852dSDavid S. Miller 	return err;
3359bf4852dSDavid S. Miller }
3369bf4852dSDavid S. Miller 
337a8d97cefSDavid S. Miller static void ctr_crypt_final(struct crypto_sparc64_aes_ctx *ctx,
338a8d97cefSDavid S. Miller 			    struct blkcipher_walk *walk)
339a8d97cefSDavid S. Miller {
340a8d97cefSDavid S. Miller 	u8 *ctrblk = walk->iv;
341a8d97cefSDavid S. Miller 	u64 keystream[AES_BLOCK_SIZE / sizeof(u64)];
342a8d97cefSDavid S. Miller 	u8 *src = walk->src.virt.addr;
343a8d97cefSDavid S. Miller 	u8 *dst = walk->dst.virt.addr;
344a8d97cefSDavid S. Miller 	unsigned int nbytes = walk->nbytes;
345a8d97cefSDavid S. Miller 
346a8d97cefSDavid S. Miller 	ctx->ops->ecb_encrypt(&ctx->key[0], (const u64 *)ctrblk,
347a8d97cefSDavid S. Miller 			      keystream, AES_BLOCK_SIZE);
34845fe93dfSArd Biesheuvel 	crypto_xor_cpy(dst, (u8 *) keystream, src, nbytes);
349a8d97cefSDavid S. Miller 	crypto_inc(ctrblk, AES_BLOCK_SIZE);
350a8d97cefSDavid S. Miller }
351a8d97cefSDavid S. Miller 
3529fd130ecSDavid S. Miller static int ctr_crypt(struct blkcipher_desc *desc,
3539fd130ecSDavid S. Miller 		     struct scatterlist *dst, struct scatterlist *src,
3549fd130ecSDavid S. Miller 		     unsigned int nbytes)
3559fd130ecSDavid S. Miller {
3569fd130ecSDavid S. Miller 	struct crypto_sparc64_aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
3579fd130ecSDavid S. Miller 	struct blkcipher_walk walk;
3589fd130ecSDavid S. Miller 	int err;
3599fd130ecSDavid S. Miller 
3609fd130ecSDavid S. Miller 	blkcipher_walk_init(&walk, dst, src, nbytes);
361a8d97cefSDavid S. Miller 	err = blkcipher_walk_virt_block(desc, &walk, AES_BLOCK_SIZE);
362a8d97cefSDavid S. Miller 	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
3639fd130ecSDavid S. Miller 
3649fd130ecSDavid S. Miller 	ctx->ops->load_encrypt_keys(&ctx->key[0]);
365a8d97cefSDavid S. Miller 	while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) {
3669fd130ecSDavid S. Miller 		unsigned int block_len = nbytes & AES_BLOCK_MASK;
3679fd130ecSDavid S. Miller 
3689fd130ecSDavid S. Miller 		if (likely(block_len)) {
3699fd130ecSDavid S. Miller 			ctx->ops->ctr_crypt(&ctx->key[0],
3709fd130ecSDavid S. Miller 					    (const u64 *)walk.src.virt.addr,
3719fd130ecSDavid S. Miller 					    (u64 *) walk.dst.virt.addr,
3729fd130ecSDavid S. Miller 					    block_len, (u64 *) walk.iv);
3739fd130ecSDavid S. Miller 		}
3749fd130ecSDavid S. Miller 		nbytes &= AES_BLOCK_SIZE - 1;
3759fd130ecSDavid S. Miller 		err = blkcipher_walk_done(desc, &walk, nbytes);
3769fd130ecSDavid S. Miller 	}
377a8d97cefSDavid S. Miller 	if (walk.nbytes) {
378a8d97cefSDavid S. Miller 		ctr_crypt_final(ctx, &walk);
379a8d97cefSDavid S. Miller 		err = blkcipher_walk_done(desc, &walk, 0);
380a8d97cefSDavid S. Miller 	}
3819fd130ecSDavid S. Miller 	fprs_write(0);
3829fd130ecSDavid S. Miller 	return err;
3839fd130ecSDavid S. Miller }
3849fd130ecSDavid S. Miller 
3859bf4852dSDavid S. Miller static struct crypto_alg algs[] = { {
3869bf4852dSDavid S. Miller 	.cra_name		= "aes",
3879bf4852dSDavid S. Miller 	.cra_driver_name	= "aes-sparc64",
38810803624SDavid S. Miller 	.cra_priority		= SPARC_CR_OPCODE_PRIORITY,
3899bf4852dSDavid S. Miller 	.cra_flags		= CRYPTO_ALG_TYPE_CIPHER,
3909bf4852dSDavid S. Miller 	.cra_blocksize		= AES_BLOCK_SIZE,
3919bf4852dSDavid S. Miller 	.cra_ctxsize		= sizeof(struct crypto_sparc64_aes_ctx),
3929bf4852dSDavid S. Miller 	.cra_alignmask		= 3,
3939bf4852dSDavid S. Miller 	.cra_module		= THIS_MODULE,
3949bf4852dSDavid S. Miller 	.cra_u	= {
3959bf4852dSDavid S. Miller 		.cipher	= {
3969bf4852dSDavid S. Miller 			.cia_min_keysize	= AES_MIN_KEY_SIZE,
3979bf4852dSDavid S. Miller 			.cia_max_keysize	= AES_MAX_KEY_SIZE,
3989bf4852dSDavid S. Miller 			.cia_setkey		= aes_set_key,
3999bf4852dSDavid S. Miller 			.cia_encrypt		= aes_encrypt,
4009bf4852dSDavid S. Miller 			.cia_decrypt		= aes_decrypt
4019bf4852dSDavid S. Miller 		}
4029bf4852dSDavid S. Miller 	}
4039bf4852dSDavid S. Miller }, {
4049bf4852dSDavid S. Miller 	.cra_name		= "ecb(aes)",
4059bf4852dSDavid S. Miller 	.cra_driver_name	= "ecb-aes-sparc64",
40610803624SDavid S. Miller 	.cra_priority		= SPARC_CR_OPCODE_PRIORITY,
4079bf4852dSDavid S. Miller 	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
4089bf4852dSDavid S. Miller 	.cra_blocksize		= AES_BLOCK_SIZE,
4099bf4852dSDavid S. Miller 	.cra_ctxsize		= sizeof(struct crypto_sparc64_aes_ctx),
4109bf4852dSDavid S. Miller 	.cra_alignmask		= 7,
4119bf4852dSDavid S. Miller 	.cra_type		= &crypto_blkcipher_type,
4129bf4852dSDavid S. Miller 	.cra_module		= THIS_MODULE,
4139bf4852dSDavid S. Miller 	.cra_u = {
4149bf4852dSDavid S. Miller 		.blkcipher = {
4159bf4852dSDavid S. Miller 			.min_keysize	= AES_MIN_KEY_SIZE,
4169bf4852dSDavid S. Miller 			.max_keysize	= AES_MAX_KEY_SIZE,
4179bf4852dSDavid S. Miller 			.setkey		= aes_set_key,
4189bf4852dSDavid S. Miller 			.encrypt	= ecb_encrypt,
4199bf4852dSDavid S. Miller 			.decrypt	= ecb_decrypt,
4209bf4852dSDavid S. Miller 		},
4219bf4852dSDavid S. Miller 	},
4229bf4852dSDavid S. Miller }, {
4239bf4852dSDavid S. Miller 	.cra_name		= "cbc(aes)",
4249bf4852dSDavid S. Miller 	.cra_driver_name	= "cbc-aes-sparc64",
42510803624SDavid S. Miller 	.cra_priority		= SPARC_CR_OPCODE_PRIORITY,
4269bf4852dSDavid S. Miller 	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
4279bf4852dSDavid S. Miller 	.cra_blocksize		= AES_BLOCK_SIZE,
4289bf4852dSDavid S. Miller 	.cra_ctxsize		= sizeof(struct crypto_sparc64_aes_ctx),
4299bf4852dSDavid S. Miller 	.cra_alignmask		= 7,
4309bf4852dSDavid S. Miller 	.cra_type		= &crypto_blkcipher_type,
4319bf4852dSDavid S. Miller 	.cra_module		= THIS_MODULE,
4329bf4852dSDavid S. Miller 	.cra_u = {
4339bf4852dSDavid S. Miller 		.blkcipher = {
4349bf4852dSDavid S. Miller 			.min_keysize	= AES_MIN_KEY_SIZE,
4359bf4852dSDavid S. Miller 			.max_keysize	= AES_MAX_KEY_SIZE,
436a66d7f72SDave Kleikamp 			.ivsize		= AES_BLOCK_SIZE,
4379bf4852dSDavid S. Miller 			.setkey		= aes_set_key,
4389bf4852dSDavid S. Miller 			.encrypt	= cbc_encrypt,
4399bf4852dSDavid S. Miller 			.decrypt	= cbc_decrypt,
4409bf4852dSDavid S. Miller 		},
4419bf4852dSDavid S. Miller 	},
4429fd130ecSDavid S. Miller }, {
4439fd130ecSDavid S. Miller 	.cra_name		= "ctr(aes)",
4449fd130ecSDavid S. Miller 	.cra_driver_name	= "ctr-aes-sparc64",
44510803624SDavid S. Miller 	.cra_priority		= SPARC_CR_OPCODE_PRIORITY,
4469fd130ecSDavid S. Miller 	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
447a8d97cefSDavid S. Miller 	.cra_blocksize		= 1,
4489fd130ecSDavid S. Miller 	.cra_ctxsize		= sizeof(struct crypto_sparc64_aes_ctx),
4499fd130ecSDavid S. Miller 	.cra_alignmask		= 7,
4509fd130ecSDavid S. Miller 	.cra_type		= &crypto_blkcipher_type,
4519fd130ecSDavid S. Miller 	.cra_module		= THIS_MODULE,
4529fd130ecSDavid S. Miller 	.cra_u = {
4539fd130ecSDavid S. Miller 		.blkcipher = {
4549fd130ecSDavid S. Miller 			.min_keysize	= AES_MIN_KEY_SIZE,
4559fd130ecSDavid S. Miller 			.max_keysize	= AES_MAX_KEY_SIZE,
456a66d7f72SDave Kleikamp 			.ivsize		= AES_BLOCK_SIZE,
4579fd130ecSDavid S. Miller 			.setkey		= aes_set_key,
4589fd130ecSDavid S. Miller 			.encrypt	= ctr_crypt,
4599fd130ecSDavid S. Miller 			.decrypt	= ctr_crypt,
4609fd130ecSDavid S. Miller 		},
4619fd130ecSDavid S. Miller 	},
4629bf4852dSDavid S. Miller } };
4639bf4852dSDavid S. Miller 
4649bf4852dSDavid S. Miller static bool __init sparc64_has_aes_opcode(void)
4659bf4852dSDavid S. Miller {
4669bf4852dSDavid S. Miller 	unsigned long cfr;
4679bf4852dSDavid S. Miller 
4689bf4852dSDavid S. Miller 	if (!(sparc64_elf_hwcap & HWCAP_SPARC_CRYPTO))
4699bf4852dSDavid S. Miller 		return false;
4709bf4852dSDavid S. Miller 
4719bf4852dSDavid S. Miller 	__asm__ __volatile__("rd %%asr26, %0" : "=r" (cfr));
4729bf4852dSDavid S. Miller 	if (!(cfr & CFR_AES))
4739bf4852dSDavid S. Miller 		return false;
4749bf4852dSDavid S. Miller 
4759bf4852dSDavid S. Miller 	return true;
4769bf4852dSDavid S. Miller }
4779bf4852dSDavid S. Miller 
4789bf4852dSDavid S. Miller static int __init aes_sparc64_mod_init(void)
4799bf4852dSDavid S. Miller {
4809bf4852dSDavid S. Miller 	if (sparc64_has_aes_opcode()) {
4819bf4852dSDavid S. Miller 		pr_info("Using sparc64 aes opcodes optimized AES implementation\n");
4829bf4852dSDavid S. Miller 		return crypto_register_algs(algs, ARRAY_SIZE(algs));
4839bf4852dSDavid S. Miller 	}
4849bf4852dSDavid S. Miller 	pr_info("sparc64 aes opcodes not available.\n");
4859bf4852dSDavid S. Miller 	return -ENODEV;
4869bf4852dSDavid S. Miller }
4879bf4852dSDavid S. Miller 
4889bf4852dSDavid S. Miller static void __exit aes_sparc64_mod_fini(void)
4899bf4852dSDavid S. Miller {
4909bf4852dSDavid S. Miller 	crypto_unregister_algs(algs, ARRAY_SIZE(algs));
4919bf4852dSDavid S. Miller }
4929bf4852dSDavid S. Miller 
4939bf4852dSDavid S. Miller module_init(aes_sparc64_mod_init);
4949bf4852dSDavid S. Miller module_exit(aes_sparc64_mod_fini);
4959bf4852dSDavid S. Miller 
4969bf4852dSDavid S. Miller MODULE_LICENSE("GPL");
497b0126417SMathias Krause MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm, sparc64 aes opcode accelerated");
4989bf4852dSDavid S. Miller 
4995d26a105SKees Cook MODULE_ALIAS_CRYPTO("aes");
500226f7ceaSDavid S. Miller 
501226f7ceaSDavid S. Miller #include "crop_devid.c"
502