xref: /openbmc/linux/arch/sparc/crypto/aes_glue.c (revision 674f368a)
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>
2764db5e74SEric Biggers #include <crypto/internal/skcipher.h>
289bf4852dSDavid S. Miller 
299bf4852dSDavid S. Miller #include <asm/fpumacro.h>
309bf4852dSDavid S. Miller #include <asm/pstate.h>
319bf4852dSDavid S. Miller #include <asm/elf.h>
329bf4852dSDavid S. Miller 
3310803624SDavid S. Miller #include "opcodes.h"
3410803624SDavid S. Miller 
350bdcaf74SDavid S. Miller struct aes_ops {
360bdcaf74SDavid S. Miller 	void (*encrypt)(const u64 *key, const u32 *input, u32 *output);
370bdcaf74SDavid S. Miller 	void (*decrypt)(const u64 *key, const u32 *input, u32 *output);
380bdcaf74SDavid S. Miller 	void (*load_encrypt_keys)(const u64 *key);
390bdcaf74SDavid S. Miller 	void (*load_decrypt_keys)(const u64 *key);
400bdcaf74SDavid S. Miller 	void (*ecb_encrypt)(const u64 *key, const u64 *input, u64 *output,
410bdcaf74SDavid S. Miller 			    unsigned int len);
420bdcaf74SDavid S. Miller 	void (*ecb_decrypt)(const u64 *key, const u64 *input, u64 *output,
430bdcaf74SDavid S. Miller 			    unsigned int len);
440bdcaf74SDavid S. Miller 	void (*cbc_encrypt)(const u64 *key, const u64 *input, u64 *output,
450bdcaf74SDavid S. Miller 			    unsigned int len, u64 *iv);
460bdcaf74SDavid S. Miller 	void (*cbc_decrypt)(const u64 *key, const u64 *input, u64 *output,
470bdcaf74SDavid S. Miller 			    unsigned int len, u64 *iv);
489fd130ecSDavid S. Miller 	void (*ctr_crypt)(const u64 *key, const u64 *input, u64 *output,
499fd130ecSDavid S. Miller 			  unsigned int len, u64 *iv);
500bdcaf74SDavid S. Miller };
510bdcaf74SDavid S. Miller 
529bf4852dSDavid S. Miller struct crypto_sparc64_aes_ctx {
530bdcaf74SDavid S. Miller 	struct aes_ops *ops;
549bf4852dSDavid S. Miller 	u64 key[AES_MAX_KEYLENGTH / sizeof(u64)];
559bf4852dSDavid S. Miller 	u32 key_length;
569bf4852dSDavid S. Miller 	u32 expanded_key_length;
579bf4852dSDavid S. Miller };
589bf4852dSDavid S. Miller 
590bdcaf74SDavid S. Miller extern void aes_sparc64_encrypt_128(const u64 *key, const u32 *input,
600bdcaf74SDavid S. Miller 				    u32 *output);
610bdcaf74SDavid S. Miller extern void aes_sparc64_encrypt_192(const u64 *key, const u32 *input,
620bdcaf74SDavid S. Miller 				    u32 *output);
630bdcaf74SDavid S. Miller extern void aes_sparc64_encrypt_256(const u64 *key, const u32 *input,
640bdcaf74SDavid S. Miller 				    u32 *output);
650bdcaf74SDavid S. Miller 
660bdcaf74SDavid S. Miller extern void aes_sparc64_decrypt_128(const u64 *key, const u32 *input,
670bdcaf74SDavid S. Miller 				    u32 *output);
680bdcaf74SDavid S. Miller extern void aes_sparc64_decrypt_192(const u64 *key, const u32 *input,
690bdcaf74SDavid S. Miller 				    u32 *output);
700bdcaf74SDavid S. Miller extern void aes_sparc64_decrypt_256(const u64 *key, const u32 *input,
710bdcaf74SDavid S. Miller 				    u32 *output);
720bdcaf74SDavid S. Miller 
730bdcaf74SDavid S. Miller extern void aes_sparc64_load_encrypt_keys_128(const u64 *key);
740bdcaf74SDavid S. Miller extern void aes_sparc64_load_encrypt_keys_192(const u64 *key);
750bdcaf74SDavid S. Miller extern void aes_sparc64_load_encrypt_keys_256(const u64 *key);
760bdcaf74SDavid S. Miller 
770bdcaf74SDavid S. Miller extern void aes_sparc64_load_decrypt_keys_128(const u64 *key);
780bdcaf74SDavid S. Miller extern void aes_sparc64_load_decrypt_keys_192(const u64 *key);
790bdcaf74SDavid S. Miller extern void aes_sparc64_load_decrypt_keys_256(const u64 *key);
800bdcaf74SDavid S. Miller 
810bdcaf74SDavid S. Miller extern void aes_sparc64_ecb_encrypt_128(const u64 *key, const u64 *input,
820bdcaf74SDavid S. Miller 					u64 *output, unsigned int len);
830bdcaf74SDavid S. Miller extern void aes_sparc64_ecb_encrypt_192(const u64 *key, const u64 *input,
840bdcaf74SDavid S. Miller 					u64 *output, unsigned int len);
850bdcaf74SDavid S. Miller extern void aes_sparc64_ecb_encrypt_256(const u64 *key, const u64 *input,
860bdcaf74SDavid S. Miller 					u64 *output, unsigned int len);
870bdcaf74SDavid S. Miller 
880bdcaf74SDavid S. Miller extern void aes_sparc64_ecb_decrypt_128(const u64 *key, const u64 *input,
890bdcaf74SDavid S. Miller 					u64 *output, unsigned int len);
900bdcaf74SDavid S. Miller extern void aes_sparc64_ecb_decrypt_192(const u64 *key, const u64 *input,
910bdcaf74SDavid S. Miller 					u64 *output, unsigned int len);
920bdcaf74SDavid S. Miller extern void aes_sparc64_ecb_decrypt_256(const u64 *key, const u64 *input,
930bdcaf74SDavid S. Miller 					u64 *output, unsigned int len);
940bdcaf74SDavid S. Miller 
950bdcaf74SDavid S. Miller extern void aes_sparc64_cbc_encrypt_128(const u64 *key, const u64 *input,
960bdcaf74SDavid S. Miller 					u64 *output, unsigned int len,
970bdcaf74SDavid S. Miller 					u64 *iv);
980bdcaf74SDavid S. Miller 
990bdcaf74SDavid S. Miller extern void aes_sparc64_cbc_encrypt_192(const u64 *key, const u64 *input,
1000bdcaf74SDavid S. Miller 					u64 *output, unsigned int len,
1010bdcaf74SDavid S. Miller 					u64 *iv);
1020bdcaf74SDavid S. Miller 
1030bdcaf74SDavid S. Miller extern void aes_sparc64_cbc_encrypt_256(const u64 *key, const u64 *input,
1040bdcaf74SDavid S. Miller 					u64 *output, unsigned int len,
1050bdcaf74SDavid S. Miller 					u64 *iv);
1060bdcaf74SDavid S. Miller 
1070bdcaf74SDavid S. Miller extern void aes_sparc64_cbc_decrypt_128(const u64 *key, const u64 *input,
1080bdcaf74SDavid S. Miller 					u64 *output, unsigned int len,
1090bdcaf74SDavid S. Miller 					u64 *iv);
1100bdcaf74SDavid S. Miller 
1110bdcaf74SDavid S. Miller extern void aes_sparc64_cbc_decrypt_192(const u64 *key, const u64 *input,
1120bdcaf74SDavid S. Miller 					u64 *output, unsigned int len,
1130bdcaf74SDavid S. Miller 					u64 *iv);
1140bdcaf74SDavid S. Miller 
1150bdcaf74SDavid S. Miller extern void aes_sparc64_cbc_decrypt_256(const u64 *key, const u64 *input,
1160bdcaf74SDavid S. Miller 					u64 *output, unsigned int len,
1170bdcaf74SDavid S. Miller 					u64 *iv);
1180bdcaf74SDavid S. Miller 
1199fd130ecSDavid S. Miller extern void aes_sparc64_ctr_crypt_128(const u64 *key, const u64 *input,
1209fd130ecSDavid S. Miller 				      u64 *output, unsigned int len,
1219fd130ecSDavid S. Miller 				      u64 *iv);
1229fd130ecSDavid S. Miller extern void aes_sparc64_ctr_crypt_192(const u64 *key, const u64 *input,
1239fd130ecSDavid S. Miller 				      u64 *output, unsigned int len,
1249fd130ecSDavid S. Miller 				      u64 *iv);
1259fd130ecSDavid S. Miller extern void aes_sparc64_ctr_crypt_256(const u64 *key, const u64 *input,
1269fd130ecSDavid S. Miller 				      u64 *output, unsigned int len,
1279fd130ecSDavid S. Miller 				      u64 *iv);
1289fd130ecSDavid S. Miller 
129756382cbSSam Ravnborg static struct aes_ops aes128_ops = {
1300bdcaf74SDavid S. Miller 	.encrypt		= aes_sparc64_encrypt_128,
1310bdcaf74SDavid S. Miller 	.decrypt		= aes_sparc64_decrypt_128,
1320bdcaf74SDavid S. Miller 	.load_encrypt_keys	= aes_sparc64_load_encrypt_keys_128,
1330bdcaf74SDavid S. Miller 	.load_decrypt_keys	= aes_sparc64_load_decrypt_keys_128,
1340bdcaf74SDavid S. Miller 	.ecb_encrypt		= aes_sparc64_ecb_encrypt_128,
1350bdcaf74SDavid S. Miller 	.ecb_decrypt		= aes_sparc64_ecb_decrypt_128,
1360bdcaf74SDavid S. Miller 	.cbc_encrypt		= aes_sparc64_cbc_encrypt_128,
1370bdcaf74SDavid S. Miller 	.cbc_decrypt		= aes_sparc64_cbc_decrypt_128,
1389fd130ecSDavid S. Miller 	.ctr_crypt		= aes_sparc64_ctr_crypt_128,
1390bdcaf74SDavid S. Miller };
1400bdcaf74SDavid S. Miller 
141756382cbSSam Ravnborg static struct aes_ops aes192_ops = {
1420bdcaf74SDavid S. Miller 	.encrypt		= aes_sparc64_encrypt_192,
1430bdcaf74SDavid S. Miller 	.decrypt		= aes_sparc64_decrypt_192,
1440bdcaf74SDavid S. Miller 	.load_encrypt_keys	= aes_sparc64_load_encrypt_keys_192,
1450bdcaf74SDavid S. Miller 	.load_decrypt_keys	= aes_sparc64_load_decrypt_keys_192,
1460bdcaf74SDavid S. Miller 	.ecb_encrypt		= aes_sparc64_ecb_encrypt_192,
1470bdcaf74SDavid S. Miller 	.ecb_decrypt		= aes_sparc64_ecb_decrypt_192,
1480bdcaf74SDavid S. Miller 	.cbc_encrypt		= aes_sparc64_cbc_encrypt_192,
1490bdcaf74SDavid S. Miller 	.cbc_decrypt		= aes_sparc64_cbc_decrypt_192,
1509fd130ecSDavid S. Miller 	.ctr_crypt		= aes_sparc64_ctr_crypt_192,
1510bdcaf74SDavid S. Miller };
1520bdcaf74SDavid S. Miller 
153756382cbSSam Ravnborg static struct aes_ops aes256_ops = {
1540bdcaf74SDavid S. Miller 	.encrypt		= aes_sparc64_encrypt_256,
1550bdcaf74SDavid S. Miller 	.decrypt		= aes_sparc64_decrypt_256,
1560bdcaf74SDavid S. Miller 	.load_encrypt_keys	= aes_sparc64_load_encrypt_keys_256,
1570bdcaf74SDavid S. Miller 	.load_decrypt_keys	= aes_sparc64_load_decrypt_keys_256,
1580bdcaf74SDavid S. Miller 	.ecb_encrypt		= aes_sparc64_ecb_encrypt_256,
1590bdcaf74SDavid S. Miller 	.ecb_decrypt		= aes_sparc64_ecb_decrypt_256,
1600bdcaf74SDavid S. Miller 	.cbc_encrypt		= aes_sparc64_cbc_encrypt_256,
1610bdcaf74SDavid S. Miller 	.cbc_decrypt		= aes_sparc64_cbc_decrypt_256,
1629fd130ecSDavid S. Miller 	.ctr_crypt		= aes_sparc64_ctr_crypt_256,
1630bdcaf74SDavid S. Miller };
1640bdcaf74SDavid S. Miller 
1659bf4852dSDavid S. Miller extern void aes_sparc64_key_expand(const u32 *in_key, u64 *output_key,
1669bf4852dSDavid S. Miller 				   unsigned int key_len);
1679bf4852dSDavid S. Miller 
aes_set_key(struct crypto_tfm * tfm,const u8 * in_key,unsigned int key_len)1689bf4852dSDavid S. Miller static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
1699bf4852dSDavid S. Miller 		       unsigned int key_len)
1709bf4852dSDavid S. Miller {
1719bf4852dSDavid S. Miller 	struct crypto_sparc64_aes_ctx *ctx = crypto_tfm_ctx(tfm);
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 		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 
aes_set_key_skcipher(struct crypto_skcipher * tfm,const u8 * in_key,unsigned int key_len)19964db5e74SEric Biggers static int aes_set_key_skcipher(struct crypto_skcipher *tfm, const u8 *in_key,
20064db5e74SEric Biggers 				unsigned int key_len)
20164db5e74SEric Biggers {
20264db5e74SEric Biggers 	return aes_set_key(crypto_skcipher_tfm(tfm), in_key, key_len);
20364db5e74SEric Biggers }
20464db5e74SEric Biggers 
crypto_aes_encrypt(struct crypto_tfm * tfm,u8 * dst,const u8 * src)205724ecd3cSArd Biesheuvel static void crypto_aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
2069bf4852dSDavid S. Miller {
2079bf4852dSDavid S. Miller 	struct crypto_sparc64_aes_ctx *ctx = crypto_tfm_ctx(tfm);
2089bf4852dSDavid S. Miller 
2090bdcaf74SDavid S. Miller 	ctx->ops->encrypt(&ctx->key[0], (const u32 *) src, (u32 *) dst);
2109bf4852dSDavid S. Miller }
2119bf4852dSDavid S. Miller 
crypto_aes_decrypt(struct crypto_tfm * tfm,u8 * dst,const u8 * src)212724ecd3cSArd Biesheuvel static void crypto_aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
2139bf4852dSDavid S. Miller {
2149bf4852dSDavid S. Miller 	struct crypto_sparc64_aes_ctx *ctx = crypto_tfm_ctx(tfm);
2159bf4852dSDavid S. Miller 
2160bdcaf74SDavid S. Miller 	ctx->ops->decrypt(&ctx->key[0], (const u32 *) src, (u32 *) dst);
2179bf4852dSDavid S. Miller }
2189bf4852dSDavid S. Miller 
ecb_encrypt(struct skcipher_request * req)21964db5e74SEric Biggers static int ecb_encrypt(struct skcipher_request *req)
2209bf4852dSDavid S. Miller {
22164db5e74SEric Biggers 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
22264db5e74SEric Biggers 	const struct crypto_sparc64_aes_ctx *ctx = crypto_skcipher_ctx(tfm);
22364db5e74SEric Biggers 	struct skcipher_walk walk;
22464db5e74SEric Biggers 	unsigned int nbytes;
2259bf4852dSDavid S. Miller 	int err;
2269bf4852dSDavid S. Miller 
22764db5e74SEric Biggers 	err = skcipher_walk_virt(&walk, req, true);
22864db5e74SEric Biggers 	if (err)
22964db5e74SEric Biggers 		return err;
2309bf4852dSDavid S. Miller 
2310bdcaf74SDavid S. Miller 	ctx->ops->load_encrypt_keys(&ctx->key[0]);
23264db5e74SEric Biggers 	while ((nbytes = walk.nbytes) != 0) {
23364db5e74SEric Biggers 		ctx->ops->ecb_encrypt(&ctx->key[0], walk.src.virt.addr,
23464db5e74SEric Biggers 				      walk.dst.virt.addr,
23564db5e74SEric Biggers 				      round_down(nbytes, AES_BLOCK_SIZE));
23664db5e74SEric Biggers 		err = skcipher_walk_done(&walk, nbytes % AES_BLOCK_SIZE);
2379bf4852dSDavid S. Miller 	}
2389bf4852dSDavid S. Miller 	fprs_write(0);
2399bf4852dSDavid S. Miller 	return err;
2409bf4852dSDavid S. Miller }
2419bf4852dSDavid S. Miller 
ecb_decrypt(struct skcipher_request * req)24264db5e74SEric Biggers static int ecb_decrypt(struct skcipher_request *req)
2439bf4852dSDavid S. Miller {
24464db5e74SEric Biggers 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
24564db5e74SEric Biggers 	const struct crypto_sparc64_aes_ctx *ctx = crypto_skcipher_ctx(tfm);
24664db5e74SEric Biggers 	const u64 *key_end;
24764db5e74SEric Biggers 	struct skcipher_walk walk;
24864db5e74SEric Biggers 	unsigned int nbytes;
2499bf4852dSDavid S. Miller 	int err;
2509bf4852dSDavid S. Miller 
25164db5e74SEric Biggers 	err = skcipher_walk_virt(&walk, req, true);
25264db5e74SEric Biggers 	if (err)
25364db5e74SEric Biggers 		return err;
2549bf4852dSDavid S. Miller 
2550bdcaf74SDavid S. Miller 	ctx->ops->load_decrypt_keys(&ctx->key[0]);
2569bf4852dSDavid S. Miller 	key_end = &ctx->key[ctx->expanded_key_length / sizeof(u64)];
25764db5e74SEric Biggers 	while ((nbytes = walk.nbytes) != 0) {
25864db5e74SEric Biggers 		ctx->ops->ecb_decrypt(key_end, walk.src.virt.addr,
25964db5e74SEric Biggers 				      walk.dst.virt.addr,
26064db5e74SEric Biggers 				      round_down(nbytes, AES_BLOCK_SIZE));
26164db5e74SEric Biggers 		err = skcipher_walk_done(&walk, nbytes % AES_BLOCK_SIZE);
2629bf4852dSDavid S. Miller 	}
2639bf4852dSDavid S. Miller 	fprs_write(0);
2649bf4852dSDavid S. Miller 
2659bf4852dSDavid S. Miller 	return err;
2669bf4852dSDavid S. Miller }
2679bf4852dSDavid S. Miller 
cbc_encrypt(struct skcipher_request * req)26864db5e74SEric Biggers static int cbc_encrypt(struct skcipher_request *req)
2699bf4852dSDavid S. Miller {
27064db5e74SEric Biggers 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
27164db5e74SEric Biggers 	const struct crypto_sparc64_aes_ctx *ctx = crypto_skcipher_ctx(tfm);
27264db5e74SEric Biggers 	struct skcipher_walk walk;
27364db5e74SEric Biggers 	unsigned int nbytes;
2749bf4852dSDavid S. Miller 	int err;
2759bf4852dSDavid S. Miller 
27664db5e74SEric Biggers 	err = skcipher_walk_virt(&walk, req, true);
27764db5e74SEric Biggers 	if (err)
27864db5e74SEric Biggers 		return err;
2799bf4852dSDavid S. Miller 
2800bdcaf74SDavid S. Miller 	ctx->ops->load_encrypt_keys(&ctx->key[0]);
28164db5e74SEric Biggers 	while ((nbytes = walk.nbytes) != 0) {
28264db5e74SEric Biggers 		ctx->ops->cbc_encrypt(&ctx->key[0], walk.src.virt.addr,
28364db5e74SEric Biggers 				      walk.dst.virt.addr,
28464db5e74SEric Biggers 				      round_down(nbytes, AES_BLOCK_SIZE),
28564db5e74SEric Biggers 				      walk.iv);
28664db5e74SEric Biggers 		err = skcipher_walk_done(&walk, nbytes % AES_BLOCK_SIZE);
2879bf4852dSDavid S. Miller 	}
2889bf4852dSDavid S. Miller 	fprs_write(0);
2899bf4852dSDavid S. Miller 	return err;
2909bf4852dSDavid S. Miller }
2919bf4852dSDavid S. Miller 
cbc_decrypt(struct skcipher_request * req)29264db5e74SEric Biggers static int cbc_decrypt(struct skcipher_request *req)
2939bf4852dSDavid S. Miller {
29464db5e74SEric Biggers 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
29564db5e74SEric Biggers 	const struct crypto_sparc64_aes_ctx *ctx = crypto_skcipher_ctx(tfm);
29664db5e74SEric Biggers 	const u64 *key_end;
29764db5e74SEric Biggers 	struct skcipher_walk walk;
29864db5e74SEric Biggers 	unsigned int nbytes;
2999bf4852dSDavid S. Miller 	int err;
3009bf4852dSDavid S. Miller 
30164db5e74SEric Biggers 	err = skcipher_walk_virt(&walk, req, true);
30264db5e74SEric Biggers 	if (err)
30364db5e74SEric Biggers 		return err;
3049bf4852dSDavid S. Miller 
3050bdcaf74SDavid S. Miller 	ctx->ops->load_decrypt_keys(&ctx->key[0]);
3069bf4852dSDavid S. Miller 	key_end = &ctx->key[ctx->expanded_key_length / sizeof(u64)];
30764db5e74SEric Biggers 	while ((nbytes = walk.nbytes) != 0) {
30864db5e74SEric Biggers 		ctx->ops->cbc_decrypt(key_end, walk.src.virt.addr,
30964db5e74SEric Biggers 				      walk.dst.virt.addr,
31064db5e74SEric Biggers 				      round_down(nbytes, AES_BLOCK_SIZE),
31164db5e74SEric Biggers 				      walk.iv);
31264db5e74SEric Biggers 		err = skcipher_walk_done(&walk, nbytes % AES_BLOCK_SIZE);
3139bf4852dSDavid S. Miller 	}
3149bf4852dSDavid S. Miller 	fprs_write(0);
3159bf4852dSDavid S. Miller 
3169bf4852dSDavid S. Miller 	return err;
3179bf4852dSDavid S. Miller }
3189bf4852dSDavid S. Miller 
ctr_crypt_final(const struct crypto_sparc64_aes_ctx * ctx,struct skcipher_walk * walk)31964db5e74SEric Biggers static void ctr_crypt_final(const struct crypto_sparc64_aes_ctx *ctx,
32064db5e74SEric Biggers 			    struct skcipher_walk *walk)
321a8d97cefSDavid S. Miller {
322a8d97cefSDavid S. Miller 	u8 *ctrblk = walk->iv;
323a8d97cefSDavid S. Miller 	u64 keystream[AES_BLOCK_SIZE / sizeof(u64)];
324a8d97cefSDavid S. Miller 	u8 *src = walk->src.virt.addr;
325a8d97cefSDavid S. Miller 	u8 *dst = walk->dst.virt.addr;
326a8d97cefSDavid S. Miller 	unsigned int nbytes = walk->nbytes;
327a8d97cefSDavid S. Miller 
328a8d97cefSDavid S. Miller 	ctx->ops->ecb_encrypt(&ctx->key[0], (const u64 *)ctrblk,
329a8d97cefSDavid S. Miller 			      keystream, AES_BLOCK_SIZE);
33045fe93dfSArd Biesheuvel 	crypto_xor_cpy(dst, (u8 *) keystream, src, nbytes);
331a8d97cefSDavid S. Miller 	crypto_inc(ctrblk, AES_BLOCK_SIZE);
332a8d97cefSDavid S. Miller }
333a8d97cefSDavid S. Miller 
ctr_crypt(struct skcipher_request * req)33464db5e74SEric Biggers static int ctr_crypt(struct skcipher_request *req)
3359fd130ecSDavid S. Miller {
33664db5e74SEric Biggers 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
33764db5e74SEric Biggers 	const struct crypto_sparc64_aes_ctx *ctx = crypto_skcipher_ctx(tfm);
33864db5e74SEric Biggers 	struct skcipher_walk walk;
33964db5e74SEric Biggers 	unsigned int nbytes;
3409fd130ecSDavid S. Miller 	int err;
3419fd130ecSDavid S. Miller 
34264db5e74SEric Biggers 	err = skcipher_walk_virt(&walk, req, true);
34364db5e74SEric Biggers 	if (err)
34464db5e74SEric Biggers 		return err;
3459fd130ecSDavid S. Miller 
3469fd130ecSDavid S. Miller 	ctx->ops->load_encrypt_keys(&ctx->key[0]);
347a8d97cefSDavid S. Miller 	while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) {
34864db5e74SEric Biggers 		ctx->ops->ctr_crypt(&ctx->key[0], walk.src.virt.addr,
34964db5e74SEric Biggers 				    walk.dst.virt.addr,
35064db5e74SEric Biggers 				    round_down(nbytes, AES_BLOCK_SIZE),
35164db5e74SEric Biggers 				    walk.iv);
35264db5e74SEric Biggers 		err = skcipher_walk_done(&walk, nbytes % AES_BLOCK_SIZE);
3539fd130ecSDavid S. Miller 	}
354a8d97cefSDavid S. Miller 	if (walk.nbytes) {
355a8d97cefSDavid S. Miller 		ctr_crypt_final(ctx, &walk);
35664db5e74SEric Biggers 		err = skcipher_walk_done(&walk, 0);
357a8d97cefSDavid S. Miller 	}
3589fd130ecSDavid S. Miller 	fprs_write(0);
3599fd130ecSDavid S. Miller 	return err;
3609fd130ecSDavid S. Miller }
3619fd130ecSDavid S. Miller 
36264db5e74SEric Biggers static struct crypto_alg cipher_alg = {
3639bf4852dSDavid S. Miller 	.cra_name		= "aes",
3649bf4852dSDavid S. Miller 	.cra_driver_name	= "aes-sparc64",
36510803624SDavid S. Miller 	.cra_priority		= SPARC_CR_OPCODE_PRIORITY,
3669bf4852dSDavid S. Miller 	.cra_flags		= CRYPTO_ALG_TYPE_CIPHER,
3679bf4852dSDavid S. Miller 	.cra_blocksize		= AES_BLOCK_SIZE,
3689bf4852dSDavid S. Miller 	.cra_ctxsize		= sizeof(struct crypto_sparc64_aes_ctx),
3699bf4852dSDavid S. Miller 	.cra_alignmask		= 3,
3709bf4852dSDavid S. Miller 	.cra_module		= THIS_MODULE,
3719bf4852dSDavid S. Miller 	.cra_u	= {
3729bf4852dSDavid S. Miller 		.cipher	= {
3739bf4852dSDavid S. Miller 			.cia_min_keysize	= AES_MIN_KEY_SIZE,
3749bf4852dSDavid S. Miller 			.cia_max_keysize	= AES_MAX_KEY_SIZE,
3759bf4852dSDavid S. Miller 			.cia_setkey		= aes_set_key,
376724ecd3cSArd Biesheuvel 			.cia_encrypt		= crypto_aes_encrypt,
377724ecd3cSArd Biesheuvel 			.cia_decrypt		= crypto_aes_decrypt
3789bf4852dSDavid S. Miller 		}
3799bf4852dSDavid S. Miller 	}
38064db5e74SEric Biggers };
38164db5e74SEric Biggers 
38264db5e74SEric Biggers static struct skcipher_alg skcipher_algs[] = {
38364db5e74SEric Biggers 	{
38464db5e74SEric Biggers 		.base.cra_name		= "ecb(aes)",
38564db5e74SEric Biggers 		.base.cra_driver_name	= "ecb-aes-sparc64",
38664db5e74SEric Biggers 		.base.cra_priority	= SPARC_CR_OPCODE_PRIORITY,
38764db5e74SEric Biggers 		.base.cra_blocksize	= AES_BLOCK_SIZE,
38864db5e74SEric Biggers 		.base.cra_ctxsize	= sizeof(struct crypto_sparc64_aes_ctx),
38964db5e74SEric Biggers 		.base.cra_alignmask	= 7,
39064db5e74SEric Biggers 		.base.cra_module	= THIS_MODULE,
3919bf4852dSDavid S. Miller 		.min_keysize		= AES_MIN_KEY_SIZE,
3929bf4852dSDavid S. Miller 		.max_keysize		= AES_MAX_KEY_SIZE,
39364db5e74SEric Biggers 		.setkey			= aes_set_key_skcipher,
3949bf4852dSDavid S. Miller 		.encrypt		= ecb_encrypt,
3959bf4852dSDavid S. Miller 		.decrypt		= ecb_decrypt,
3969bf4852dSDavid S. Miller 	}, {
39764db5e74SEric Biggers 		.base.cra_name		= "cbc(aes)",
39864db5e74SEric Biggers 		.base.cra_driver_name	= "cbc-aes-sparc64",
39964db5e74SEric Biggers 		.base.cra_priority	= SPARC_CR_OPCODE_PRIORITY,
40064db5e74SEric Biggers 		.base.cra_blocksize	= AES_BLOCK_SIZE,
40164db5e74SEric Biggers 		.base.cra_ctxsize	= sizeof(struct crypto_sparc64_aes_ctx),
40264db5e74SEric Biggers 		.base.cra_alignmask	= 7,
40364db5e74SEric Biggers 		.base.cra_module	= THIS_MODULE,
4049bf4852dSDavid S. Miller 		.min_keysize		= AES_MIN_KEY_SIZE,
4059bf4852dSDavid S. Miller 		.max_keysize		= AES_MAX_KEY_SIZE,
406a66d7f72SDave Kleikamp 		.ivsize			= AES_BLOCK_SIZE,
40764db5e74SEric Biggers 		.setkey			= aes_set_key_skcipher,
4089bf4852dSDavid S. Miller 		.encrypt		= cbc_encrypt,
4099bf4852dSDavid S. Miller 		.decrypt		= cbc_decrypt,
4109fd130ecSDavid S. Miller 	}, {
41164db5e74SEric Biggers 		.base.cra_name		= "ctr(aes)",
41264db5e74SEric Biggers 		.base.cra_driver_name	= "ctr-aes-sparc64",
41364db5e74SEric Biggers 		.base.cra_priority	= SPARC_CR_OPCODE_PRIORITY,
41464db5e74SEric Biggers 		.base.cra_blocksize	= 1,
41564db5e74SEric Biggers 		.base.cra_ctxsize	= sizeof(struct crypto_sparc64_aes_ctx),
41664db5e74SEric Biggers 		.base.cra_alignmask	= 7,
41764db5e74SEric Biggers 		.base.cra_module	= THIS_MODULE,
4189fd130ecSDavid S. Miller 		.min_keysize		= AES_MIN_KEY_SIZE,
4199fd130ecSDavid S. Miller 		.max_keysize		= AES_MAX_KEY_SIZE,
420a66d7f72SDave Kleikamp 		.ivsize			= AES_BLOCK_SIZE,
42164db5e74SEric Biggers 		.setkey			= aes_set_key_skcipher,
4229fd130ecSDavid S. Miller 		.encrypt		= ctr_crypt,
4239fd130ecSDavid S. Miller 		.decrypt		= ctr_crypt,
42464db5e74SEric Biggers 		.chunksize		= AES_BLOCK_SIZE,
42564db5e74SEric Biggers 	}
42664db5e74SEric Biggers };
4279bf4852dSDavid S. Miller 
sparc64_has_aes_opcode(void)4289bf4852dSDavid S. Miller static bool __init sparc64_has_aes_opcode(void)
4299bf4852dSDavid S. Miller {
4309bf4852dSDavid S. Miller 	unsigned long cfr;
4319bf4852dSDavid S. Miller 
4329bf4852dSDavid S. Miller 	if (!(sparc64_elf_hwcap & HWCAP_SPARC_CRYPTO))
4339bf4852dSDavid S. Miller 		return false;
4349bf4852dSDavid S. Miller 
4359bf4852dSDavid S. Miller 	__asm__ __volatile__("rd %%asr26, %0" : "=r" (cfr));
4369bf4852dSDavid S. Miller 	if (!(cfr & CFR_AES))
4379bf4852dSDavid S. Miller 		return false;
4389bf4852dSDavid S. Miller 
4399bf4852dSDavid S. Miller 	return true;
4409bf4852dSDavid S. Miller }
4419bf4852dSDavid S. Miller 
aes_sparc64_mod_init(void)4429bf4852dSDavid S. Miller static int __init aes_sparc64_mod_init(void)
4439bf4852dSDavid S. Miller {
44464db5e74SEric Biggers 	int err;
44564db5e74SEric Biggers 
44664db5e74SEric Biggers 	if (!sparc64_has_aes_opcode()) {
4479bf4852dSDavid S. Miller 		pr_info("sparc64 aes opcodes not available.\n");
4489bf4852dSDavid S. Miller 		return -ENODEV;
4499bf4852dSDavid S. Miller 	}
45064db5e74SEric Biggers 	pr_info("Using sparc64 aes opcodes optimized AES implementation\n");
45164db5e74SEric Biggers 	err = crypto_register_alg(&cipher_alg);
45264db5e74SEric Biggers 	if (err)
45364db5e74SEric Biggers 		return err;
45464db5e74SEric Biggers 	err = crypto_register_skciphers(skcipher_algs,
45564db5e74SEric Biggers 					ARRAY_SIZE(skcipher_algs));
45664db5e74SEric Biggers 	if (err)
45764db5e74SEric Biggers 		crypto_unregister_alg(&cipher_alg);
45864db5e74SEric Biggers 	return err;
45964db5e74SEric Biggers }
4609bf4852dSDavid S. Miller 
aes_sparc64_mod_fini(void)4619bf4852dSDavid S. Miller static void __exit aes_sparc64_mod_fini(void)
4629bf4852dSDavid S. Miller {
46364db5e74SEric Biggers 	crypto_unregister_alg(&cipher_alg);
46464db5e74SEric Biggers 	crypto_unregister_skciphers(skcipher_algs, ARRAY_SIZE(skcipher_algs));
4659bf4852dSDavid S. Miller }
4669bf4852dSDavid S. Miller 
4679bf4852dSDavid S. Miller module_init(aes_sparc64_mod_init);
4689bf4852dSDavid S. Miller module_exit(aes_sparc64_mod_fini);
4699bf4852dSDavid S. Miller 
4709bf4852dSDavid S. Miller MODULE_LICENSE("GPL");
471b0126417SMathias Krause MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm, sparc64 aes opcode accelerated");
4729bf4852dSDavid S. Miller 
4735d26a105SKees Cook MODULE_ALIAS_CRYPTO("aes");
474226f7ceaSDavid S. Miller 
475226f7ceaSDavid S. Miller #include "crop_devid.c"
476