162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Bit sliced AES using NEON instructions
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2016 - 2017 Linaro Ltd <ard.biesheuvel@linaro.org>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <asm/neon.h>
962306a36Sopenharmony_ci#include <asm/simd.h>
1062306a36Sopenharmony_ci#include <crypto/aes.h>
1162306a36Sopenharmony_ci#include <crypto/ctr.h>
1262306a36Sopenharmony_ci#include <crypto/internal/simd.h>
1362306a36Sopenharmony_ci#include <crypto/internal/skcipher.h>
1462306a36Sopenharmony_ci#include <crypto/scatterwalk.h>
1562306a36Sopenharmony_ci#include <crypto/xts.h>
1662306a36Sopenharmony_ci#include <linux/module.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ciMODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
1962306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("ecb(aes)");
2262306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("cbc(aes)");
2362306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("ctr(aes)");
2462306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("xts(aes)");
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ciasmlinkage void aesbs_convert_key(u8 out[], u32 const rk[], int rounds);
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ciasmlinkage void aesbs_ecb_encrypt(u8 out[], u8 const in[], u8 const rk[],
2962306a36Sopenharmony_ci				  int rounds, int blocks);
3062306a36Sopenharmony_ciasmlinkage void aesbs_ecb_decrypt(u8 out[], u8 const in[], u8 const rk[],
3162306a36Sopenharmony_ci				  int rounds, int blocks);
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ciasmlinkage void aesbs_cbc_decrypt(u8 out[], u8 const in[], u8 const rk[],
3462306a36Sopenharmony_ci				  int rounds, int blocks, u8 iv[]);
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ciasmlinkage void aesbs_ctr_encrypt(u8 out[], u8 const in[], u8 const rk[],
3762306a36Sopenharmony_ci				  int rounds, int blocks, u8 iv[]);
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ciasmlinkage void aesbs_xts_encrypt(u8 out[], u8 const in[], u8 const rk[],
4062306a36Sopenharmony_ci				  int rounds, int blocks, u8 iv[]);
4162306a36Sopenharmony_ciasmlinkage void aesbs_xts_decrypt(u8 out[], u8 const in[], u8 const rk[],
4262306a36Sopenharmony_ci				  int rounds, int blocks, u8 iv[]);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci/* borrowed from aes-neon-blk.ko */
4562306a36Sopenharmony_ciasmlinkage void neon_aes_ecb_encrypt(u8 out[], u8 const in[], u32 const rk[],
4662306a36Sopenharmony_ci				     int rounds, int blocks);
4762306a36Sopenharmony_ciasmlinkage void neon_aes_cbc_encrypt(u8 out[], u8 const in[], u32 const rk[],
4862306a36Sopenharmony_ci				     int rounds, int blocks, u8 iv[]);
4962306a36Sopenharmony_ciasmlinkage void neon_aes_ctr_encrypt(u8 out[], u8 const in[], u32 const rk[],
5062306a36Sopenharmony_ci				     int rounds, int bytes, u8 ctr[]);
5162306a36Sopenharmony_ciasmlinkage void neon_aes_xts_encrypt(u8 out[], u8 const in[],
5262306a36Sopenharmony_ci				     u32 const rk1[], int rounds, int bytes,
5362306a36Sopenharmony_ci				     u32 const rk2[], u8 iv[], int first);
5462306a36Sopenharmony_ciasmlinkage void neon_aes_xts_decrypt(u8 out[], u8 const in[],
5562306a36Sopenharmony_ci				     u32 const rk1[], int rounds, int bytes,
5662306a36Sopenharmony_ci				     u32 const rk2[], u8 iv[], int first);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistruct aesbs_ctx {
5962306a36Sopenharmony_ci	u8	rk[13 * (8 * AES_BLOCK_SIZE) + 32];
6062306a36Sopenharmony_ci	int	rounds;
6162306a36Sopenharmony_ci} __aligned(AES_BLOCK_SIZE);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistruct aesbs_cbc_ctr_ctx {
6462306a36Sopenharmony_ci	struct aesbs_ctx	key;
6562306a36Sopenharmony_ci	u32			enc[AES_MAX_KEYLENGTH_U32];
6662306a36Sopenharmony_ci};
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistruct aesbs_xts_ctx {
6962306a36Sopenharmony_ci	struct aesbs_ctx	key;
7062306a36Sopenharmony_ci	u32			twkey[AES_MAX_KEYLENGTH_U32];
7162306a36Sopenharmony_ci	struct crypto_aes_ctx	cts;
7262306a36Sopenharmony_ci};
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic int aesbs_setkey(struct crypto_skcipher *tfm, const u8 *in_key,
7562306a36Sopenharmony_ci			unsigned int key_len)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	struct aesbs_ctx *ctx = crypto_skcipher_ctx(tfm);
7862306a36Sopenharmony_ci	struct crypto_aes_ctx rk;
7962306a36Sopenharmony_ci	int err;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	err = aes_expandkey(&rk, in_key, key_len);
8262306a36Sopenharmony_ci	if (err)
8362306a36Sopenharmony_ci		return err;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	ctx->rounds = 6 + key_len / 4;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	kernel_neon_begin();
8862306a36Sopenharmony_ci	aesbs_convert_key(ctx->rk, rk.key_enc, ctx->rounds);
8962306a36Sopenharmony_ci	kernel_neon_end();
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	return 0;
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic int __ecb_crypt(struct skcipher_request *req,
9562306a36Sopenharmony_ci		       void (*fn)(u8 out[], u8 const in[], u8 const rk[],
9662306a36Sopenharmony_ci				  int rounds, int blocks))
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
9962306a36Sopenharmony_ci	struct aesbs_ctx *ctx = crypto_skcipher_ctx(tfm);
10062306a36Sopenharmony_ci	struct skcipher_walk walk;
10162306a36Sopenharmony_ci	int err;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, false);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	while (walk.nbytes >= AES_BLOCK_SIZE) {
10662306a36Sopenharmony_ci		unsigned int blocks = walk.nbytes / AES_BLOCK_SIZE;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci		if (walk.nbytes < walk.total)
10962306a36Sopenharmony_ci			blocks = round_down(blocks,
11062306a36Sopenharmony_ci					    walk.stride / AES_BLOCK_SIZE);
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci		kernel_neon_begin();
11362306a36Sopenharmony_ci		fn(walk.dst.virt.addr, walk.src.virt.addr, ctx->rk,
11462306a36Sopenharmony_ci		   ctx->rounds, blocks);
11562306a36Sopenharmony_ci		kernel_neon_end();
11662306a36Sopenharmony_ci		err = skcipher_walk_done(&walk,
11762306a36Sopenharmony_ci					 walk.nbytes - blocks * AES_BLOCK_SIZE);
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	return err;
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic int ecb_encrypt(struct skcipher_request *req)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	return __ecb_crypt(req, aesbs_ecb_encrypt);
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic int ecb_decrypt(struct skcipher_request *req)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	return __ecb_crypt(req, aesbs_ecb_decrypt);
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic int aesbs_cbc_ctr_setkey(struct crypto_skcipher *tfm, const u8 *in_key,
13462306a36Sopenharmony_ci			    unsigned int key_len)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	struct aesbs_cbc_ctr_ctx *ctx = crypto_skcipher_ctx(tfm);
13762306a36Sopenharmony_ci	struct crypto_aes_ctx rk;
13862306a36Sopenharmony_ci	int err;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	err = aes_expandkey(&rk, in_key, key_len);
14162306a36Sopenharmony_ci	if (err)
14262306a36Sopenharmony_ci		return err;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	ctx->key.rounds = 6 + key_len / 4;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	memcpy(ctx->enc, rk.key_enc, sizeof(ctx->enc));
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	kernel_neon_begin();
14962306a36Sopenharmony_ci	aesbs_convert_key(ctx->key.rk, rk.key_enc, ctx->key.rounds);
15062306a36Sopenharmony_ci	kernel_neon_end();
15162306a36Sopenharmony_ci	memzero_explicit(&rk, sizeof(rk));
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	return 0;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic int cbc_encrypt(struct skcipher_request *req)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
15962306a36Sopenharmony_ci	struct aesbs_cbc_ctr_ctx *ctx = crypto_skcipher_ctx(tfm);
16062306a36Sopenharmony_ci	struct skcipher_walk walk;
16162306a36Sopenharmony_ci	int err;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, false);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	while (walk.nbytes >= AES_BLOCK_SIZE) {
16662306a36Sopenharmony_ci		unsigned int blocks = walk.nbytes / AES_BLOCK_SIZE;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci		/* fall back to the non-bitsliced NEON implementation */
16962306a36Sopenharmony_ci		kernel_neon_begin();
17062306a36Sopenharmony_ci		neon_aes_cbc_encrypt(walk.dst.virt.addr, walk.src.virt.addr,
17162306a36Sopenharmony_ci				     ctx->enc, ctx->key.rounds, blocks,
17262306a36Sopenharmony_ci				     walk.iv);
17362306a36Sopenharmony_ci		kernel_neon_end();
17462306a36Sopenharmony_ci		err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE);
17562306a36Sopenharmony_ci	}
17662306a36Sopenharmony_ci	return err;
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic int cbc_decrypt(struct skcipher_request *req)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
18262306a36Sopenharmony_ci	struct aesbs_cbc_ctr_ctx *ctx = crypto_skcipher_ctx(tfm);
18362306a36Sopenharmony_ci	struct skcipher_walk walk;
18462306a36Sopenharmony_ci	int err;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, false);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	while (walk.nbytes >= AES_BLOCK_SIZE) {
18962306a36Sopenharmony_ci		unsigned int blocks = walk.nbytes / AES_BLOCK_SIZE;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci		if (walk.nbytes < walk.total)
19262306a36Sopenharmony_ci			blocks = round_down(blocks,
19362306a36Sopenharmony_ci					    walk.stride / AES_BLOCK_SIZE);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci		kernel_neon_begin();
19662306a36Sopenharmony_ci		aesbs_cbc_decrypt(walk.dst.virt.addr, walk.src.virt.addr,
19762306a36Sopenharmony_ci				  ctx->key.rk, ctx->key.rounds, blocks,
19862306a36Sopenharmony_ci				  walk.iv);
19962306a36Sopenharmony_ci		kernel_neon_end();
20062306a36Sopenharmony_ci		err = skcipher_walk_done(&walk,
20162306a36Sopenharmony_ci					 walk.nbytes - blocks * AES_BLOCK_SIZE);
20262306a36Sopenharmony_ci	}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	return err;
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistatic int ctr_encrypt(struct skcipher_request *req)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
21062306a36Sopenharmony_ci	struct aesbs_cbc_ctr_ctx *ctx = crypto_skcipher_ctx(tfm);
21162306a36Sopenharmony_ci	struct skcipher_walk walk;
21262306a36Sopenharmony_ci	int err;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, false);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	while (walk.nbytes > 0) {
21762306a36Sopenharmony_ci		int blocks = (walk.nbytes / AES_BLOCK_SIZE) & ~7;
21862306a36Sopenharmony_ci		int nbytes = walk.nbytes % (8 * AES_BLOCK_SIZE);
21962306a36Sopenharmony_ci		const u8 *src = walk.src.virt.addr;
22062306a36Sopenharmony_ci		u8 *dst = walk.dst.virt.addr;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci		kernel_neon_begin();
22362306a36Sopenharmony_ci		if (blocks >= 8) {
22462306a36Sopenharmony_ci			aesbs_ctr_encrypt(dst, src, ctx->key.rk, ctx->key.rounds,
22562306a36Sopenharmony_ci					  blocks, walk.iv);
22662306a36Sopenharmony_ci			dst += blocks * AES_BLOCK_SIZE;
22762306a36Sopenharmony_ci			src += blocks * AES_BLOCK_SIZE;
22862306a36Sopenharmony_ci		}
22962306a36Sopenharmony_ci		if (nbytes && walk.nbytes == walk.total) {
23062306a36Sopenharmony_ci			u8 buf[AES_BLOCK_SIZE];
23162306a36Sopenharmony_ci			u8 *d = dst;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci			if (unlikely(nbytes < AES_BLOCK_SIZE))
23462306a36Sopenharmony_ci				src = dst = memcpy(buf + sizeof(buf) - nbytes,
23562306a36Sopenharmony_ci						   src, nbytes);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci			neon_aes_ctr_encrypt(dst, src, ctx->enc, ctx->key.rounds,
23862306a36Sopenharmony_ci					     nbytes, walk.iv);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci			if (unlikely(nbytes < AES_BLOCK_SIZE))
24162306a36Sopenharmony_ci				memcpy(d, dst, nbytes);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci			nbytes = 0;
24462306a36Sopenharmony_ci		}
24562306a36Sopenharmony_ci		kernel_neon_end();
24662306a36Sopenharmony_ci		err = skcipher_walk_done(&walk, nbytes);
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci	return err;
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic int aesbs_xts_setkey(struct crypto_skcipher *tfm, const u8 *in_key,
25262306a36Sopenharmony_ci			    unsigned int key_len)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	struct aesbs_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
25562306a36Sopenharmony_ci	struct crypto_aes_ctx rk;
25662306a36Sopenharmony_ci	int err;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	err = xts_verify_key(tfm, in_key, key_len);
25962306a36Sopenharmony_ci	if (err)
26062306a36Sopenharmony_ci		return err;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	key_len /= 2;
26362306a36Sopenharmony_ci	err = aes_expandkey(&ctx->cts, in_key, key_len);
26462306a36Sopenharmony_ci	if (err)
26562306a36Sopenharmony_ci		return err;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	err = aes_expandkey(&rk, in_key + key_len, key_len);
26862306a36Sopenharmony_ci	if (err)
26962306a36Sopenharmony_ci		return err;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	memcpy(ctx->twkey, rk.key_enc, sizeof(ctx->twkey));
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	return aesbs_setkey(tfm, in_key, key_len);
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic int __xts_crypt(struct skcipher_request *req, bool encrypt,
27762306a36Sopenharmony_ci		       void (*fn)(u8 out[], u8 const in[], u8 const rk[],
27862306a36Sopenharmony_ci				  int rounds, int blocks, u8 iv[]))
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
28162306a36Sopenharmony_ci	struct aesbs_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
28262306a36Sopenharmony_ci	int tail = req->cryptlen % (8 * AES_BLOCK_SIZE);
28362306a36Sopenharmony_ci	struct scatterlist sg_src[2], sg_dst[2];
28462306a36Sopenharmony_ci	struct skcipher_request subreq;
28562306a36Sopenharmony_ci	struct scatterlist *src, *dst;
28662306a36Sopenharmony_ci	struct skcipher_walk walk;
28762306a36Sopenharmony_ci	int nbytes, err;
28862306a36Sopenharmony_ci	int first = 1;
28962306a36Sopenharmony_ci	u8 *out, *in;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	if (req->cryptlen < AES_BLOCK_SIZE)
29262306a36Sopenharmony_ci		return -EINVAL;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	/* ensure that the cts tail is covered by a single step */
29562306a36Sopenharmony_ci	if (unlikely(tail > 0 && tail < AES_BLOCK_SIZE)) {
29662306a36Sopenharmony_ci		int xts_blocks = DIV_ROUND_UP(req->cryptlen,
29762306a36Sopenharmony_ci					      AES_BLOCK_SIZE) - 2;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci		skcipher_request_set_tfm(&subreq, tfm);
30062306a36Sopenharmony_ci		skcipher_request_set_callback(&subreq,
30162306a36Sopenharmony_ci					      skcipher_request_flags(req),
30262306a36Sopenharmony_ci					      NULL, NULL);
30362306a36Sopenharmony_ci		skcipher_request_set_crypt(&subreq, req->src, req->dst,
30462306a36Sopenharmony_ci					   xts_blocks * AES_BLOCK_SIZE,
30562306a36Sopenharmony_ci					   req->iv);
30662306a36Sopenharmony_ci		req = &subreq;
30762306a36Sopenharmony_ci	} else {
30862306a36Sopenharmony_ci		tail = 0;
30962306a36Sopenharmony_ci	}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, false);
31262306a36Sopenharmony_ci	if (err)
31362306a36Sopenharmony_ci		return err;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	while (walk.nbytes >= AES_BLOCK_SIZE) {
31662306a36Sopenharmony_ci		int blocks = (walk.nbytes / AES_BLOCK_SIZE) & ~7;
31762306a36Sopenharmony_ci		out = walk.dst.virt.addr;
31862306a36Sopenharmony_ci		in = walk.src.virt.addr;
31962306a36Sopenharmony_ci		nbytes = walk.nbytes;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci		kernel_neon_begin();
32262306a36Sopenharmony_ci		if (blocks >= 8) {
32362306a36Sopenharmony_ci			if (first == 1)
32462306a36Sopenharmony_ci				neon_aes_ecb_encrypt(walk.iv, walk.iv,
32562306a36Sopenharmony_ci						     ctx->twkey,
32662306a36Sopenharmony_ci						     ctx->key.rounds, 1);
32762306a36Sopenharmony_ci			first = 2;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci			fn(out, in, ctx->key.rk, ctx->key.rounds, blocks,
33062306a36Sopenharmony_ci			   walk.iv);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci			out += blocks * AES_BLOCK_SIZE;
33362306a36Sopenharmony_ci			in += blocks * AES_BLOCK_SIZE;
33462306a36Sopenharmony_ci			nbytes -= blocks * AES_BLOCK_SIZE;
33562306a36Sopenharmony_ci		}
33662306a36Sopenharmony_ci		if (walk.nbytes == walk.total && nbytes > 0) {
33762306a36Sopenharmony_ci			if (encrypt)
33862306a36Sopenharmony_ci				neon_aes_xts_encrypt(out, in, ctx->cts.key_enc,
33962306a36Sopenharmony_ci						     ctx->key.rounds, nbytes,
34062306a36Sopenharmony_ci						     ctx->twkey, walk.iv, first);
34162306a36Sopenharmony_ci			else
34262306a36Sopenharmony_ci				neon_aes_xts_decrypt(out, in, ctx->cts.key_dec,
34362306a36Sopenharmony_ci						     ctx->key.rounds, nbytes,
34462306a36Sopenharmony_ci						     ctx->twkey, walk.iv, first);
34562306a36Sopenharmony_ci			nbytes = first = 0;
34662306a36Sopenharmony_ci		}
34762306a36Sopenharmony_ci		kernel_neon_end();
34862306a36Sopenharmony_ci		err = skcipher_walk_done(&walk, nbytes);
34962306a36Sopenharmony_ci	}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	if (err || likely(!tail))
35262306a36Sopenharmony_ci		return err;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	/* handle ciphertext stealing */
35562306a36Sopenharmony_ci	dst = src = scatterwalk_ffwd(sg_src, req->src, req->cryptlen);
35662306a36Sopenharmony_ci	if (req->dst != req->src)
35762306a36Sopenharmony_ci		dst = scatterwalk_ffwd(sg_dst, req->dst, req->cryptlen);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	skcipher_request_set_crypt(req, src, dst, AES_BLOCK_SIZE + tail,
36062306a36Sopenharmony_ci				   req->iv);
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, false);
36362306a36Sopenharmony_ci	if (err)
36462306a36Sopenharmony_ci		return err;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	out = walk.dst.virt.addr;
36762306a36Sopenharmony_ci	in = walk.src.virt.addr;
36862306a36Sopenharmony_ci	nbytes = walk.nbytes;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	kernel_neon_begin();
37162306a36Sopenharmony_ci	if (encrypt)
37262306a36Sopenharmony_ci		neon_aes_xts_encrypt(out, in, ctx->cts.key_enc, ctx->key.rounds,
37362306a36Sopenharmony_ci				     nbytes, ctx->twkey, walk.iv, first);
37462306a36Sopenharmony_ci	else
37562306a36Sopenharmony_ci		neon_aes_xts_decrypt(out, in, ctx->cts.key_dec, ctx->key.rounds,
37662306a36Sopenharmony_ci				     nbytes, ctx->twkey, walk.iv, first);
37762306a36Sopenharmony_ci	kernel_neon_end();
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	return skcipher_walk_done(&walk, 0);
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_cistatic int xts_encrypt(struct skcipher_request *req)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	return __xts_crypt(req, true, aesbs_xts_encrypt);
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_cistatic int xts_decrypt(struct skcipher_request *req)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	return __xts_crypt(req, false, aesbs_xts_decrypt);
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cistatic struct skcipher_alg aes_algs[] = { {
39362306a36Sopenharmony_ci	.base.cra_name		= "ecb(aes)",
39462306a36Sopenharmony_ci	.base.cra_driver_name	= "ecb-aes-neonbs",
39562306a36Sopenharmony_ci	.base.cra_priority	= 250,
39662306a36Sopenharmony_ci	.base.cra_blocksize	= AES_BLOCK_SIZE,
39762306a36Sopenharmony_ci	.base.cra_ctxsize	= sizeof(struct aesbs_ctx),
39862306a36Sopenharmony_ci	.base.cra_module	= THIS_MODULE,
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	.min_keysize		= AES_MIN_KEY_SIZE,
40162306a36Sopenharmony_ci	.max_keysize		= AES_MAX_KEY_SIZE,
40262306a36Sopenharmony_ci	.walksize		= 8 * AES_BLOCK_SIZE,
40362306a36Sopenharmony_ci	.setkey			= aesbs_setkey,
40462306a36Sopenharmony_ci	.encrypt		= ecb_encrypt,
40562306a36Sopenharmony_ci	.decrypt		= ecb_decrypt,
40662306a36Sopenharmony_ci}, {
40762306a36Sopenharmony_ci	.base.cra_name		= "cbc(aes)",
40862306a36Sopenharmony_ci	.base.cra_driver_name	= "cbc-aes-neonbs",
40962306a36Sopenharmony_ci	.base.cra_priority	= 250,
41062306a36Sopenharmony_ci	.base.cra_blocksize	= AES_BLOCK_SIZE,
41162306a36Sopenharmony_ci	.base.cra_ctxsize	= sizeof(struct aesbs_cbc_ctr_ctx),
41262306a36Sopenharmony_ci	.base.cra_module	= THIS_MODULE,
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	.min_keysize		= AES_MIN_KEY_SIZE,
41562306a36Sopenharmony_ci	.max_keysize		= AES_MAX_KEY_SIZE,
41662306a36Sopenharmony_ci	.walksize		= 8 * AES_BLOCK_SIZE,
41762306a36Sopenharmony_ci	.ivsize			= AES_BLOCK_SIZE,
41862306a36Sopenharmony_ci	.setkey			= aesbs_cbc_ctr_setkey,
41962306a36Sopenharmony_ci	.encrypt		= cbc_encrypt,
42062306a36Sopenharmony_ci	.decrypt		= cbc_decrypt,
42162306a36Sopenharmony_ci}, {
42262306a36Sopenharmony_ci	.base.cra_name		= "ctr(aes)",
42362306a36Sopenharmony_ci	.base.cra_driver_name	= "ctr-aes-neonbs",
42462306a36Sopenharmony_ci	.base.cra_priority	= 250,
42562306a36Sopenharmony_ci	.base.cra_blocksize	= 1,
42662306a36Sopenharmony_ci	.base.cra_ctxsize	= sizeof(struct aesbs_cbc_ctr_ctx),
42762306a36Sopenharmony_ci	.base.cra_module	= THIS_MODULE,
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	.min_keysize		= AES_MIN_KEY_SIZE,
43062306a36Sopenharmony_ci	.max_keysize		= AES_MAX_KEY_SIZE,
43162306a36Sopenharmony_ci	.chunksize		= AES_BLOCK_SIZE,
43262306a36Sopenharmony_ci	.walksize		= 8 * AES_BLOCK_SIZE,
43362306a36Sopenharmony_ci	.ivsize			= AES_BLOCK_SIZE,
43462306a36Sopenharmony_ci	.setkey			= aesbs_cbc_ctr_setkey,
43562306a36Sopenharmony_ci	.encrypt		= ctr_encrypt,
43662306a36Sopenharmony_ci	.decrypt		= ctr_encrypt,
43762306a36Sopenharmony_ci}, {
43862306a36Sopenharmony_ci	.base.cra_name		= "xts(aes)",
43962306a36Sopenharmony_ci	.base.cra_driver_name	= "xts-aes-neonbs",
44062306a36Sopenharmony_ci	.base.cra_priority	= 250,
44162306a36Sopenharmony_ci	.base.cra_blocksize	= AES_BLOCK_SIZE,
44262306a36Sopenharmony_ci	.base.cra_ctxsize	= sizeof(struct aesbs_xts_ctx),
44362306a36Sopenharmony_ci	.base.cra_module	= THIS_MODULE,
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	.min_keysize		= 2 * AES_MIN_KEY_SIZE,
44662306a36Sopenharmony_ci	.max_keysize		= 2 * AES_MAX_KEY_SIZE,
44762306a36Sopenharmony_ci	.walksize		= 8 * AES_BLOCK_SIZE,
44862306a36Sopenharmony_ci	.ivsize			= AES_BLOCK_SIZE,
44962306a36Sopenharmony_ci	.setkey			= aesbs_xts_setkey,
45062306a36Sopenharmony_ci	.encrypt		= xts_encrypt,
45162306a36Sopenharmony_ci	.decrypt		= xts_decrypt,
45262306a36Sopenharmony_ci} };
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_cistatic void aes_exit(void)
45562306a36Sopenharmony_ci{
45662306a36Sopenharmony_ci	crypto_unregister_skciphers(aes_algs, ARRAY_SIZE(aes_algs));
45762306a36Sopenharmony_ci}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_cistatic int __init aes_init(void)
46062306a36Sopenharmony_ci{
46162306a36Sopenharmony_ci	if (!cpu_have_named_feature(ASIMD))
46262306a36Sopenharmony_ci		return -ENODEV;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	return crypto_register_skciphers(aes_algs, ARRAY_SIZE(aes_algs));
46562306a36Sopenharmony_ci}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_cimodule_init(aes_init);
46862306a36Sopenharmony_cimodule_exit(aes_exit);
469