xref: /openbmc/linux/arch/sparc/crypto/aes_glue.c (revision 45fe93df)
19bf4852dSDavid S. Miller /* Glue code for AES encryption optimized for sparc64 crypto opcodes.
29bf4852dSDavid S. Miller  *
39bf4852dSDavid S. Miller  * This is based largely upon arch/x86/crypto/aesni-intel_glue.c
49bf4852dSDavid S. Miller  *
59bf4852dSDavid S. Miller  * Copyright (C) 2008, Intel Corp.
69bf4852dSDavid S. Miller  *    Author: Huang Ying <ying.huang@intel.com>
79bf4852dSDavid S. Miller  *
89bf4852dSDavid S. Miller  * Added RFC4106 AES-GCM support for 128-bit keys under the AEAD
99bf4852dSDavid S. Miller  * interface for 64-bit kernels.
109bf4852dSDavid S. Miller  *    Authors: Adrian Hoban <adrian.hoban@intel.com>
119bf4852dSDavid S. Miller  *             Gabriele Paoloni <gabriele.paoloni@intel.com>
129bf4852dSDavid S. Miller  *             Tadeusz Struk (tadeusz.struk@intel.com)
139bf4852dSDavid S. Miller  *             Aidan O'Mahony (aidan.o.mahony@intel.com)
149bf4852dSDavid S. Miller  *    Copyright (c) 2010, Intel Corporation.
159bf4852dSDavid S. Miller  */
169bf4852dSDavid S. Miller 
1771741680SDavid S. Miller #define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
1871741680SDavid S. Miller 
199bf4852dSDavid S. Miller #include <linux/crypto.h>
209bf4852dSDavid S. Miller #include <linux/init.h>
219bf4852dSDavid S. Miller #include <linux/module.h>
229bf4852dSDavid S. Miller #include <linux/mm.h>
239bf4852dSDavid S. Miller #include <linux/types.h>
249bf4852dSDavid S. Miller #include <crypto/algapi.h>
259bf4852dSDavid S. Miller #include <crypto/aes.h>
269bf4852dSDavid S. Miller 
279bf4852dSDavid S. Miller #include <asm/fpumacro.h>
289bf4852dSDavid S. Miller #include <asm/pstate.h>
299bf4852dSDavid S. Miller #include <asm/elf.h>
309bf4852dSDavid S. Miller 
3110803624SDavid S. Miller #include "opcodes.h"
3210803624SDavid S. Miller 
330bdcaf74SDavid S. Miller struct aes_ops {
340bdcaf74SDavid S. Miller 	void (*encrypt)(const u64 *key, const u32 *input, u32 *output);
350bdcaf74SDavid S. Miller 	void (*decrypt)(const u64 *key, const u32 *input, u32 *output);
360bdcaf74SDavid S. Miller 	void (*load_encrypt_keys)(const u64 *key);
370bdcaf74SDavid S. Miller 	void (*load_decrypt_keys)(const u64 *key);
380bdcaf74SDavid S. Miller 	void (*ecb_encrypt)(const u64 *key, const u64 *input, u64 *output,
390bdcaf74SDavid S. Miller 			    unsigned int len);
400bdcaf74SDavid S. Miller 	void (*ecb_decrypt)(const u64 *key, const u64 *input, u64 *output,
410bdcaf74SDavid S. Miller 			    unsigned int len);
420bdcaf74SDavid S. Miller 	void (*cbc_encrypt)(const u64 *key, const u64 *input, u64 *output,
430bdcaf74SDavid S. Miller 			    unsigned int len, u64 *iv);
440bdcaf74SDavid S. Miller 	void (*cbc_decrypt)(const u64 *key, const u64 *input, u64 *output,
450bdcaf74SDavid S. Miller 			    unsigned int len, u64 *iv);
469fd130ecSDavid S. Miller 	void (*ctr_crypt)(const u64 *key, const u64 *input, u64 *output,
479fd130ecSDavid S. Miller 			  unsigned int len, u64 *iv);
480bdcaf74SDavid S. Miller };
490bdcaf74SDavid S. Miller 
509bf4852dSDavid S. Miller struct crypto_sparc64_aes_ctx {
510bdcaf74SDavid S. Miller 	struct aes_ops *ops;
529bf4852dSDavid S. Miller 	u64 key[AES_MAX_KEYLENGTH / sizeof(u64)];
539bf4852dSDavid S. Miller 	u32 key_length;
549bf4852dSDavid S. Miller 	u32 expanded_key_length;
559bf4852dSDavid S. Miller };
569bf4852dSDavid S. Miller 
570bdcaf74SDavid S. Miller extern void aes_sparc64_encrypt_128(const u64 *key, const u32 *input,
580bdcaf74SDavid S. Miller 				    u32 *output);
590bdcaf74SDavid S. Miller extern void aes_sparc64_encrypt_192(const u64 *key, const u32 *input,
600bdcaf74SDavid S. Miller 				    u32 *output);
610bdcaf74SDavid S. Miller extern void aes_sparc64_encrypt_256(const u64 *key, const u32 *input,
620bdcaf74SDavid S. Miller 				    u32 *output);
630bdcaf74SDavid S. Miller 
640bdcaf74SDavid S. Miller extern void aes_sparc64_decrypt_128(const u64 *key, const u32 *input,
650bdcaf74SDavid S. Miller 				    u32 *output);
660bdcaf74SDavid S. Miller extern void aes_sparc64_decrypt_192(const u64 *key, const u32 *input,
670bdcaf74SDavid S. Miller 				    u32 *output);
680bdcaf74SDavid S. Miller extern void aes_sparc64_decrypt_256(const u64 *key, const u32 *input,
690bdcaf74SDavid S. Miller 				    u32 *output);
700bdcaf74SDavid S. Miller 
710bdcaf74SDavid S. Miller extern void aes_sparc64_load_encrypt_keys_128(const u64 *key);
720bdcaf74SDavid S. Miller extern void aes_sparc64_load_encrypt_keys_192(const u64 *key);
730bdcaf74SDavid S. Miller extern void aes_sparc64_load_encrypt_keys_256(const u64 *key);
740bdcaf74SDavid S. Miller 
750bdcaf74SDavid S. Miller extern void aes_sparc64_load_decrypt_keys_128(const u64 *key);
760bdcaf74SDavid S. Miller extern void aes_sparc64_load_decrypt_keys_192(const u64 *key);
770bdcaf74SDavid S. Miller extern void aes_sparc64_load_decrypt_keys_256(const u64 *key);
780bdcaf74SDavid S. Miller 
790bdcaf74SDavid S. Miller extern void aes_sparc64_ecb_encrypt_128(const u64 *key, const u64 *input,
800bdcaf74SDavid S. Miller 					u64 *output, unsigned int len);
810bdcaf74SDavid S. Miller extern void aes_sparc64_ecb_encrypt_192(const u64 *key, const u64 *input,
820bdcaf74SDavid S. Miller 					u64 *output, unsigned int len);
830bdcaf74SDavid S. Miller extern void aes_sparc64_ecb_encrypt_256(const u64 *key, const u64 *input,
840bdcaf74SDavid S. Miller 					u64 *output, unsigned int len);
850bdcaf74SDavid S. Miller 
860bdcaf74SDavid S. Miller extern void aes_sparc64_ecb_decrypt_128(const u64 *key, const u64 *input,
870bdcaf74SDavid S. Miller 					u64 *output, unsigned int len);
880bdcaf74SDavid S. Miller extern void aes_sparc64_ecb_decrypt_192(const u64 *key, const u64 *input,
890bdcaf74SDavid S. Miller 					u64 *output, unsigned int len);
900bdcaf74SDavid S. Miller extern void aes_sparc64_ecb_decrypt_256(const u64 *key, const u64 *input,
910bdcaf74SDavid S. Miller 					u64 *output, unsigned int len);
920bdcaf74SDavid S. Miller 
930bdcaf74SDavid S. Miller extern void aes_sparc64_cbc_encrypt_128(const u64 *key, const u64 *input,
940bdcaf74SDavid S. Miller 					u64 *output, unsigned int len,
950bdcaf74SDavid S. Miller 					u64 *iv);
960bdcaf74SDavid S. Miller 
970bdcaf74SDavid S. Miller extern void aes_sparc64_cbc_encrypt_192(const u64 *key, const u64 *input,
980bdcaf74SDavid S. Miller 					u64 *output, unsigned int len,
990bdcaf74SDavid S. Miller 					u64 *iv);
1000bdcaf74SDavid S. Miller 
1010bdcaf74SDavid S. Miller extern void aes_sparc64_cbc_encrypt_256(const u64 *key, const u64 *input,
1020bdcaf74SDavid S. Miller 					u64 *output, unsigned int len,
1030bdcaf74SDavid S. Miller 					u64 *iv);
1040bdcaf74SDavid S. Miller 
1050bdcaf74SDavid S. Miller extern void aes_sparc64_cbc_decrypt_128(const u64 *key, const u64 *input,
1060bdcaf74SDavid S. Miller 					u64 *output, unsigned int len,
1070bdcaf74SDavid S. Miller 					u64 *iv);
1080bdcaf74SDavid S. Miller 
1090bdcaf74SDavid S. Miller extern void aes_sparc64_cbc_decrypt_192(const u64 *key, const u64 *input,
1100bdcaf74SDavid S. Miller 					u64 *output, unsigned int len,
1110bdcaf74SDavid S. Miller 					u64 *iv);
1120bdcaf74SDavid S. Miller 
1130bdcaf74SDavid S. Miller extern void aes_sparc64_cbc_decrypt_256(const u64 *key, const u64 *input,
1140bdcaf74SDavid S. Miller 					u64 *output, unsigned int len,
1150bdcaf74SDavid S. Miller 					u64 *iv);
1160bdcaf74SDavid S. Miller 
1179fd130ecSDavid S. Miller extern void aes_sparc64_ctr_crypt_128(const u64 *key, const u64 *input,
1189fd130ecSDavid S. Miller 				      u64 *output, unsigned int len,
1199fd130ecSDavid S. Miller 				      u64 *iv);
1209fd130ecSDavid S. Miller extern void aes_sparc64_ctr_crypt_192(const u64 *key, const u64 *input,
1219fd130ecSDavid S. Miller 				      u64 *output, unsigned int len,
1229fd130ecSDavid S. Miller 				      u64 *iv);
1239fd130ecSDavid S. Miller extern void aes_sparc64_ctr_crypt_256(const u64 *key, const u64 *input,
1249fd130ecSDavid S. Miller 				      u64 *output, unsigned int len,
1259fd130ecSDavid S. Miller 				      u64 *iv);
1269fd130ecSDavid S. Miller 
127756382cbSSam Ravnborg static struct aes_ops aes128_ops = {
1280bdcaf74SDavid S. Miller 	.encrypt		= aes_sparc64_encrypt_128,
1290bdcaf74SDavid S. Miller 	.decrypt		= aes_sparc64_decrypt_128,
1300bdcaf74SDavid S. Miller 	.load_encrypt_keys	= aes_sparc64_load_encrypt_keys_128,
1310bdcaf74SDavid S. Miller 	.load_decrypt_keys	= aes_sparc64_load_decrypt_keys_128,
1320bdcaf74SDavid S. Miller 	.ecb_encrypt		= aes_sparc64_ecb_encrypt_128,
1330bdcaf74SDavid S. Miller 	.ecb_decrypt		= aes_sparc64_ecb_decrypt_128,
1340bdcaf74SDavid S. Miller 	.cbc_encrypt		= aes_sparc64_cbc_encrypt_128,
1350bdcaf74SDavid S. Miller 	.cbc_decrypt		= aes_sparc64_cbc_decrypt_128,
1369fd130ecSDavid S. Miller 	.ctr_crypt		= aes_sparc64_ctr_crypt_128,
1370bdcaf74SDavid S. Miller };
1380bdcaf74SDavid S. Miller 
139756382cbSSam Ravnborg static struct aes_ops aes192_ops = {
1400bdcaf74SDavid S. Miller 	.encrypt		= aes_sparc64_encrypt_192,
1410bdcaf74SDavid S. Miller 	.decrypt		= aes_sparc64_decrypt_192,
1420bdcaf74SDavid S. Miller 	.load_encrypt_keys	= aes_sparc64_load_encrypt_keys_192,
1430bdcaf74SDavid S. Miller 	.load_decrypt_keys	= aes_sparc64_load_decrypt_keys_192,
1440bdcaf74SDavid S. Miller 	.ecb_encrypt		= aes_sparc64_ecb_encrypt_192,
1450bdcaf74SDavid S. Miller 	.ecb_decrypt		= aes_sparc64_ecb_decrypt_192,
1460bdcaf74SDavid S. Miller 	.cbc_encrypt		= aes_sparc64_cbc_encrypt_192,
1470bdcaf74SDavid S. Miller 	.cbc_decrypt		= aes_sparc64_cbc_decrypt_192,
1489fd130ecSDavid S. Miller 	.ctr_crypt		= aes_sparc64_ctr_crypt_192,
1490bdcaf74SDavid S. Miller };
1500bdcaf74SDavid S. Miller 
151756382cbSSam Ravnborg static struct aes_ops aes256_ops = {
1520bdcaf74SDavid S. Miller 	.encrypt		= aes_sparc64_encrypt_256,
1530bdcaf74SDavid S. Miller 	.decrypt		= aes_sparc64_decrypt_256,
1540bdcaf74SDavid S. Miller 	.load_encrypt_keys	= aes_sparc64_load_encrypt_keys_256,
1550bdcaf74SDavid S. Miller 	.load_decrypt_keys	= aes_sparc64_load_decrypt_keys_256,
1560bdcaf74SDavid S. Miller 	.ecb_encrypt		= aes_sparc64_ecb_encrypt_256,
1570bdcaf74SDavid S. Miller 	.ecb_decrypt		= aes_sparc64_ecb_decrypt_256,
1580bdcaf74SDavid S. Miller 	.cbc_encrypt		= aes_sparc64_cbc_encrypt_256,
1590bdcaf74SDavid S. Miller 	.cbc_decrypt		= aes_sparc64_cbc_decrypt_256,
1609fd130ecSDavid S. Miller 	.ctr_crypt		= aes_sparc64_ctr_crypt_256,
1610bdcaf74SDavid S. Miller };
1620bdcaf74SDavid S. Miller 
1639bf4852dSDavid S. Miller extern void aes_sparc64_key_expand(const u32 *in_key, u64 *output_key,
1649bf4852dSDavid S. Miller 				   unsigned int key_len);
1659bf4852dSDavid S. Miller 
1669bf4852dSDavid S. Miller static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
1679bf4852dSDavid S. Miller 		       unsigned int key_len)
1689bf4852dSDavid S. Miller {
1699bf4852dSDavid S. Miller 	struct crypto_sparc64_aes_ctx *ctx = crypto_tfm_ctx(tfm);
1709bf4852dSDavid S. Miller 	u32 *flags = &tfm->crt_flags;
1719bf4852dSDavid S. Miller 
1729bf4852dSDavid S. Miller 	switch (key_len) {
1739bf4852dSDavid S. Miller 	case AES_KEYSIZE_128:
1749bf4852dSDavid S. Miller 		ctx->expanded_key_length = 0xb0;
1750bdcaf74SDavid S. Miller 		ctx->ops = &aes128_ops;
1769bf4852dSDavid S. Miller 		break;
1779bf4852dSDavid S. Miller 
1789bf4852dSDavid S. Miller 	case AES_KEYSIZE_192:
1799bf4852dSDavid S. Miller 		ctx->expanded_key_length = 0xd0;
1800bdcaf74SDavid S. Miller 		ctx->ops = &aes192_ops;
1819bf4852dSDavid S. Miller 		break;
1829bf4852dSDavid S. Miller 
1839bf4852dSDavid S. Miller 	case AES_KEYSIZE_256:
1849bf4852dSDavid S. Miller 		ctx->expanded_key_length = 0xf0;
1850bdcaf74SDavid S. Miller 		ctx->ops = &aes256_ops;
1869bf4852dSDavid S. Miller 		break;
1879bf4852dSDavid S. Miller 
1889bf4852dSDavid S. Miller 	default:
1899bf4852dSDavid S. Miller 		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
1909bf4852dSDavid S. Miller 		return -EINVAL;
1919bf4852dSDavid S. Miller 	}
1929bf4852dSDavid S. Miller 
1939bf4852dSDavid S. Miller 	aes_sparc64_key_expand((const u32 *)in_key, &ctx->key[0], key_len);
1949bf4852dSDavid S. Miller 	ctx->key_length = key_len;
1959bf4852dSDavid S. Miller 
1969bf4852dSDavid S. Miller 	return 0;
1979bf4852dSDavid S. Miller }
1989bf4852dSDavid S. Miller 
1999bf4852dSDavid S. Miller static void aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
2009bf4852dSDavid S. Miller {
2019bf4852dSDavid S. Miller 	struct crypto_sparc64_aes_ctx *ctx = crypto_tfm_ctx(tfm);
2029bf4852dSDavid S. Miller 
2030bdcaf74SDavid S. Miller 	ctx->ops->encrypt(&ctx->key[0], (const u32 *) src, (u32 *) dst);
2049bf4852dSDavid S. Miller }
2059bf4852dSDavid S. Miller 
2069bf4852dSDavid S. Miller static void aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
2079bf4852dSDavid S. Miller {
2089bf4852dSDavid S. Miller 	struct crypto_sparc64_aes_ctx *ctx = crypto_tfm_ctx(tfm);
2099bf4852dSDavid S. Miller 
2100bdcaf74SDavid S. Miller 	ctx->ops->decrypt(&ctx->key[0], (const u32 *) src, (u32 *) dst);
2119bf4852dSDavid S. Miller }
2129bf4852dSDavid S. Miller 
2139bf4852dSDavid S. Miller #define AES_BLOCK_MASK	(~(AES_BLOCK_SIZE-1))
2149bf4852dSDavid S. Miller 
2159bf4852dSDavid S. Miller static int ecb_encrypt(struct blkcipher_desc *desc,
2169bf4852dSDavid S. Miller 		       struct scatterlist *dst, struct scatterlist *src,
2179bf4852dSDavid S. Miller 		       unsigned int nbytes)
2189bf4852dSDavid S. Miller {
2199bf4852dSDavid S. Miller 	struct crypto_sparc64_aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
2209bf4852dSDavid S. Miller 	struct blkcipher_walk walk;
2219bf4852dSDavid S. Miller 	int err;
2229bf4852dSDavid S. Miller 
2239bf4852dSDavid S. Miller 	blkcipher_walk_init(&walk, dst, src, nbytes);
2249bf4852dSDavid S. Miller 	err = blkcipher_walk_virt(desc, &walk);
225b35d282eSDavid S. Miller 	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
2269bf4852dSDavid S. Miller 
2270bdcaf74SDavid S. Miller 	ctx->ops->load_encrypt_keys(&ctx->key[0]);
2289bf4852dSDavid S. Miller 	while ((nbytes = walk.nbytes)) {
2299bf4852dSDavid S. Miller 		unsigned int block_len = nbytes & AES_BLOCK_MASK;
2309bf4852dSDavid S. Miller 
2319bf4852dSDavid S. Miller 		if (likely(block_len)) {
2320bdcaf74SDavid S. Miller 			ctx->ops->ecb_encrypt(&ctx->key[0],
2330bdcaf74SDavid S. Miller 					      (const u64 *)walk.src.virt.addr,
2340bdcaf74SDavid S. Miller 					      (u64 *) walk.dst.virt.addr,
2350bdcaf74SDavid S. Miller 					      block_len);
2369bf4852dSDavid S. Miller 		}
2379bf4852dSDavid S. Miller 		nbytes &= AES_BLOCK_SIZE - 1;
2389bf4852dSDavid S. Miller 		err = blkcipher_walk_done(desc, &walk, nbytes);
2399bf4852dSDavid S. Miller 	}
2409bf4852dSDavid S. Miller 	fprs_write(0);
2419bf4852dSDavid S. Miller 	return err;
2429bf4852dSDavid S. Miller }
2439bf4852dSDavid S. Miller 
2449bf4852dSDavid S. Miller static int ecb_decrypt(struct blkcipher_desc *desc,
2459bf4852dSDavid S. Miller 		       struct scatterlist *dst, struct scatterlist *src,
2469bf4852dSDavid S. Miller 		       unsigned int nbytes)
2479bf4852dSDavid S. Miller {
2489bf4852dSDavid S. Miller 	struct crypto_sparc64_aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
2499bf4852dSDavid S. Miller 	struct blkcipher_walk walk;
2509bf4852dSDavid S. Miller 	u64 *key_end;
2519bf4852dSDavid S. Miller 	int err;
2529bf4852dSDavid S. Miller 
2539bf4852dSDavid S. Miller 	blkcipher_walk_init(&walk, dst, src, nbytes);
2549bf4852dSDavid S. Miller 	err = blkcipher_walk_virt(desc, &walk);
255b35d282eSDavid S. Miller 	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
2569bf4852dSDavid S. Miller 
2570bdcaf74SDavid S. Miller 	ctx->ops->load_decrypt_keys(&ctx->key[0]);
2589bf4852dSDavid S. Miller 	key_end = &ctx->key[ctx->expanded_key_length / sizeof(u64)];
2599bf4852dSDavid S. Miller 	while ((nbytes = walk.nbytes)) {
2609bf4852dSDavid S. Miller 		unsigned int block_len = nbytes & AES_BLOCK_MASK;
2619bf4852dSDavid S. Miller 
2620bdcaf74SDavid S. Miller 		if (likely(block_len)) {
2630bdcaf74SDavid S. Miller 			ctx->ops->ecb_decrypt(key_end,
2640bdcaf74SDavid S. Miller 					      (const u64 *) walk.src.virt.addr,
2650bdcaf74SDavid S. Miller 					      (u64 *) walk.dst.virt.addr, block_len);
2660bdcaf74SDavid S. Miller 		}
2679bf4852dSDavid S. Miller 		nbytes &= AES_BLOCK_SIZE - 1;
2689bf4852dSDavid S. Miller 		err = blkcipher_walk_done(desc, &walk, nbytes);
2699bf4852dSDavid S. Miller 	}
2709bf4852dSDavid S. Miller 	fprs_write(0);
2719bf4852dSDavid S. Miller 
2729bf4852dSDavid S. Miller 	return err;
2739bf4852dSDavid S. Miller }
2749bf4852dSDavid S. Miller 
2759bf4852dSDavid S. Miller static int cbc_encrypt(struct blkcipher_desc *desc,
2769bf4852dSDavid S. Miller 		       struct scatterlist *dst, struct scatterlist *src,
2779bf4852dSDavid S. Miller 		       unsigned int nbytes)
2789bf4852dSDavid S. Miller {
2799bf4852dSDavid S. Miller 	struct crypto_sparc64_aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
2809bf4852dSDavid S. Miller 	struct blkcipher_walk walk;
2819bf4852dSDavid S. Miller 	int err;
2829bf4852dSDavid S. Miller 
2839bf4852dSDavid S. Miller 	blkcipher_walk_init(&walk, dst, src, nbytes);
2849bf4852dSDavid S. Miller 	err = blkcipher_walk_virt(desc, &walk);
285b35d282eSDavid S. Miller 	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
2869bf4852dSDavid S. Miller 
2870bdcaf74SDavid S. Miller 	ctx->ops->load_encrypt_keys(&ctx->key[0]);
2889bf4852dSDavid S. Miller 	while ((nbytes = walk.nbytes)) {
2899bf4852dSDavid S. Miller 		unsigned int block_len = nbytes & AES_BLOCK_MASK;
2909bf4852dSDavid S. Miller 
2919bf4852dSDavid S. Miller 		if (likely(block_len)) {
2920bdcaf74SDavid S. Miller 			ctx->ops->cbc_encrypt(&ctx->key[0],
2930bdcaf74SDavid S. Miller 					      (const u64 *)walk.src.virt.addr,
2940bdcaf74SDavid S. Miller 					      (u64 *) walk.dst.virt.addr,
2950bdcaf74SDavid S. Miller 					      block_len, (u64 *) walk.iv);
2969bf4852dSDavid S. Miller 		}
2979bf4852dSDavid S. Miller 		nbytes &= AES_BLOCK_SIZE - 1;
2989bf4852dSDavid S. Miller 		err = blkcipher_walk_done(desc, &walk, nbytes);
2999bf4852dSDavid S. Miller 	}
3009bf4852dSDavid S. Miller 	fprs_write(0);
3019bf4852dSDavid S. Miller 	return err;
3029bf4852dSDavid S. Miller }
3039bf4852dSDavid S. Miller 
3049bf4852dSDavid S. Miller static int cbc_decrypt(struct blkcipher_desc *desc,
3059bf4852dSDavid S. Miller 		       struct scatterlist *dst, struct scatterlist *src,
3069bf4852dSDavid S. Miller 		       unsigned int nbytes)
3079bf4852dSDavid S. Miller {
3089bf4852dSDavid S. Miller 	struct crypto_sparc64_aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
3099bf4852dSDavid S. Miller 	struct blkcipher_walk walk;
3109bf4852dSDavid S. Miller 	u64 *key_end;
3119bf4852dSDavid S. Miller 	int err;
3129bf4852dSDavid S. Miller 
3139bf4852dSDavid S. Miller 	blkcipher_walk_init(&walk, dst, src, nbytes);
3149bf4852dSDavid S. Miller 	err = blkcipher_walk_virt(desc, &walk);
315b35d282eSDavid S. Miller 	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
3169bf4852dSDavid S. Miller 
3170bdcaf74SDavid S. Miller 	ctx->ops->load_decrypt_keys(&ctx->key[0]);
3189bf4852dSDavid S. Miller 	key_end = &ctx->key[ctx->expanded_key_length / sizeof(u64)];
3199bf4852dSDavid S. Miller 	while ((nbytes = walk.nbytes)) {
3209bf4852dSDavid S. Miller 		unsigned int block_len = nbytes & AES_BLOCK_MASK;
3219bf4852dSDavid S. Miller 
3220bdcaf74SDavid S. Miller 		if (likely(block_len)) {
3230bdcaf74SDavid S. Miller 			ctx->ops->cbc_decrypt(key_end,
3240bdcaf74SDavid S. Miller 					      (const u64 *) walk.src.virt.addr,
3250bdcaf74SDavid S. Miller 					      (u64 *) walk.dst.virt.addr,
3269bf4852dSDavid S. Miller 					      block_len, (u64 *) walk.iv);
3270bdcaf74SDavid S. Miller 		}
3289bf4852dSDavid S. Miller 		nbytes &= AES_BLOCK_SIZE - 1;
3299bf4852dSDavid S. Miller 		err = blkcipher_walk_done(desc, &walk, nbytes);
3309bf4852dSDavid S. Miller 	}
3319bf4852dSDavid S. Miller 	fprs_write(0);
3329bf4852dSDavid S. Miller 
3339bf4852dSDavid S. Miller 	return err;
3349bf4852dSDavid S. Miller }
3359bf4852dSDavid S. Miller 
336a8d97cefSDavid S. Miller static void ctr_crypt_final(struct crypto_sparc64_aes_ctx *ctx,
337a8d97cefSDavid S. Miller 			    struct blkcipher_walk *walk)
338a8d97cefSDavid S. Miller {
339a8d97cefSDavid S. Miller 	u8 *ctrblk = walk->iv;
340a8d97cefSDavid S. Miller 	u64 keystream[AES_BLOCK_SIZE / sizeof(u64)];
341a8d97cefSDavid S. Miller 	u8 *src = walk->src.virt.addr;
342a8d97cefSDavid S. Miller 	u8 *dst = walk->dst.virt.addr;
343a8d97cefSDavid S. Miller 	unsigned int nbytes = walk->nbytes;
344a8d97cefSDavid S. Miller 
345a8d97cefSDavid S. Miller 	ctx->ops->ecb_encrypt(&ctx->key[0], (const u64 *)ctrblk,
346a8d97cefSDavid S. Miller 			      keystream, AES_BLOCK_SIZE);
34745fe93dfSArd Biesheuvel 	crypto_xor_cpy(dst, (u8 *) keystream, src, nbytes);
348a8d97cefSDavid S. Miller 	crypto_inc(ctrblk, AES_BLOCK_SIZE);
349a8d97cefSDavid S. Miller }
350a8d97cefSDavid S. Miller 
3519fd130ecSDavid S. Miller static int ctr_crypt(struct blkcipher_desc *desc,
3529fd130ecSDavid S. Miller 		     struct scatterlist *dst, struct scatterlist *src,
3539fd130ecSDavid S. Miller 		     unsigned int nbytes)
3549fd130ecSDavid S. Miller {
3559fd130ecSDavid S. Miller 	struct crypto_sparc64_aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
3569fd130ecSDavid S. Miller 	struct blkcipher_walk walk;
3579fd130ecSDavid S. Miller 	int err;
3589fd130ecSDavid S. Miller 
3599fd130ecSDavid S. Miller 	blkcipher_walk_init(&walk, dst, src, nbytes);
360a8d97cefSDavid S. Miller 	err = blkcipher_walk_virt_block(desc, &walk, AES_BLOCK_SIZE);
361a8d97cefSDavid S. Miller 	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
3629fd130ecSDavid S. Miller 
3639fd130ecSDavid S. Miller 	ctx->ops->load_encrypt_keys(&ctx->key[0]);
364a8d97cefSDavid S. Miller 	while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) {
3659fd130ecSDavid S. Miller 		unsigned int block_len = nbytes & AES_BLOCK_MASK;
3669fd130ecSDavid S. Miller 
3679fd130ecSDavid S. Miller 		if (likely(block_len)) {
3689fd130ecSDavid S. Miller 			ctx->ops->ctr_crypt(&ctx->key[0],
3699fd130ecSDavid S. Miller 					    (const u64 *)walk.src.virt.addr,
3709fd130ecSDavid S. Miller 					    (u64 *) walk.dst.virt.addr,
3719fd130ecSDavid S. Miller 					    block_len, (u64 *) walk.iv);
3729fd130ecSDavid S. Miller 		}
3739fd130ecSDavid S. Miller 		nbytes &= AES_BLOCK_SIZE - 1;
3749fd130ecSDavid S. Miller 		err = blkcipher_walk_done(desc, &walk, nbytes);
3759fd130ecSDavid S. Miller 	}
376a8d97cefSDavid S. Miller 	if (walk.nbytes) {
377a8d97cefSDavid S. Miller 		ctr_crypt_final(ctx, &walk);
378a8d97cefSDavid S. Miller 		err = blkcipher_walk_done(desc, &walk, 0);
379a8d97cefSDavid S. Miller 	}
3809fd130ecSDavid S. Miller 	fprs_write(0);
3819fd130ecSDavid S. Miller 	return err;
3829fd130ecSDavid S. Miller }
3839fd130ecSDavid S. Miller 
3849bf4852dSDavid S. Miller static struct crypto_alg algs[] = { {
3859bf4852dSDavid S. Miller 	.cra_name		= "aes",
3869bf4852dSDavid S. Miller 	.cra_driver_name	= "aes-sparc64",
38710803624SDavid S. Miller 	.cra_priority		= SPARC_CR_OPCODE_PRIORITY,
3889bf4852dSDavid S. Miller 	.cra_flags		= CRYPTO_ALG_TYPE_CIPHER,
3899bf4852dSDavid S. Miller 	.cra_blocksize		= AES_BLOCK_SIZE,
3909bf4852dSDavid S. Miller 	.cra_ctxsize		= sizeof(struct crypto_sparc64_aes_ctx),
3919bf4852dSDavid S. Miller 	.cra_alignmask		= 3,
3929bf4852dSDavid S. Miller 	.cra_module		= THIS_MODULE,
3939bf4852dSDavid S. Miller 	.cra_u	= {
3949bf4852dSDavid S. Miller 		.cipher	= {
3959bf4852dSDavid S. Miller 			.cia_min_keysize	= AES_MIN_KEY_SIZE,
3969bf4852dSDavid S. Miller 			.cia_max_keysize	= AES_MAX_KEY_SIZE,
3979bf4852dSDavid S. Miller 			.cia_setkey		= aes_set_key,
3989bf4852dSDavid S. Miller 			.cia_encrypt		= aes_encrypt,
3999bf4852dSDavid S. Miller 			.cia_decrypt		= aes_decrypt
4009bf4852dSDavid S. Miller 		}
4019bf4852dSDavid S. Miller 	}
4029bf4852dSDavid S. Miller }, {
4039bf4852dSDavid S. Miller 	.cra_name		= "ecb(aes)",
4049bf4852dSDavid S. Miller 	.cra_driver_name	= "ecb-aes-sparc64",
40510803624SDavid S. Miller 	.cra_priority		= SPARC_CR_OPCODE_PRIORITY,
4069bf4852dSDavid S. Miller 	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
4079bf4852dSDavid S. Miller 	.cra_blocksize		= AES_BLOCK_SIZE,
4089bf4852dSDavid S. Miller 	.cra_ctxsize		= sizeof(struct crypto_sparc64_aes_ctx),
4099bf4852dSDavid S. Miller 	.cra_alignmask		= 7,
4109bf4852dSDavid S. Miller 	.cra_type		= &crypto_blkcipher_type,
4119bf4852dSDavid S. Miller 	.cra_module		= THIS_MODULE,
4129bf4852dSDavid S. Miller 	.cra_u = {
4139bf4852dSDavid S. Miller 		.blkcipher = {
4149bf4852dSDavid S. Miller 			.min_keysize	= AES_MIN_KEY_SIZE,
4159bf4852dSDavid S. Miller 			.max_keysize	= AES_MAX_KEY_SIZE,
4169bf4852dSDavid S. Miller 			.setkey		= aes_set_key,
4179bf4852dSDavid S. Miller 			.encrypt	= ecb_encrypt,
4189bf4852dSDavid S. Miller 			.decrypt	= ecb_decrypt,
4199bf4852dSDavid S. Miller 		},
4209bf4852dSDavid S. Miller 	},
4219bf4852dSDavid S. Miller }, {
4229bf4852dSDavid S. Miller 	.cra_name		= "cbc(aes)",
4239bf4852dSDavid S. Miller 	.cra_driver_name	= "cbc-aes-sparc64",
42410803624SDavid S. Miller 	.cra_priority		= SPARC_CR_OPCODE_PRIORITY,
4259bf4852dSDavid S. Miller 	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
4269bf4852dSDavid S. Miller 	.cra_blocksize		= AES_BLOCK_SIZE,
4279bf4852dSDavid S. Miller 	.cra_ctxsize		= sizeof(struct crypto_sparc64_aes_ctx),
4289bf4852dSDavid S. Miller 	.cra_alignmask		= 7,
4299bf4852dSDavid S. Miller 	.cra_type		= &crypto_blkcipher_type,
4309bf4852dSDavid S. Miller 	.cra_module		= THIS_MODULE,
4319bf4852dSDavid S. Miller 	.cra_u = {
4329bf4852dSDavid S. Miller 		.blkcipher = {
4339bf4852dSDavid S. Miller 			.min_keysize	= AES_MIN_KEY_SIZE,
4349bf4852dSDavid S. Miller 			.max_keysize	= AES_MAX_KEY_SIZE,
435a66d7f72SDave Kleikamp 			.ivsize		= AES_BLOCK_SIZE,
4369bf4852dSDavid S. Miller 			.setkey		= aes_set_key,
4379bf4852dSDavid S. Miller 			.encrypt	= cbc_encrypt,
4389bf4852dSDavid S. Miller 			.decrypt	= cbc_decrypt,
4399bf4852dSDavid S. Miller 		},
4409bf4852dSDavid S. Miller 	},
4419fd130ecSDavid S. Miller }, {
4429fd130ecSDavid S. Miller 	.cra_name		= "ctr(aes)",
4439fd130ecSDavid S. Miller 	.cra_driver_name	= "ctr-aes-sparc64",
44410803624SDavid S. Miller 	.cra_priority		= SPARC_CR_OPCODE_PRIORITY,
4459fd130ecSDavid S. Miller 	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
446a8d97cefSDavid S. Miller 	.cra_blocksize		= 1,
4479fd130ecSDavid S. Miller 	.cra_ctxsize		= sizeof(struct crypto_sparc64_aes_ctx),
4489fd130ecSDavid S. Miller 	.cra_alignmask		= 7,
4499fd130ecSDavid S. Miller 	.cra_type		= &crypto_blkcipher_type,
4509fd130ecSDavid S. Miller 	.cra_module		= THIS_MODULE,
4519fd130ecSDavid S. Miller 	.cra_u = {
4529fd130ecSDavid S. Miller 		.blkcipher = {
4539fd130ecSDavid S. Miller 			.min_keysize	= AES_MIN_KEY_SIZE,
4549fd130ecSDavid S. Miller 			.max_keysize	= AES_MAX_KEY_SIZE,
455a66d7f72SDave Kleikamp 			.ivsize		= AES_BLOCK_SIZE,
4569fd130ecSDavid S. Miller 			.setkey		= aes_set_key,
4579fd130ecSDavid S. Miller 			.encrypt	= ctr_crypt,
4589fd130ecSDavid S. Miller 			.decrypt	= ctr_crypt,
4599fd130ecSDavid S. Miller 		},
4609fd130ecSDavid S. Miller 	},
4619bf4852dSDavid S. Miller } };
4629bf4852dSDavid S. Miller 
4639bf4852dSDavid S. Miller static bool __init sparc64_has_aes_opcode(void)
4649bf4852dSDavid S. Miller {
4659bf4852dSDavid S. Miller 	unsigned long cfr;
4669bf4852dSDavid S. Miller 
4679bf4852dSDavid S. Miller 	if (!(sparc64_elf_hwcap & HWCAP_SPARC_CRYPTO))
4689bf4852dSDavid S. Miller 		return false;
4699bf4852dSDavid S. Miller 
4709bf4852dSDavid S. Miller 	__asm__ __volatile__("rd %%asr26, %0" : "=r" (cfr));
4719bf4852dSDavid S. Miller 	if (!(cfr & CFR_AES))
4729bf4852dSDavid S. Miller 		return false;
4739bf4852dSDavid S. Miller 
4749bf4852dSDavid S. Miller 	return true;
4759bf4852dSDavid S. Miller }
4769bf4852dSDavid S. Miller 
4779bf4852dSDavid S. Miller static int __init aes_sparc64_mod_init(void)
4789bf4852dSDavid S. Miller {
4799bf4852dSDavid S. Miller 	int i;
4809bf4852dSDavid S. Miller 
4819bf4852dSDavid S. Miller 	for (i = 0; i < ARRAY_SIZE(algs); i++)
4829bf4852dSDavid S. Miller 		INIT_LIST_HEAD(&algs[i].cra_list);
4839bf4852dSDavid S. Miller 
4849bf4852dSDavid S. Miller 	if (sparc64_has_aes_opcode()) {
4859bf4852dSDavid S. Miller 		pr_info("Using sparc64 aes opcodes optimized AES implementation\n");
4869bf4852dSDavid S. Miller 		return crypto_register_algs(algs, ARRAY_SIZE(algs));
4879bf4852dSDavid S. Miller 	}
4889bf4852dSDavid S. Miller 	pr_info("sparc64 aes opcodes not available.\n");
4899bf4852dSDavid S. Miller 	return -ENODEV;
4909bf4852dSDavid S. Miller }
4919bf4852dSDavid S. Miller 
4929bf4852dSDavid S. Miller static void __exit aes_sparc64_mod_fini(void)
4939bf4852dSDavid S. Miller {
4949bf4852dSDavid S. Miller 	crypto_unregister_algs(algs, ARRAY_SIZE(algs));
4959bf4852dSDavid S. Miller }
4969bf4852dSDavid S. Miller 
4979bf4852dSDavid S. Miller module_init(aes_sparc64_mod_init);
4989bf4852dSDavid S. Miller module_exit(aes_sparc64_mod_fini);
4999bf4852dSDavid S. Miller 
5009bf4852dSDavid S. Miller MODULE_LICENSE("GPL");
501b0126417SMathias Krause MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm, sparc64 aes opcode accelerated");
5029bf4852dSDavid S. Miller 
5035d26a105SKees Cook MODULE_ALIAS_CRYPTO("aes");
504226f7ceaSDavid S. Miller 
505226f7ceaSDavid S. Miller #include "crop_devid.c"
506