[PATCH v2 3/3] ARM: add support for bit sliced AES using NEON instructions

Nicolas Pitre nicolas.pitre at linaro.org
Thu Oct 3 20:38:58 EDT 2013


On Thu, 3 Oct 2013, Ard Biesheuvel wrote:

> Bit sliced AES gives around 45% speedup on Cortex-A15 for encryption
> and around 25% for decryption. This implementation of the AES algorithm
> does not rely on any lookup tables so it is believed to be invulnerable
> to cache timing attacks.
> 
> This algorithm processes up to 8 blocks in parallel in constant time. This
> means that it is not usable by chaining modes that are strictly sequential
> in nature, such as CBC encryption. CBC decryption, however, can benefit from
> this implementation and runs about 25% faster. The other chaining modes
> implemented in this module, XTS and CTR, can execute fully in parallel in
> both directions.
> 
> The core code has been adopted from the OpenSSL project (in collaboration
> with the original author, on cc). For ease of maintenance, this version is
> identical to the upstream OpenSSL code, i.e., all modifications that were
> required to make it suitable for inclusion into the kernel have been made
> upstream. The original [called bsaes-armv7.pl] can be found here:
> 
>     http://git.openssl.org/gitweb/?p=openssl.git;a=commit;h=6f6a6130
> 
> Note to integrators:
> While this implementation is significantly faster than the existing table
> based ones (generic or ARM asm), especially in CTR mode, the effects on
> power efficiency are unclear as of yet. This code does fundamentally more
> work, by calculating values that the table based code obtains by a simple
> lookup; only by doing all of that work in a SIMD fashion, it manages to
> perform better.
> 
> Cc: Andy Polyakov <appro at openssl.org>
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel at linaro.org>

Acked-by: Nicolas Pitre <nico at linaro.org>

> ---
>  arch/arm/crypto/Makefile     |    6 +-
>  arch/arm/crypto/aesbs-core.S | 2544 ++++++++++++++++++++++++++++++++++++++++++
>  arch/arm/crypto/aesbs-glue.c |  435 ++++++++
>  crypto/Kconfig               |   16 +
>  4 files changed, 2999 insertions(+), 2 deletions(-)
>  create mode 100644 arch/arm/crypto/aesbs-core.S
>  create mode 100644 arch/arm/crypto/aesbs-glue.c
> 
> diff --git a/arch/arm/crypto/Makefile b/arch/arm/crypto/Makefile
> index a2c8385..bda5848 100644
> --- a/arch/arm/crypto/Makefile
> +++ b/arch/arm/crypto/Makefile
> @@ -3,7 +3,9 @@
>  #
>  
>  obj-$(CONFIG_CRYPTO_AES_ARM) += aes-arm.o
> +obj-$(CONFIG_CRYPTO_AES_ARM_BS) += aes-arm-bs.o
>  obj-$(CONFIG_CRYPTO_SHA1_ARM) += sha1-arm.o
>  
> -aes-arm-y  := aes-armv4.o aes_glue.o
> -sha1-arm-y := sha1-armv4-large.o sha1_glue.o
> +aes-arm-y	:= aes-armv4.o aes_glue.o
> +aes-arm-bs-y	:= aesbs-core.o aesbs-glue.o
> +sha1-arm-y	:= sha1-armv4-large.o sha1_glue.o
> diff --git a/arch/arm/crypto/aesbs-core.S b/arch/arm/crypto/aesbs-core.S
> new file mode 100644
> index 0000000..64205d4
> --- /dev/null
> +++ b/arch/arm/crypto/aesbs-core.S
> @@ -0,0 +1,2544 @@
> +
> +@ ====================================================================
> +@ Written by Andy Polyakov <appro at openssl.org> for the OpenSSL
> +@ project. The module is, however, dual licensed under OpenSSL and
> +@ CRYPTOGAMS licenses depending on where you obtain it. For further
> +@ details see http://www.openssl.org/~appro/cryptogams/.
> +@
> +@ Specific modes and adaptation for Linux kernel by Ard Biesheuvel
> +@ <ard.biesheuvel at linaro.org>. Permission to use under GPL terms is
> +@ granted.
> +@ ====================================================================
> +
> +@ Bit-sliced AES for ARM NEON
> +@
> +@ February 2012.
> +@
> +@ This implementation is direct adaptation of bsaes-x86_64 module for
> +@ ARM NEON. Except that this module is endian-neutral [in sense that
> +@ it can be compiled for either endianness] by courtesy of vld1.8's
> +@ neutrality. Initial version doesn't implement interface to OpenSSL,
> +@ only low-level primitives and unsupported entry points, just enough
> +@ to collect performance results, which for Cortex-A8 core are:
> +@
> +@ encrypt	19.5 cycles per byte processed with 128-bit key
> +@ decrypt	22.1 cycles per byte processed with 128-bit key
> +@ key conv.	440  cycles per 128-bit key/0.18 of 8x block
> +@
> +@ Snapdragon S4 encrypts byte in 17.6 cycles and decrypts in 19.7,
> +@ which is [much] worse than anticipated (for further details see
> +@ http://www.openssl.org/~appro/Snapdragon-S4.html).
> +@
> +@ Cortex-A15 manages in 14.2/16.1 cycles [when integer-only code
> +@ manages in 20.0 cycles].
> +@
> +@ When comparing to x86_64 results keep in mind that NEON unit is
> +@ [mostly] single-issue and thus can't [fully] benefit from
> +@ instruction-level parallelism. And when comparing to aes-armv4
> +@ results keep in mind key schedule conversion overhead (see
> +@ bsaes-x86_64.pl for further details)...
> +@
> +@						<appro at openssl.org>
> +
> +@ April-August 2013
> +@
> +@ Add CBC, CTR and XTS subroutines, adapt for kernel use.
> +@
> +@					<ard.biesheuvel at linaro.org>
> +
> +#ifndef __KERNEL__
> +# include "arm_arch.h"
> +
> +# define VFP_ABI_PUSH	vstmdb	sp!,{d8-d15}
> +# define VFP_ABI_POP	vldmia	sp!,{d8-d15}
> +# define VFP_ABI_FRAME	0x40
> +#else
> +# define VFP_ABI_PUSH
> +# define VFP_ABI_POP
> +# define VFP_ABI_FRAME	0
> +# define BSAES_ASM_EXTENDED_KEY
> +# define XTS_CHAIN_TWEAK
> +# define __ARM_ARCH__ __LINUX_ARM_ARCH__
> +#endif
> +
> +#ifdef __thumb__
> +# define adrl adr
> +#endif
> +
> +#if __ARM_ARCH__>=7
> +.text
> +.syntax	unified 	@ ARMv7-capable assembler is expected to handle this
> +#ifdef __thumb2__
> +.thumb
> +#else
> +.code   32
> +#endif
> +
> +.fpu	neon
> +
> +.type	_bsaes_decrypt8,%function
> +.align	4
> +_bsaes_decrypt8:
> +	adr	r6,_bsaes_decrypt8
> +	vldmia	r4!, {q9}		@ round 0 key
> +	add	r6,r6,#.LM0ISR-_bsaes_decrypt8
> +
> +	vldmia	r6!, {q8}		@ .LM0ISR
> +	veor	q10, q0, q9	@ xor with round0 key
> +	veor	q11, q1, q9
> +	 vtbl.8	d0, {q10}, d16
> +	 vtbl.8	d1, {q10}, d17
> +	veor	q12, q2, q9
> +	 vtbl.8	d2, {q11}, d16
> +	 vtbl.8	d3, {q11}, d17
> +	veor	q13, q3, q9
> +	 vtbl.8	d4, {q12}, d16
> +	 vtbl.8	d5, {q12}, d17
> +	veor	q14, q4, q9
> +	 vtbl.8	d6, {q13}, d16
> +	 vtbl.8	d7, {q13}, d17
> +	veor	q15, q5, q9
> +	 vtbl.8	d8, {q14}, d16
> +	 vtbl.8	d9, {q14}, d17
> +	veor	q10, q6, q9
> +	 vtbl.8	d10, {q15}, d16
> +	 vtbl.8	d11, {q15}, d17
> +	veor	q11, q7, q9
> +	 vtbl.8	d12, {q10}, d16
> +	 vtbl.8	d13, {q10}, d17
> +	 vtbl.8	d14, {q11}, d16
> +	 vtbl.8	d15, {q11}, d17
> +	vmov.i8	q8,#0x55			@ compose .LBS0
> +	vmov.i8	q9,#0x33			@ compose .LBS1
> +	vshr.u64	q10, q6, #1
> +	 vshr.u64	q11, q4, #1
> +	veor		q10, q10, q7
> +	 veor		q11, q11, q5
> +	vand		q10, q10, q8
> +	 vand		q11, q11, q8
> +	veor		q7, q7, q10
> +	vshl.u64	q10, q10, #1
> +	 veor		q5, q5, q11
> +	 vshl.u64	q11, q11, #1
> +	veor		q6, q6, q10
> +	 veor		q4, q4, q11
> +	vshr.u64	q10, q2, #1
> +	 vshr.u64	q11, q0, #1
> +	veor		q10, q10, q3
> +	 veor		q11, q11, q1
> +	vand		q10, q10, q8
> +	 vand		q11, q11, q8
> +	veor		q3, q3, q10
> +	vshl.u64	q10, q10, #1
> +	 veor		q1, q1, q11
> +	 vshl.u64	q11, q11, #1
> +	veor		q2, q2, q10
> +	 veor		q0, q0, q11
> +	vmov.i8	q8,#0x0f			@ compose .LBS2
> +	vshr.u64	q10, q5, #2
> +	 vshr.u64	q11, q4, #2
> +	veor		q10, q10, q7
> +	 veor		q11, q11, q6
> +	vand		q10, q10, q9
> +	 vand		q11, q11, q9
> +	veor		q7, q7, q10
> +	vshl.u64	q10, q10, #2
> +	 veor		q6, q6, q11
> +	 vshl.u64	q11, q11, #2
> +	veor		q5, q5, q10
> +	 veor		q4, q4, q11
> +	vshr.u64	q10, q1, #2
> +	 vshr.u64	q11, q0, #2
> +	veor		q10, q10, q3
> +	 veor		q11, q11, q2
> +	vand		q10, q10, q9
> +	 vand		q11, q11, q9
> +	veor		q3, q3, q10
> +	vshl.u64	q10, q10, #2
> +	 veor		q2, q2, q11
> +	 vshl.u64	q11, q11, #2
> +	veor		q1, q1, q10
> +	 veor		q0, q0, q11
> +	vshr.u64	q10, q3, #4
> +	 vshr.u64	q11, q2, #4
> +	veor		q10, q10, q7
> +	 veor		q11, q11, q6
> +	vand		q10, q10, q8
> +	 vand		q11, q11, q8
> +	veor		q7, q7, q10
> +	vshl.u64	q10, q10, #4
> +	 veor		q6, q6, q11
> +	 vshl.u64	q11, q11, #4
> +	veor		q3, q3, q10
> +	 veor		q2, q2, q11
> +	vshr.u64	q10, q1, #4
> +	 vshr.u64	q11, q0, #4
> +	veor		q10, q10, q5
> +	 veor		q11, q11, q4
> +	vand		q10, q10, q8
> +	 vand		q11, q11, q8
> +	veor		q5, q5, q10
> +	vshl.u64	q10, q10, #4
> +	 veor		q4, q4, q11
> +	 vshl.u64	q11, q11, #4
> +	veor		q1, q1, q10
> +	 veor		q0, q0, q11
> +	sub	r5,r5,#1
> +	b	.Ldec_sbox
> +.align	4
> +.Ldec_loop:
> +	vldmia	r4!, {q8-q11}
> +	veor	q8, q8, q0
> +	veor	q9, q9, q1
> +	vtbl.8	d0, {q8}, d24
> +	vtbl.8	d1, {q8}, d25
> +	vldmia	r4!, {q8}
> +	veor	q10, q10, q2
> +	vtbl.8	d2, {q9}, d24
> +	vtbl.8	d3, {q9}, d25
> +	vldmia	r4!, {q9}
> +	veor	q11, q11, q3
> +	vtbl.8	d4, {q10}, d24
> +	vtbl.8	d5, {q10}, d25
> +	vldmia	r4!, {q10}
> +	vtbl.8	d6, {q11}, d24
> +	vtbl.8	d7, {q11}, d25
> +	vldmia	r4!, {q11}
> +	veor	q8, q8, q4
> +	veor	q9, q9, q5
> +	vtbl.8	d8, {q8}, d24
> +	vtbl.8	d9, {q8}, d25
> +	veor	q10, q10, q6
> +	vtbl.8	d10, {q9}, d24
> +	vtbl.8	d11, {q9}, d25
> +	veor	q11, q11, q7
> +	vtbl.8	d12, {q10}, d24
> +	vtbl.8	d13, {q10}, d25
> +	vtbl.8	d14, {q11}, d24
> +	vtbl.8	d15, {q11}, d25
> +.Ldec_sbox:
> +	 veor	q1, q1, q4
> +	veor	q3, q3, q4
> +
> +	veor	q4, q4, q7
> +	 veor	q1, q1, q6
> +	veor	q2, q2, q7
> +	veor	q6, q6, q4
> +
> +	veor	q0, q0, q1
> +	veor	q2, q2, q5
> +	 veor	q7, q7, q6
> +	veor	q3, q3, q0
> +	veor	q5, q5, q0
> +	veor	q1, q1, q3
> +	veor	q11, q3, q0
> +	veor	q10, q7, q4
> +	veor	q9, q1, q6
> +	veor	q13, q4, q0
> +	 vmov	q8, q10
> +	veor	q12, q5, q2
> +
> +	vorr	q10, q10, q9
> +	veor	q15, q11, q8
> +	vand	q14, q11, q12
> +	vorr	q11, q11, q12
> +	veor	q12, q12, q9
> +	vand	q8, q8, q9
> +	veor	q9, q6, q2
> +	vand	q15, q15, q12
> +	vand	q13, q13, q9
> +	veor	q9, q3, q7
> +	veor	q12, q1, q5
> +	veor	q11, q11, q13
> +	veor	q10, q10, q13
> +	vand	q13, q9, q12
> +	vorr	q9, q9, q12
> +	veor	q11, q11, q15
> +	veor	q8, q8, q13
> +	veor	q10, q10, q14
> +	veor	q9, q9, q15
> +	veor	q8, q8, q14
> +	vand	q12, q4, q6
> +	veor	q9, q9, q14
> +	vand	q13, q0, q2
> +	vand	q14, q7, q1
> +	vorr	q15, q3, q5
> +	veor	q11, q11, q12
> +	veor	q9, q9, q14
> +	veor	q8, q8, q15
> +	veor	q10, q10, q13
> +
> +	@ Inv_GF16 	0, 	1, 	2, 	3, s0, s1, s2, s3
> +
> +	@ new smaller inversion
> +
> +	vand	q14, q11, q9
> +	vmov	q12, q8
> +
> +	veor	q13, q10, q14
> +	veor	q15, q8, q14
> +	veor	q14, q8, q14	@ q14=q15
> +
> +	vbsl	q13, q9, q8
> +	vbsl	q15, q11, q10
> +	veor	q11, q11, q10
> +
> +	vbsl	q12, q13, q14
> +	vbsl	q8, q14, q13
> +
> +	vand	q14, q12, q15
> +	veor	q9, q9, q8
> +
> +	veor	q14, q14, q11
> +	veor	q12, q5, q2
> +	veor	q8, q1, q6
> +	veor 	q10, q15, q14
> +	vand	q10, q10, q5
> +	veor	q5, q5, q1
> +	vand	q11, q1, q15
> +	vand	q5, q5, q14
> +	veor	q1, q11, q10
> +	veor	q5, q5, q11
> +	veor	q15, q15, q13
> +	veor	q14, q14, q9
> +	veor	q11, q15, q14
> +	 veor 	q10, q13, q9
> +	vand	q11, q11, q12
> +	 vand	q10, q10, q2
> +	veor	q12, q12, q8
> +	 veor	q2, q2, q6
> +	vand	q8, q8, q15
> +	 vand	q6, q6, q13
> +	vand	q12, q12, q14
> +	 vand	q2, q2, q9
> +	veor	q8, q8, q12
> +	 veor	q2, q2, q6
> +	veor	q12, q12, q11
> +	 veor	q6, q6, q10
> +	veor	q5, q5, q12
> +	veor	q2, q2, q12
> +	veor	q1, q1, q8
> +	veor	q6, q6, q8
> +
> +	veor	q12, q3, q0
> +	veor	q8, q7, q4
> +	veor	q11, q15, q14
> +	 veor 	q10, q13, q9
> +	vand	q11, q11, q12
> +	 vand	q10, q10, q0
> +	veor	q12, q12, q8
> +	 veor	q0, q0, q4
> +	vand	q8, q8, q15
> +	 vand	q4, q4, q13
> +	vand	q12, q12, q14
> +	 vand	q0, q0, q9
> +	veor	q8, q8, q12
> +	 veor	q0, q0, q4
> +	veor	q12, q12, q11
> +	 veor	q4, q4, q10
> +	veor	q15, q15, q13
> +	veor	q14, q14, q9
> +	veor 	q10, q15, q14
> +	vand	q10, q10, q3
> +	veor	q3, q3, q7
> +	vand	q11, q7, q15
> +	vand	q3, q3, q14
> +	veor	q7, q11, q10
> +	veor	q3, q3, q11
> +	veor	q3, q3, q12
> +	veor	q0, q0, q12
> +	veor	q7, q7, q8
> +	veor	q4, q4, q8
> +	veor	q1, q1, q7
> +	veor	q6, q6, q5
> +
> +	veor	q4, q4, q1
> +	veor	q2, q2, q7
> +	veor	q5, q5, q7
> +	veor	q4, q4, q2
> +	 veor 	q7, q7, q0
> +	veor	q4, q4, q5
> +	 veor	q3, q3, q6
> +	 veor	q6, q6, q1
> +	veor	q3, q3, q4
> +
> +	veor	q4, q4, q0
> +	veor	q7, q7, q3
> +	subs	r5,r5,#1
> +	bcc	.Ldec_done
> +	@ multiplication by 0x05-0x00-0x04-0x00
> +	vext.8	q8, q0, q0, #8
> +	vext.8	q14, q3, q3, #8
> +	vext.8	q15, q5, q5, #8
> +	veor	q8, q8, q0
> +	vext.8	q9, q1, q1, #8
> +	veor	q14, q14, q3
> +	vext.8	q10, q6, q6, #8
> +	veor	q15, q15, q5
> +	vext.8	q11, q4, q4, #8
> +	veor	q9, q9, q1
> +	vext.8	q12, q2, q2, #8
> +	veor	q10, q10, q6
> +	vext.8	q13, q7, q7, #8
> +	veor	q11, q11, q4
> +	veor	q12, q12, q2
> +	veor	q13, q13, q7
> +
> +	 veor	q0, q0, q14
> +	 veor	q1, q1, q14
> +	 veor	q6, q6, q8
> +	 veor	q2, q2, q10
> +	 veor	q4, q4, q9
> +	 veor	q1, q1, q15
> +	 veor	q6, q6, q15
> +	 veor	q2, q2, q14
> +	 veor	q7, q7, q11
> +	 veor	q4, q4, q14
> +	 veor	q3, q3, q12
> +	 veor	q2, q2, q15
> +	 veor	q7, q7, q15
> +	 veor	q5, q5, q13
> +	vext.8	q8, q0, q0, #12	@ x0 <<< 32
> +	vext.8	q9, q1, q1, #12
> +	 veor	q0, q0, q8		@ x0 ^ (x0 <<< 32)
> +	vext.8	q10, q6, q6, #12
> +	 veor	q1, q1, q9
> +	vext.8	q11, q4, q4, #12
> +	 veor	q6, q6, q10
> +	vext.8	q12, q2, q2, #12
> +	 veor	q4, q4, q11
> +	vext.8	q13, q7, q7, #12
> +	 veor	q2, q2, q12
> +	vext.8	q14, q3, q3, #12
> +	 veor	q7, q7, q13
> +	vext.8	q15, q5, q5, #12
> +	 veor	q3, q3, q14
> +
> +	veor	q9, q9, q0
> +	 veor	q5, q5, q15
> +	 vext.8	q0, q0, q0, #8		@ (x0 ^ (x0 <<< 32)) <<< 64)
> +	veor	q10, q10, q1
> +	veor	q8, q8, q5
> +	veor	q9, q9, q5
> +	 vext.8	q1, q1, q1, #8
> +	veor	q13, q13, q2
> +	 veor	q0, q0, q8
> +	veor	q14, q14, q7
> +	 veor	q1, q1, q9
> +	 vext.8	q8, q2, q2, #8
> +	veor	q12, q12, q4
> +	 vext.8	q9, q7, q7, #8
> +	veor	q15, q15, q3
> +	 vext.8	q2, q4, q4, #8
> +	veor	q11, q11, q6
> +	 vext.8	q7, q5, q5, #8
> +	veor	q12, q12, q5
> +	 vext.8	q4, q3, q3, #8
> +	veor	q11, q11, q5
> +	 vext.8	q3, q6, q6, #8
> +	veor	q5, q9, q13
> +	veor	q11, q11, q2
> +	veor	q7, q7, q15
> +	veor	q6, q4, q14
> +	veor	q4, q8, q12
> +	veor	q2, q3, q10
> +	vmov	q3, q11
> +	 @ vmov	q5, q9
> +	vldmia	r6, {q12}		@ .LISR
> +	ite	eq				@ Thumb2 thing, sanity check in ARM
> +	addeq	r6,r6,#0x10
> +	bne	.Ldec_loop
> +	vldmia	r6, {q12}		@ .LISRM0
> +	b	.Ldec_loop
> +.align	4
> +.Ldec_done:
> +	vmov.i8	q8,#0x55			@ compose .LBS0
> +	vmov.i8	q9,#0x33			@ compose .LBS1
> +	vshr.u64	q10, q3, #1
> +	 vshr.u64	q11, q2, #1
> +	veor		q10, q10, q5
> +	 veor		q11, q11, q7
> +	vand		q10, q10, q8
> +	 vand		q11, q11, q8
> +	veor		q5, q5, q10
> +	vshl.u64	q10, q10, #1
> +	 veor		q7, q7, q11
> +	 vshl.u64	q11, q11, #1
> +	veor		q3, q3, q10
> +	 veor		q2, q2, q11
> +	vshr.u64	q10, q6, #1
> +	 vshr.u64	q11, q0, #1
> +	veor		q10, q10, q4
> +	 veor		q11, q11, q1
> +	vand		q10, q10, q8
> +	 vand		q11, q11, q8
> +	veor		q4, q4, q10
> +	vshl.u64	q10, q10, #1
> +	 veor		q1, q1, q11
> +	 vshl.u64	q11, q11, #1
> +	veor		q6, q6, q10
> +	 veor		q0, q0, q11
> +	vmov.i8	q8,#0x0f			@ compose .LBS2
> +	vshr.u64	q10, q7, #2
> +	 vshr.u64	q11, q2, #2
> +	veor		q10, q10, q5
> +	 veor		q11, q11, q3
> +	vand		q10, q10, q9
> +	 vand		q11, q11, q9
> +	veor		q5, q5, q10
> +	vshl.u64	q10, q10, #2
> +	 veor		q3, q3, q11
> +	 vshl.u64	q11, q11, #2
> +	veor		q7, q7, q10
> +	 veor		q2, q2, q11
> +	vshr.u64	q10, q1, #2
> +	 vshr.u64	q11, q0, #2
> +	veor		q10, q10, q4
> +	 veor		q11, q11, q6
> +	vand		q10, q10, q9
> +	 vand		q11, q11, q9
> +	veor		q4, q4, q10
> +	vshl.u64	q10, q10, #2
> +	 veor		q6, q6, q11
> +	 vshl.u64	q11, q11, #2
> +	veor		q1, q1, q10
> +	 veor		q0, q0, q11
> +	vshr.u64	q10, q4, #4
> +	 vshr.u64	q11, q6, #4
> +	veor		q10, q10, q5
> +	 veor		q11, q11, q3
> +	vand		q10, q10, q8
> +	 vand		q11, q11, q8
> +	veor		q5, q5, q10
> +	vshl.u64	q10, q10, #4
> +	 veor		q3, q3, q11
> +	 vshl.u64	q11, q11, #4
> +	veor		q4, q4, q10
> +	 veor		q6, q6, q11
> +	vshr.u64	q10, q1, #4
> +	 vshr.u64	q11, q0, #4
> +	veor		q10, q10, q7
> +	 veor		q11, q11, q2
> +	vand		q10, q10, q8
> +	 vand		q11, q11, q8
> +	veor		q7, q7, q10
> +	vshl.u64	q10, q10, #4
> +	 veor		q2, q2, q11
> +	 vshl.u64	q11, q11, #4
> +	veor		q1, q1, q10
> +	 veor		q0, q0, q11
> +	vldmia	r4, {q8}			@ last round key
> +	veor	q6, q6, q8
> +	veor	q4, q4, q8
> +	veor	q2, q2, q8
> +	veor	q7, q7, q8
> +	veor	q3, q3, q8
> +	veor	q5, q5, q8
> +	veor	q0, q0, q8
> +	veor	q1, q1, q8
> +	bx	lr
> +.size	_bsaes_decrypt8,.-_bsaes_decrypt8
> +
> +.type	_bsaes_const,%object
> +.align	6
> +_bsaes_const:
> +.LM0ISR:	@ InvShiftRows constants
> +	.quad	0x0a0e0206070b0f03, 0x0004080c0d010509
> +.LISR:
> +	.quad	0x0504070602010003, 0x0f0e0d0c080b0a09
> +.LISRM0:
> +	.quad	0x01040b0e0205080f, 0x0306090c00070a0d
> +.LM0SR:		@ ShiftRows constants
> +	.quad	0x0a0e02060f03070b, 0x0004080c05090d01
> +.LSR:
> +	.quad	0x0504070600030201, 0x0f0e0d0c0a09080b
> +.LSRM0:
> +	.quad	0x0304090e00050a0f, 0x01060b0c0207080d
> +.LM0:
> +	.quad	0x02060a0e03070b0f, 0x0004080c0105090d
> +.LREVM0SR:
> +	.quad	0x090d01050c000408, 0x03070b0f060a0e02
> +.asciz	"Bit-sliced AES for NEON, CRYPTOGAMS by <appro at openssl.org>"
> +.align	6
> +.size	_bsaes_const,.-_bsaes_const
> +
> +.type	_bsaes_encrypt8,%function
> +.align	4
> +_bsaes_encrypt8:
> +	adr	r6,_bsaes_encrypt8
> +	vldmia	r4!, {q9}		@ round 0 key
> +	sub	r6,r6,#_bsaes_encrypt8-.LM0SR
> +
> +	vldmia	r6!, {q8}		@ .LM0SR
> +_bsaes_encrypt8_alt:
> +	veor	q10, q0, q9	@ xor with round0 key
> +	veor	q11, q1, q9
> +	 vtbl.8	d0, {q10}, d16
> +	 vtbl.8	d1, {q10}, d17
> +	veor	q12, q2, q9
> +	 vtbl.8	d2, {q11}, d16
> +	 vtbl.8	d3, {q11}, d17
> +	veor	q13, q3, q9
> +	 vtbl.8	d4, {q12}, d16
> +	 vtbl.8	d5, {q12}, d17
> +	veor	q14, q4, q9
> +	 vtbl.8	d6, {q13}, d16
> +	 vtbl.8	d7, {q13}, d17
> +	veor	q15, q5, q9
> +	 vtbl.8	d8, {q14}, d16
> +	 vtbl.8	d9, {q14}, d17
> +	veor	q10, q6, q9
> +	 vtbl.8	d10, {q15}, d16
> +	 vtbl.8	d11, {q15}, d17
> +	veor	q11, q7, q9
> +	 vtbl.8	d12, {q10}, d16
> +	 vtbl.8	d13, {q10}, d17
> +	 vtbl.8	d14, {q11}, d16
> +	 vtbl.8	d15, {q11}, d17
> +_bsaes_encrypt8_bitslice:
> +	vmov.i8	q8,#0x55			@ compose .LBS0
> +	vmov.i8	q9,#0x33			@ compose .LBS1
> +	vshr.u64	q10, q6, #1
> +	 vshr.u64	q11, q4, #1
> +	veor		q10, q10, q7
> +	 veor		q11, q11, q5
> +	vand		q10, q10, q8
> +	 vand		q11, q11, q8
> +	veor		q7, q7, q10
> +	vshl.u64	q10, q10, #1
> +	 veor		q5, q5, q11
> +	 vshl.u64	q11, q11, #1
> +	veor		q6, q6, q10
> +	 veor		q4, q4, q11
> +	vshr.u64	q10, q2, #1
> +	 vshr.u64	q11, q0, #1
> +	veor		q10, q10, q3
> +	 veor		q11, q11, q1
> +	vand		q10, q10, q8
> +	 vand		q11, q11, q8
> +	veor		q3, q3, q10
> +	vshl.u64	q10, q10, #1
> +	 veor		q1, q1, q11
> +	 vshl.u64	q11, q11, #1
> +	veor		q2, q2, q10
> +	 veor		q0, q0, q11
> +	vmov.i8	q8,#0x0f			@ compose .LBS2
> +	vshr.u64	q10, q5, #2
> +	 vshr.u64	q11, q4, #2
> +	veor		q10, q10, q7
> +	 veor		q11, q11, q6
> +	vand		q10, q10, q9
> +	 vand		q11, q11, q9
> +	veor		q7, q7, q10
> +	vshl.u64	q10, q10, #2
> +	 veor		q6, q6, q11
> +	 vshl.u64	q11, q11, #2
> +	veor		q5, q5, q10
> +	 veor		q4, q4, q11
> +	vshr.u64	q10, q1, #2
> +	 vshr.u64	q11, q0, #2
> +	veor		q10, q10, q3
> +	 veor		q11, q11, q2
> +	vand		q10, q10, q9
> +	 vand		q11, q11, q9
> +	veor		q3, q3, q10
> +	vshl.u64	q10, q10, #2
> +	 veor		q2, q2, q11
> +	 vshl.u64	q11, q11, #2
> +	veor		q1, q1, q10
> +	 veor		q0, q0, q11
> +	vshr.u64	q10, q3, #4
> +	 vshr.u64	q11, q2, #4
> +	veor		q10, q10, q7
> +	 veor		q11, q11, q6
> +	vand		q10, q10, q8
> +	 vand		q11, q11, q8
> +	veor		q7, q7, q10
> +	vshl.u64	q10, q10, #4
> +	 veor		q6, q6, q11
> +	 vshl.u64	q11, q11, #4
> +	veor		q3, q3, q10
> +	 veor		q2, q2, q11
> +	vshr.u64	q10, q1, #4
> +	 vshr.u64	q11, q0, #4
> +	veor		q10, q10, q5
> +	 veor		q11, q11, q4
> +	vand		q10, q10, q8
> +	 vand		q11, q11, q8
> +	veor		q5, q5, q10
> +	vshl.u64	q10, q10, #4
> +	 veor		q4, q4, q11
> +	 vshl.u64	q11, q11, #4
> +	veor		q1, q1, q10
> +	 veor		q0, q0, q11
> +	sub	r5,r5,#1
> +	b	.Lenc_sbox
> +.align	4
> +.Lenc_loop:
> +	vldmia	r4!, {q8-q11}
> +	veor	q8, q8, q0
> +	veor	q9, q9, q1
> +	vtbl.8	d0, {q8}, d24
> +	vtbl.8	d1, {q8}, d25
> +	vldmia	r4!, {q8}
> +	veor	q10, q10, q2
> +	vtbl.8	d2, {q9}, d24
> +	vtbl.8	d3, {q9}, d25
> +	vldmia	r4!, {q9}
> +	veor	q11, q11, q3
> +	vtbl.8	d4, {q10}, d24
> +	vtbl.8	d5, {q10}, d25
> +	vldmia	r4!, {q10}
> +	vtbl.8	d6, {q11}, d24
> +	vtbl.8	d7, {q11}, d25
> +	vldmia	r4!, {q11}
> +	veor	q8, q8, q4
> +	veor	q9, q9, q5
> +	vtbl.8	d8, {q8}, d24
> +	vtbl.8	d9, {q8}, d25
> +	veor	q10, q10, q6
> +	vtbl.8	d10, {q9}, d24
> +	vtbl.8	d11, {q9}, d25
> +	veor	q11, q11, q7
> +	vtbl.8	d12, {q10}, d24
> +	vtbl.8	d13, {q10}, d25
> +	vtbl.8	d14, {q11}, d24
> +	vtbl.8	d15, {q11}, d25
> +.Lenc_sbox:
> +	veor	q2, q2, q1
> +	veor	q5, q5, q6
> +	veor	q3, q3, q0
> +	veor	q6, q6, q2
> +	veor	q5, q5, q0
> +
> +	veor	q6, q6, q3
> +	veor	q3, q3, q7
> +	veor	q7, q7, q5
> +	veor	q3, q3, q4
> +	veor	q4, q4, q5
> +
> +	veor	q2, q2, q7
> +	veor	q3, q3, q1
> +	veor	q1, q1, q5
> +	veor	q11, q7, q4
> +	veor	q10, q1, q2
> +	veor	q9, q5, q3
> +	veor	q13, q2, q4
> +	 vmov	q8, q10
> +	veor	q12, q6, q0
> +
> +	vorr	q10, q10, q9
> +	veor	q15, q11, q8
> +	vand	q14, q11, q12
> +	vorr	q11, q11, q12
> +	veor	q12, q12, q9
> +	vand	q8, q8, q9
> +	veor	q9, q3, q0
> +	vand	q15, q15, q12
> +	vand	q13, q13, q9
> +	veor	q9, q7, q1
> +	veor	q12, q5, q6
> +	veor	q11, q11, q13
> +	veor	q10, q10, q13
> +	vand	q13, q9, q12
> +	vorr	q9, q9, q12
> +	veor	q11, q11, q15
> +	veor	q8, q8, q13
> +	veor	q10, q10, q14
> +	veor	q9, q9, q15
> +	veor	q8, q8, q14
> +	vand	q12, q2, q3
> +	veor	q9, q9, q14
> +	vand	q13, q4, q0
> +	vand	q14, q1, q5
> +	vorr	q15, q7, q6
> +	veor	q11, q11, q12
> +	veor	q9, q9, q14
> +	veor	q8, q8, q15
> +	veor	q10, q10, q13
> +
> +	@ Inv_GF16 	0, 	1, 	2, 	3, s0, s1, s2, s3
> +
> +	@ new smaller inversion
> +
> +	vand	q14, q11, q9
> +	vmov	q12, q8
> +
> +	veor	q13, q10, q14
> +	veor	q15, q8, q14
> +	veor	q14, q8, q14	@ q14=q15
> +
> +	vbsl	q13, q9, q8
> +	vbsl	q15, q11, q10
> +	veor	q11, q11, q10
> +
> +	vbsl	q12, q13, q14
> +	vbsl	q8, q14, q13
> +
> +	vand	q14, q12, q15
> +	veor	q9, q9, q8
> +
> +	veor	q14, q14, q11
> +	veor	q12, q6, q0
> +	veor	q8, q5, q3
> +	veor 	q10, q15, q14
> +	vand	q10, q10, q6
> +	veor	q6, q6, q5
> +	vand	q11, q5, q15
> +	vand	q6, q6, q14
> +	veor	q5, q11, q10
> +	veor	q6, q6, q11
> +	veor	q15, q15, q13
> +	veor	q14, q14, q9
> +	veor	q11, q15, q14
> +	 veor 	q10, q13, q9
> +	vand	q11, q11, q12
> +	 vand	q10, q10, q0
> +	veor	q12, q12, q8
> +	 veor	q0, q0, q3
> +	vand	q8, q8, q15
> +	 vand	q3, q3, q13
> +	vand	q12, q12, q14
> +	 vand	q0, q0, q9
> +	veor	q8, q8, q12
> +	 veor	q0, q0, q3
> +	veor	q12, q12, q11
> +	 veor	q3, q3, q10
> +	veor	q6, q6, q12
> +	veor	q0, q0, q12
> +	veor	q5, q5, q8
> +	veor	q3, q3, q8
> +
> +	veor	q12, q7, q4
> +	veor	q8, q1, q2
> +	veor	q11, q15, q14
> +	 veor 	q10, q13, q9
> +	vand	q11, q11, q12
> +	 vand	q10, q10, q4
> +	veor	q12, q12, q8
> +	 veor	q4, q4, q2
> +	vand	q8, q8, q15
> +	 vand	q2, q2, q13
> +	vand	q12, q12, q14
> +	 vand	q4, q4, q9
> +	veor	q8, q8, q12
> +	 veor	q4, q4, q2
> +	veor	q12, q12, q11
> +	 veor	q2, q2, q10
> +	veor	q15, q15, q13
> +	veor	q14, q14, q9
> +	veor 	q10, q15, q14
> +	vand	q10, q10, q7
> +	veor	q7, q7, q1
> +	vand	q11, q1, q15
> +	vand	q7, q7, q14
> +	veor	q1, q11, q10
> +	veor	q7, q7, q11
> +	veor	q7, q7, q12
> +	veor	q4, q4, q12
> +	veor	q1, q1, q8
> +	veor	q2, q2, q8
> +	veor	q7, q7, q0
> +	veor	q1, q1, q6
> +	veor	q6, q6, q0
> +	veor	q4, q4, q7
> +	veor	q0, q0, q1
> +
> +	veor	q1, q1, q5
> +	veor	q5, q5, q2
> +	veor	q2, q2, q3
> +	veor	q3, q3, q5
> +	veor	q4, q4, q5
> +
> +	veor	q6, q6, q3
> +	subs	r5,r5,#1
> +	bcc	.Lenc_done
> +	vext.8	q8, q0, q0, #12	@ x0 <<< 32
> +	vext.8	q9, q1, q1, #12
> +	 veor	q0, q0, q8		@ x0 ^ (x0 <<< 32)
> +	vext.8	q10, q4, q4, #12
> +	 veor	q1, q1, q9
> +	vext.8	q11, q6, q6, #12
> +	 veor	q4, q4, q10
> +	vext.8	q12, q3, q3, #12
> +	 veor	q6, q6, q11
> +	vext.8	q13, q7, q7, #12
> +	 veor	q3, q3, q12
> +	vext.8	q14, q2, q2, #12
> +	 veor	q7, q7, q13
> +	vext.8	q15, q5, q5, #12
> +	 veor	q2, q2, q14
> +
> +	veor	q9, q9, q0
> +	 veor	q5, q5, q15
> +	 vext.8	q0, q0, q0, #8		@ (x0 ^ (x0 <<< 32)) <<< 64)
> +	veor	q10, q10, q1
> +	veor	q8, q8, q5
> +	veor	q9, q9, q5
> +	 vext.8	q1, q1, q1, #8
> +	veor	q13, q13, q3
> +	 veor	q0, q0, q8
> +	veor	q14, q14, q7
> +	 veor	q1, q1, q9
> +	 vext.8	q8, q3, q3, #8
> +	veor	q12, q12, q6
> +	 vext.8	q9, q7, q7, #8
> +	veor	q15, q15, q2
> +	 vext.8	q3, q6, q6, #8
> +	veor	q11, q11, q4
> +	 vext.8	q7, q5, q5, #8
> +	veor	q12, q12, q5
> +	 vext.8	q6, q2, q2, #8
> +	veor	q11, q11, q5
> +	 vext.8	q2, q4, q4, #8
> +	veor	q5, q9, q13
> +	veor	q4, q8, q12
> +	veor	q3, q3, q11
> +	veor	q7, q7, q15
> +	veor	q6, q6, q14
> +	 @ vmov	q4, q8
> +	veor	q2, q2, q10
> +	 @ vmov	q5, q9
> +	vldmia	r6, {q12}		@ .LSR
> +	ite	eq				@ Thumb2 thing, samity check in ARM
> +	addeq	r6,r6,#0x10
> +	bne	.Lenc_loop
> +	vldmia	r6, {q12}		@ .LSRM0
> +	b	.Lenc_loop
> +.align	4
> +.Lenc_done:
> +	vmov.i8	q8,#0x55			@ compose .LBS0
> +	vmov.i8	q9,#0x33			@ compose .LBS1
> +	vshr.u64	q10, q2, #1
> +	 vshr.u64	q11, q3, #1
> +	veor		q10, q10, q5
> +	 veor		q11, q11, q7
> +	vand		q10, q10, q8
> +	 vand		q11, q11, q8
> +	veor		q5, q5, q10
> +	vshl.u64	q10, q10, #1
> +	 veor		q7, q7, q11
> +	 vshl.u64	q11, q11, #1
> +	veor		q2, q2, q10
> +	 veor		q3, q3, q11
> +	vshr.u64	q10, q4, #1
> +	 vshr.u64	q11, q0, #1
> +	veor		q10, q10, q6
> +	 veor		q11, q11, q1
> +	vand		q10, q10, q8
> +	 vand		q11, q11, q8
> +	veor		q6, q6, q10
> +	vshl.u64	q10, q10, #1
> +	 veor		q1, q1, q11
> +	 vshl.u64	q11, q11, #1
> +	veor		q4, q4, q10
> +	 veor		q0, q0, q11
> +	vmov.i8	q8,#0x0f			@ compose .LBS2
> +	vshr.u64	q10, q7, #2
> +	 vshr.u64	q11, q3, #2
> +	veor		q10, q10, q5
> +	 veor		q11, q11, q2
> +	vand		q10, q10, q9
> +	 vand		q11, q11, q9
> +	veor		q5, q5, q10
> +	vshl.u64	q10, q10, #2
> +	 veor		q2, q2, q11
> +	 vshl.u64	q11, q11, #2
> +	veor		q7, q7, q10
> +	 veor		q3, q3, q11
> +	vshr.u64	q10, q1, #2
> +	 vshr.u64	q11, q0, #2
> +	veor		q10, q10, q6
> +	 veor		q11, q11, q4
> +	vand		q10, q10, q9
> +	 vand		q11, q11, q9
> +	veor		q6, q6, q10
> +	vshl.u64	q10, q10, #2
> +	 veor		q4, q4, q11
> +	 vshl.u64	q11, q11, #2
> +	veor		q1, q1, q10
> +	 veor		q0, q0, q11
> +	vshr.u64	q10, q6, #4
> +	 vshr.u64	q11, q4, #4
> +	veor		q10, q10, q5
> +	 veor		q11, q11, q2
> +	vand		q10, q10, q8
> +	 vand		q11, q11, q8
> +	veor		q5, q5, q10
> +	vshl.u64	q10, q10, #4
> +	 veor		q2, q2, q11
> +	 vshl.u64	q11, q11, #4
> +	veor		q6, q6, q10
> +	 veor		q4, q4, q11
> +	vshr.u64	q10, q1, #4
> +	 vshr.u64	q11, q0, #4
> +	veor		q10, q10, q7
> +	 veor		q11, q11, q3
> +	vand		q10, q10, q8
> +	 vand		q11, q11, q8
> +	veor		q7, q7, q10
> +	vshl.u64	q10, q10, #4
> +	 veor		q3, q3, q11
> +	 vshl.u64	q11, q11, #4
> +	veor		q1, q1, q10
> +	 veor		q0, q0, q11
> +	vldmia	r4, {q8}			@ last round key
> +	veor	q4, q4, q8
> +	veor	q6, q6, q8
> +	veor	q3, q3, q8
> +	veor	q7, q7, q8
> +	veor	q2, q2, q8
> +	veor	q5, q5, q8
> +	veor	q0, q0, q8
> +	veor	q1, q1, q8
> +	bx	lr
> +.size	_bsaes_encrypt8,.-_bsaes_encrypt8
> +.type	_bsaes_key_convert,%function
> +.align	4
> +_bsaes_key_convert:
> +	adr	r6,_bsaes_key_convert
> +	vld1.8	{q7},  [r4]!		@ load round 0 key
> +	sub	r6,r6,#_bsaes_key_convert-.LM0
> +	vld1.8	{q15}, [r4]!		@ load round 1 key
> +
> +	vmov.i8	q8,  #0x01			@ bit masks
> +	vmov.i8	q9,  #0x02
> +	vmov.i8	q10, #0x04
> +	vmov.i8	q11, #0x08
> +	vmov.i8	q12, #0x10
> +	vmov.i8	q13, #0x20
> +	vldmia	r6, {q14}		@ .LM0
> +
> +#ifdef __ARMEL__
> +	vrev32.8	q7,  q7
> +	vrev32.8	q15, q15
> +#endif
> +	sub	r5,r5,#1
> +	vstmia	r12!, {q7}		@ save round 0 key
> +	b	.Lkey_loop
> +
> +.align	4
> +.Lkey_loop:
> +	vtbl.8	d14,{q15},d28
> +	vtbl.8	d15,{q15},d29
> +	vmov.i8	q6,  #0x40
> +	vmov.i8	q15, #0x80
> +
> +	vtst.8	q0, q7, q8
> +	vtst.8	q1, q7, q9
> +	vtst.8	q2, q7, q10
> +	vtst.8	q3, q7, q11
> +	vtst.8	q4, q7, q12
> +	vtst.8	q5, q7, q13
> +	vtst.8	q6, q7, q6
> +	vtst.8	q7, q7, q15
> +	vld1.8	{q15}, [r4]!		@ load next round key
> +	vmvn	q0, q0		@ "pnot"
> +	vmvn	q1, q1
> +	vmvn	q5, q5
> +	vmvn	q6, q6
> +#ifdef __ARMEL__
> +	vrev32.8	q15, q15
> +#endif
> +	subs	r5,r5,#1
> +	vstmia	r12!,{q0-q7}		@ write bit-sliced round key
> +	bne	.Lkey_loop
> +
> +	vmov.i8	q7,#0x63			@ compose .L63
> +	@ don't save last round key
> +	bx	lr
> +.size	_bsaes_key_convert,.-_bsaes_key_convert
> +.extern AES_cbc_encrypt
> +.extern AES_decrypt
> +
> +.global	bsaes_cbc_encrypt
> +.type	bsaes_cbc_encrypt,%function
> +.align	5
> +bsaes_cbc_encrypt:
> +#ifndef	__KERNEL__
> +	cmp	r2, #128
> +#ifndef	__thumb__
> +	blo	AES_cbc_encrypt
> +#else
> +	bhs	1f
> +	b	AES_cbc_encrypt
> +1:
> +#endif
> +#endif
> +
> +	@ it is up to the caller to make sure we are called with enc == 0
> +
> +	mov	ip, sp
> +	stmdb	sp!, {r4-r10, lr}
> +	VFP_ABI_PUSH
> +	ldr	r8, [ip]			@ IV is 1st arg on the stack
> +	mov	r2, r2, lsr#4		@ len in 16 byte blocks
> +	sub	sp, #0x10			@ scratch space to carry over the IV
> +	mov	r9, sp				@ save sp
> +
> +	ldr	r10, [r3, #240]		@ get # of rounds
> +#ifndef	BSAES_ASM_EXTENDED_KEY
> +	@ allocate the key schedule on the stack
> +	sub	r12, sp, r10, lsl#7		@ 128 bytes per inner round key
> +	add	r12, #96			@ sifze of bit-slices key schedule
> +
> +	@ populate the key schedule
> +	mov	r4, r3			@ pass key
> +	mov	r5, r10			@ pass # of rounds
> +	mov	sp, r12				@ sp is sp
> +	bl	_bsaes_key_convert
> +	vldmia	sp, {q6}
> +	vstmia	r12,  {q15}		@ save last round key
> +	veor	q7, q7, q6	@ fix up round 0 key
> +	vstmia	sp, {q7}
> +#else
> +	ldr	r12, [r3, #244]
> +	eors	r12, #1
> +	beq	0f
> +
> +	@ populate the key schedule
> +	str	r12, [r3, #244]
> +	mov	r4, r3			@ pass key
> +	mov	r5, r10			@ pass # of rounds
> +	add	r12, r3, #248			@ pass key schedule
> +	bl	_bsaes_key_convert
> +	add	r4, r3, #248
> +	vldmia	r4, {q6}
> +	vstmia	r12, {q15}			@ save last round key
> +	veor	q7, q7, q6	@ fix up round 0 key
> +	vstmia	r4, {q7}
> +
> +.align	2
> +0:
> +#endif
> +
> +	vld1.8	{q15}, [r8]		@ load IV
> +	b	.Lcbc_dec_loop
> +
> +.align	4
> +.Lcbc_dec_loop:
> +	subs	r2, r2, #0x8
> +	bmi	.Lcbc_dec_loop_finish
> +
> +	vld1.8	{q0-q1}, [r0]!	@ load input
> +	vld1.8	{q2-q3}, [r0]!
> +#ifndef	BSAES_ASM_EXTENDED_KEY
> +	mov	r4, sp			@ pass the key
> +#else
> +	add	r4, r3, #248
> +#endif
> +	vld1.8	{q4-q5}, [r0]!
> +	mov	r5, r10
> +	vld1.8	{q6-q7}, [r0]
> +	sub	r0, r0, #0x60
> +	vstmia	r9, {q15}			@ put aside IV
> +
> +	bl	_bsaes_decrypt8
> +
> +	vldmia	r9, {q14}			@ reload IV
> +	vld1.8	{q8-q9}, [r0]!	@ reload input
> +	veor	q0, q0, q14	@ ^= IV
> +	vld1.8	{q10-q11}, [r0]!
> +	veor	q1, q1, q8
> +	veor	q6, q6, q9
> +	vld1.8	{q12-q13}, [r0]!
> +	veor	q4, q4, q10
> +	veor	q2, q2, q11
> +	vld1.8	{q14-q15}, [r0]!
> +	veor	q7, q7, q12
> +	vst1.8	{q0-q1}, [r1]!	@ write output
> +	veor	q3, q3, q13
> +	vst1.8	{q6}, [r1]!
> +	veor	q5, q5, q14
> +	vst1.8	{q4}, [r1]!
> +	vst1.8	{q2}, [r1]!
> +	vst1.8	{q7}, [r1]!
> +	vst1.8	{q3}, [r1]!
> +	vst1.8	{q5}, [r1]!
> +
> +	b	.Lcbc_dec_loop
> +
> +.Lcbc_dec_loop_finish:
> +	adds	r2, r2, #8
> +	beq	.Lcbc_dec_done
> +
> +	vld1.8	{q0}, [r0]!		@ load input
> +	cmp	r2, #2
> +	blo	.Lcbc_dec_one
> +	vld1.8	{q1}, [r0]!
> +#ifndef	BSAES_ASM_EXTENDED_KEY
> +	mov	r4, sp			@ pass the key
> +#else
> +	add	r4, r3, #248
> +#endif
> +	mov	r5, r10
> +	vstmia	r9, {q15}			@ put aside IV
> +	beq	.Lcbc_dec_two
> +	vld1.8	{q2}, [r0]!
> +	cmp	r2, #4
> +	blo	.Lcbc_dec_three
> +	vld1.8	{q3}, [r0]!
> +	beq	.Lcbc_dec_four
> +	vld1.8	{q4}, [r0]!
> +	cmp	r2, #6
> +	blo	.Lcbc_dec_five
> +	vld1.8	{q5}, [r0]!
> +	beq	.Lcbc_dec_six
> +	vld1.8	{q6}, [r0]!
> +	sub	r0, r0, #0x70
> +
> +	bl	_bsaes_decrypt8
> +
> +	vldmia	r9, {q14}			@ reload IV
> +	vld1.8	{q8-q9}, [r0]!	@ reload input
> +	veor	q0, q0, q14	@ ^= IV
> +	vld1.8	{q10-q11}, [r0]!
> +	veor	q1, q1, q8
> +	veor	q6, q6, q9
> +	vld1.8	{q12-q13}, [r0]!
> +	veor	q4, q4, q10
> +	veor	q2, q2, q11
> +	vld1.8	{q15}, [r0]!
> +	veor	q7, q7, q12
> +	vst1.8	{q0-q1}, [r1]!	@ write output
> +	veor	q3, q3, q13
> +	vst1.8	{q6}, [r1]!
> +	vst1.8	{q4}, [r1]!
> +	vst1.8	{q2}, [r1]!
> +	vst1.8	{q7}, [r1]!
> +	vst1.8	{q3}, [r1]!
> +	b	.Lcbc_dec_done
> +.align	4
> +.Lcbc_dec_six:
> +	sub	r0, r0, #0x60
> +	bl	_bsaes_decrypt8
> +	vldmia	r9,{q14}			@ reload IV
> +	vld1.8	{q8-q9}, [r0]!	@ reload input
> +	veor	q0, q0, q14	@ ^= IV
> +	vld1.8	{q10-q11}, [r0]!
> +	veor	q1, q1, q8
> +	veor	q6, q6, q9
> +	vld1.8	{q12}, [r0]!
> +	veor	q4, q4, q10
> +	veor	q2, q2, q11
> +	vld1.8	{q15}, [r0]!
> +	veor	q7, q7, q12
> +	vst1.8	{q0-q1}, [r1]!	@ write output
> +	vst1.8	{q6}, [r1]!
> +	vst1.8	{q4}, [r1]!
> +	vst1.8	{q2}, [r1]!
> +	vst1.8	{q7}, [r1]!
> +	b	.Lcbc_dec_done
> +.align	4
> +.Lcbc_dec_five:
> +	sub	r0, r0, #0x50
> +	bl	_bsaes_decrypt8
> +	vldmia	r9, {q14}			@ reload IV
> +	vld1.8	{q8-q9}, [r0]!	@ reload input
> +	veor	q0, q0, q14	@ ^= IV
> +	vld1.8	{q10-q11}, [r0]!
> +	veor	q1, q1, q8
> +	veor	q6, q6, q9
> +	vld1.8	{q15}, [r0]!
> +	veor	q4, q4, q10
> +	vst1.8	{q0-q1}, [r1]!	@ write output
> +	veor	q2, q2, q11
> +	vst1.8	{q6}, [r1]!
> +	vst1.8	{q4}, [r1]!
> +	vst1.8	{q2}, [r1]!
> +	b	.Lcbc_dec_done
> +.align	4
> +.Lcbc_dec_four:
> +	sub	r0, r0, #0x40
> +	bl	_bsaes_decrypt8
> +	vldmia	r9, {q14}			@ reload IV
> +	vld1.8	{q8-q9}, [r0]!	@ reload input
> +	veor	q0, q0, q14	@ ^= IV
> +	vld1.8	{q10}, [r0]!
> +	veor	q1, q1, q8
> +	veor	q6, q6, q9
> +	vld1.8	{q15}, [r0]!
> +	veor	q4, q4, q10
> +	vst1.8	{q0-q1}, [r1]!	@ write output
> +	vst1.8	{q6}, [r1]!
> +	vst1.8	{q4}, [r1]!
> +	b	.Lcbc_dec_done
> +.align	4
> +.Lcbc_dec_three:
> +	sub	r0, r0, #0x30
> +	bl	_bsaes_decrypt8
> +	vldmia	r9, {q14}			@ reload IV
> +	vld1.8	{q8-q9}, [r0]!	@ reload input
> +	veor	q0, q0, q14	@ ^= IV
> +	vld1.8	{q15}, [r0]!
> +	veor	q1, q1, q8
> +	veor	q6, q6, q9
> +	vst1.8	{q0-q1}, [r1]!	@ write output
> +	vst1.8	{q6}, [r1]!
> +	b	.Lcbc_dec_done
> +.align	4
> +.Lcbc_dec_two:
> +	sub	r0, r0, #0x20
> +	bl	_bsaes_decrypt8
> +	vldmia	r9, {q14}			@ reload IV
> +	vld1.8	{q8}, [r0]!		@ reload input
> +	veor	q0, q0, q14	@ ^= IV
> +	vld1.8	{q15}, [r0]!		@ reload input
> +	veor	q1, q1, q8
> +	vst1.8	{q0-q1}, [r1]!	@ write output
> +	b	.Lcbc_dec_done
> +.align	4
> +.Lcbc_dec_one:
> +	sub	r0, r0, #0x10
> +	mov	r10, r1			@ save original out pointer
> +	mov	r1, r9			@ use the iv scratch space as out buffer
> +	mov	r2, r3
> +	vmov	q4,q15		@ just in case ensure that IV
> +	vmov	q5,q0			@ and input are preserved
> +	bl	AES_decrypt
> +	vld1.8	{q0}, [r9,:64]		@ load result
> +	veor	q0, q0, q4	@ ^= IV
> +	vmov	q15, q5		@ q5 holds input
> +	vst1.8	{q0}, [r10]		@ write output
> +
> +.Lcbc_dec_done:
> +#ifndef	BSAES_ASM_EXTENDED_KEY
> +	vmov.i32	q0, #0
> +	vmov.i32	q1, #0
> +.Lcbc_dec_bzero:				@ wipe key schedule [if any]
> +	vstmia		sp!, {q0-q1}
> +	cmp		sp, r9
> +	bne		.Lcbc_dec_bzero
> +#endif
> +
> +	mov	sp, r9
> +	add	sp, #0x10			@ add sp,r9,#0x10 is no good for thumb
> +	vst1.8	{q15}, [r8]		@ return IV
> +	VFP_ABI_POP
> +	ldmia	sp!, {r4-r10, pc}
> +.size	bsaes_cbc_encrypt,.-bsaes_cbc_encrypt
> +.extern	AES_encrypt
> +.global	bsaes_ctr32_encrypt_blocks
> +.type	bsaes_ctr32_encrypt_blocks,%function
> +.align	5
> +bsaes_ctr32_encrypt_blocks:
> +	cmp	r2, #8			@ use plain AES for
> +	blo	.Lctr_enc_short			@ small sizes
> +
> +	mov	ip, sp
> +	stmdb	sp!, {r4-r10, lr}
> +	VFP_ABI_PUSH
> +	ldr	r8, [ip]			@ ctr is 1st arg on the stack
> +	sub	sp, sp, #0x10			@ scratch space to carry over the ctr
> +	mov	r9, sp				@ save sp
> +
> +	ldr	r10, [r3, #240]		@ get # of rounds
> +#ifndef	BSAES_ASM_EXTENDED_KEY
> +	@ allocate the key schedule on the stack
> +	sub	r12, sp, r10, lsl#7		@ 128 bytes per inner round key
> +	add	r12, #96			@ size of bit-sliced key schedule
> +
> +	@ populate the key schedule
> +	mov	r4, r3			@ pass key
> +	mov	r5, r10			@ pass # of rounds
> +	mov	sp, r12				@ sp is sp
> +	bl	_bsaes_key_convert
> +	veor	q7,q7,q15	@ fix up last round key
> +	vstmia	r12, {q7}			@ save last round key
> +
> +	vld1.8	{q0}, [r8]		@ load counter
> +	add	r8, r6, #.LREVM0SR-.LM0	@ borrow r8
> +	vldmia	sp, {q4}		@ load round0 key
> +#else
> +	ldr	r12, [r3, #244]
> +	eors	r12, #1
> +	beq	0f
> +
> +	@ populate the key schedule
> +	str	r12, [r3, #244]
> +	mov	r4, r3			@ pass key
> +	mov	r5, r10			@ pass # of rounds
> +	add	r12, r3, #248			@ pass key schedule
> +	bl	_bsaes_key_convert
> +	veor	q7,q7,q15	@ fix up last round key
> +	vstmia	r12, {q7}			@ save last round key
> +
> +.align	2
> +0:	add	r12, r3, #248
> +	vld1.8	{q0}, [r8]		@ load counter
> +	adrl	r8, .LREVM0SR			@ borrow r8
> +	vldmia	r12, {q4}			@ load round0 key
> +	sub	sp, #0x10			@ place for adjusted round0 key
> +#endif
> +
> +	vmov.i32	q8,#1		@ compose 1<<96
> +	veor		q9,q9,q9
> +	vrev32.8	q0,q0
> +	vext.8		q8,q9,q8,#4
> +	vrev32.8	q4,q4
> +	vadd.u32	q9,q8,q8	@ compose 2<<96
> +	vstmia	sp, {q4}		@ save adjusted round0 key
> +	b	.Lctr_enc_loop
> +
> +.align	4
> +.Lctr_enc_loop:
> +	vadd.u32	q10, q8, q9	@ compose 3<<96
> +	vadd.u32	q1, q0, q8	@ +1
> +	vadd.u32	q2, q0, q9	@ +2
> +	vadd.u32	q3, q0, q10	@ +3
> +	vadd.u32	q4, q1, q10
> +	vadd.u32	q5, q2, q10
> +	vadd.u32	q6, q3, q10
> +	vadd.u32	q7, q4, q10
> +	vadd.u32	q10, q5, q10	@ next counter
> +
> +	@ Borrow prologue from _bsaes_encrypt8 to use the opportunity
> +	@ to flip byte order in 32-bit counter
> +
> +	vldmia		sp, {q9}		@ load round0 key
> +#ifndef	BSAES_ASM_EXTENDED_KEY
> +	add		r4, sp, #0x10		@ pass next round key
> +#else
> +	add		r4, r3, #264
> +#endif
> +	vldmia		r8, {q8}			@ .LREVM0SR
> +	mov		r5, r10			@ pass rounds
> +	vstmia		r9, {q10}			@ save next counter
> +	sub		r6, r8, #.LREVM0SR-.LSR	@ pass constants
> +
> +	bl		_bsaes_encrypt8_alt
> +
> +	subs		r2, r2, #8
> +	blo		.Lctr_enc_loop_done
> +
> +	vld1.8		{q8-q9}, [r0]!	@ load input
> +	vld1.8		{q10-q11}, [r0]!
> +	veor		q0, q8
> +	veor		q1, q9
> +	vld1.8		{q12-q13}, [r0]!
> +	veor		q4, q10
> +	veor		q6, q11
> +	vld1.8		{q14-q15}, [r0]!
> +	veor		q3, q12
> +	vst1.8		{q0-q1}, [r1]!	@ write output
> +	veor		q7, q13
> +	veor		q2, q14
> +	vst1.8		{q4}, [r1]!
> +	veor		q5, q15
> +	vst1.8		{q6}, [r1]!
> +	vmov.i32	q8, #1			@ compose 1<<96
> +	vst1.8		{q3}, [r1]!
> +	veor		q9, q9, q9
> +	vst1.8		{q7}, [r1]!
> +	vext.8		q8, q9, q8, #4
> +	vst1.8		{q2}, [r1]!
> +	vadd.u32	q9,q8,q8		@ compose 2<<96
> +	vst1.8		{q5}, [r1]!
> +	vldmia		r9, {q0}			@ load counter
> +
> +	bne		.Lctr_enc_loop
> +	b		.Lctr_enc_done
> +
> +.align	4
> +.Lctr_enc_loop_done:
> +	add		r2, r2, #8
> +	vld1.8		{q8}, [r0]!	@ load input
> +	veor		q0, q8
> +	vst1.8		{q0}, [r1]!	@ write output
> +	cmp		r2, #2
> +	blo		.Lctr_enc_done
> +	vld1.8		{q9}, [r0]!
> +	veor		q1, q9
> +	vst1.8		{q1}, [r1]!
> +	beq		.Lctr_enc_done
> +	vld1.8		{q10}, [r0]!
> +	veor		q4, q10
> +	vst1.8		{q4}, [r1]!
> +	cmp		r2, #4
> +	blo		.Lctr_enc_done
> +	vld1.8		{q11}, [r0]!
> +	veor		q6, q11
> +	vst1.8		{q6}, [r1]!
> +	beq		.Lctr_enc_done
> +	vld1.8		{q12}, [r0]!
> +	veor		q3, q12
> +	vst1.8		{q3}, [r1]!
> +	cmp		r2, #6
> +	blo		.Lctr_enc_done
> +	vld1.8		{q13}, [r0]!
> +	veor		q7, q13
> +	vst1.8		{q7}, [r1]!
> +	beq		.Lctr_enc_done
> +	vld1.8		{q14}, [r0]
> +	veor		q2, q14
> +	vst1.8		{q2}, [r1]!
> +
> +.Lctr_enc_done:
> +	vmov.i32	q0, #0
> +	vmov.i32	q1, #0
> +#ifndef	BSAES_ASM_EXTENDED_KEY
> +.Lctr_enc_bzero:			@ wipe key schedule [if any]
> +	vstmia		sp!, {q0-q1}
> +	cmp		sp, r9
> +	bne		.Lctr_enc_bzero
> +#else
> +	vstmia		sp, {q0-q1}
> +#endif
> +
> +	mov	sp, r9
> +	add	sp, #0x10		@ add sp,r9,#0x10 is no good for thumb
> +	VFP_ABI_POP
> +	ldmia	sp!, {r4-r10, pc}	@ return
> +
> +.align	4
> +.Lctr_enc_short:
> +	ldr	ip, [sp]		@ ctr pointer is passed on stack
> +	stmdb	sp!, {r4-r8, lr}
> +
> +	mov	r4, r0		@ copy arguments
> +	mov	r5, r1
> +	mov	r6, r2
> +	mov	r7, r3
> +	ldr	r8, [ip, #12]		@ load counter LSW
> +	vld1.8	{q1}, [ip]		@ load whole counter value
> +#ifdef __ARMEL__
> +	rev	r8, r8
> +#endif
> +	sub	sp, sp, #0x10
> +	vst1.8	{q1}, [sp,:64]	@ copy counter value
> +	sub	sp, sp, #0x10
> +
> +.Lctr_enc_short_loop:
> +	add	r0, sp, #0x10		@ input counter value
> +	mov	r1, sp			@ output on the stack
> +	mov	r2, r7			@ key
> +
> +	bl	AES_encrypt
> +
> +	vld1.8	{q0}, [r4]!	@ load input
> +	vld1.8	{q1}, [sp,:64]	@ load encrypted counter
> +	add	r8, r8, #1
> +#ifdef __ARMEL__
> +	rev	r0, r8
> +	str	r0, [sp, #0x1c]		@ next counter value
> +#else
> +	str	r8, [sp, #0x1c]		@ next counter value
> +#endif
> +	veor	q0,q0,q1
> +	vst1.8	{q0}, [r5]!	@ store output
> +	subs	r6, r6, #1
> +	bne	.Lctr_enc_short_loop
> +
> +	vmov.i32	q0, #0
> +	vmov.i32	q1, #0
> +	vstmia		sp!, {q0-q1}
> +
> +	ldmia	sp!, {r4-r8, pc}
> +.size	bsaes_ctr32_encrypt_blocks,.-bsaes_ctr32_encrypt_blocks
> +.globl	bsaes_xts_encrypt
> +.type	bsaes_xts_encrypt,%function
> +.align	4
> +bsaes_xts_encrypt:
> +	mov	ip, sp
> +	stmdb	sp!, {r4-r10, lr}		@ 0x20
> +	VFP_ABI_PUSH
> +	mov	r6, sp				@ future r3
> +
> +	mov	r7, r0
> +	mov	r8, r1
> +	mov	r9, r2
> +	mov	r10, r3
> +
> +	sub	r0, sp, #0x10			@ 0x10
> +	bic	r0, #0xf			@ align at 16 bytes
> +	mov	sp, r0
> +
> +#ifdef	XTS_CHAIN_TWEAK
> +	ldr	r0, [ip]			@ pointer to input tweak
> +#else
> +	@ generate initial tweak
> +	ldr	r0, [ip, #4]			@ iv[]
> +	mov	r1, sp
> +	ldr	r2, [ip, #0]			@ key2
> +	bl	AES_encrypt
> +	mov	r0,sp				@ pointer to initial tweak
> +#endif
> +
> +	ldr	r1, [r10, #240]		@ get # of rounds
> +	mov	r3, r6
> +#ifndef	BSAES_ASM_EXTENDED_KEY
> +	@ allocate the key schedule on the stack
> +	sub	r12, sp, r1, lsl#7		@ 128 bytes per inner round key
> +	@ add	r12, #96			@ size of bit-sliced key schedule
> +	sub	r12, #48			@ place for tweak[9]
> +
> +	@ populate the key schedule
> +	mov	r4, r10			@ pass key
> +	mov	r5, r1			@ pass # of rounds
> +	mov	sp, r12
> +	add	r12, #0x90			@ pass key schedule
> +	bl	_bsaes_key_convert
> +	veor	q7, q7, q15	@ fix up last round key
> +	vstmia	r12, {q7}			@ save last round key
> +#else
> +	ldr	r12, [r10, #244]
> +	eors	r12, #1
> +	beq	0f
> +
> +	str	r12, [r10, #244]
> +	mov	r4, r10			@ pass key
> +	mov	r5, r1			@ pass # of rounds
> +	add	r12, r10, #248			@ pass key schedule
> +	bl	_bsaes_key_convert
> +	veor	q7, q7, q15	@ fix up last round key
> +	vstmia	r12, {q7}
> +
> +.align	2
> +0:	sub	sp, #0x90			@ place for tweak[9]
> +#endif
> +
> +	vld1.8	{q8}, [r0]			@ initial tweak
> +	adr	r2, .Lxts_magic
> +
> +	subs	r9, #0x80
> +	blo	.Lxts_enc_short
> +	b	.Lxts_enc_loop
> +
> +.align	4
> +.Lxts_enc_loop:
> +	vldmia		r2, {q5}	@ load XTS magic
> +	vshr.s64	q6, q8, #63
> +	mov		r0, sp
> +	vand		q6, q6, q5
> +	vadd.u64	q9, q8, q8
> +	vst1.64		{q8}, [r0,:128]!
> +	vswp		d13,d12
> +	vshr.s64	q7, q9, #63
> +	veor		q9, q9, q6
> +	vand		q7, q7, q5
> +	vadd.u64	q10, q9, q9
> +	vst1.64		{q9}, [r0,:128]!
> +	vswp		d15,d14
> +	vshr.s64	q6, q10, #63
> +	veor		q10, q10, q7
> +	vand		q6, q6, q5
> +	vld1.8		{q0}, [r7]!
> +	vadd.u64	q11, q10, q10
> +	vst1.64		{q10}, [r0,:128]!
> +	vswp		d13,d12
> +	vshr.s64	q7, q11, #63
> +	veor		q11, q11, q6
> +	vand		q7, q7, q5
> +	vld1.8		{q1}, [r7]!
> +	veor		q0, q0, q8
> +	vadd.u64	q12, q11, q11
> +	vst1.64		{q11}, [r0,:128]!
> +	vswp		d15,d14
> +	vshr.s64	q6, q12, #63
> +	veor		q12, q12, q7
> +	vand		q6, q6, q5
> +	vld1.8		{q2}, [r7]!
> +	veor		q1, q1, q9
> +	vadd.u64	q13, q12, q12
> +	vst1.64		{q12}, [r0,:128]!
> +	vswp		d13,d12
> +	vshr.s64	q7, q13, #63
> +	veor		q13, q13, q6
> +	vand		q7, q7, q5
> +	vld1.8		{q3}, [r7]!
> +	veor		q2, q2, q10
> +	vadd.u64	q14, q13, q13
> +	vst1.64		{q13}, [r0,:128]!
> +	vswp		d15,d14
> +	vshr.s64	q6, q14, #63
> +	veor		q14, q14, q7
> +	vand		q6, q6, q5
> +	vld1.8		{q4}, [r7]!
> +	veor		q3, q3, q11
> +	vadd.u64	q15, q14, q14
> +	vst1.64		{q14}, [r0,:128]!
> +	vswp		d13,d12
> +	vshr.s64	q7, q15, #63
> +	veor		q15, q15, q6
> +	vand		q7, q7, q5
> +	vld1.8		{q5}, [r7]!
> +	veor		q4, q4, q12
> +	vadd.u64	q8, q15, q15
> +	vst1.64		{q15}, [r0,:128]!
> +	vswp		d15,d14
> +	veor		q8, q8, q7
> +	vst1.64		{q8}, [r0,:128]		@ next round tweak
> +
> +	vld1.8		{q6-q7}, [r7]!
> +	veor		q5, q5, q13
> +#ifndef	BSAES_ASM_EXTENDED_KEY
> +	add		r4, sp, #0x90			@ pass key schedule
> +#else
> +	add		r4, r10, #248			@ pass key schedule
> +#endif
> +	veor		q6, q6, q14
> +	mov		r5, r1			@ pass rounds
> +	veor		q7, q7, q15
> +	mov		r0, sp
> +
> +	bl		_bsaes_encrypt8
> +
> +	vld1.64		{q8-q9}, [r0,:128]!
> +	vld1.64		{q10-q11}, [r0,:128]!
> +	veor		q0, q0, q8
> +	vld1.64		{q12-q13}, [r0,:128]!
> +	veor		q1, q1, q9
> +	veor		q8, q4, q10
> +	vst1.8		{q0-q1}, [r8]!
> +	veor		q9, q6, q11
> +	vld1.64		{q14-q15}, [r0,:128]!
> +	veor		q10, q3, q12
> +	vst1.8		{q8-q9}, [r8]!
> +	veor		q11, q7, q13
> +	veor		q12, q2, q14
> +	vst1.8		{q10-q11}, [r8]!
> +	veor		q13, q5, q15
> +	vst1.8		{q12-q13}, [r8]!
> +
> +	vld1.64		{q8}, [r0,:128]		@ next round tweak
> +
> +	subs		r9, #0x80
> +	bpl		.Lxts_enc_loop
> +
> +.Lxts_enc_short:
> +	adds		r9, #0x70
> +	bmi		.Lxts_enc_done
> +
> +	vldmia		r2, {q5}	@ load XTS magic
> +	vshr.s64	q7, q8, #63
> +	mov		r0, sp
> +	vand		q7, q7, q5
> +	vadd.u64	q9, q8, q8
> +	vst1.64		{q8}, [r0,:128]!
> +	vswp		d15,d14
> +	vshr.s64	q6, q9, #63
> +	veor		q9, q9, q7
> +	vand		q6, q6, q5
> +	vadd.u64	q10, q9, q9
> +	vst1.64		{q9}, [r0,:128]!
> +	vswp		d13,d12
> +	vshr.s64	q7, q10, #63
> +	veor		q10, q10, q6
> +	vand		q7, q7, q5
> +	vld1.8		{q0}, [r7]!
> +	subs		r9, #0x10
> +	bmi		.Lxts_enc_1
> +	vadd.u64	q11, q10, q10
> +	vst1.64		{q10}, [r0,:128]!
> +	vswp		d15,d14
> +	vshr.s64	q6, q11, #63
> +	veor		q11, q11, q7
> +	vand		q6, q6, q5
> +	vld1.8		{q1}, [r7]!
> +	subs		r9, #0x10
> +	bmi		.Lxts_enc_2
> +	veor		q0, q0, q8
> +	vadd.u64	q12, q11, q11
> +	vst1.64		{q11}, [r0,:128]!
> +	vswp		d13,d12
> +	vshr.s64	q7, q12, #63
> +	veor		q12, q12, q6
> +	vand		q7, q7, q5
> +	vld1.8		{q2}, [r7]!
> +	subs		r9, #0x10
> +	bmi		.Lxts_enc_3
> +	veor		q1, q1, q9
> +	vadd.u64	q13, q12, q12
> +	vst1.64		{q12}, [r0,:128]!
> +	vswp		d15,d14
> +	vshr.s64	q6, q13, #63
> +	veor		q13, q13, q7
> +	vand		q6, q6, q5
> +	vld1.8		{q3}, [r7]!
> +	subs		r9, #0x10
> +	bmi		.Lxts_enc_4
> +	veor		q2, q2, q10
> +	vadd.u64	q14, q13, q13
> +	vst1.64		{q13}, [r0,:128]!
> +	vswp		d13,d12
> +	vshr.s64	q7, q14, #63
> +	veor		q14, q14, q6
> +	vand		q7, q7, q5
> +	vld1.8		{q4}, [r7]!
> +	subs		r9, #0x10
> +	bmi		.Lxts_enc_5
> +	veor		q3, q3, q11
> +	vadd.u64	q15, q14, q14
> +	vst1.64		{q14}, [r0,:128]!
> +	vswp		d15,d14
> +	vshr.s64	q6, q15, #63
> +	veor		q15, q15, q7
> +	vand		q6, q6, q5
> +	vld1.8		{q5}, [r7]!
> +	subs		r9, #0x10
> +	bmi		.Lxts_enc_6
> +	veor		q4, q4, q12
> +	sub		r9, #0x10
> +	vst1.64		{q15}, [r0,:128]		@ next round tweak
> +
> +	vld1.8		{q6}, [r7]!
> +	veor		q5, q5, q13
> +#ifndef	BSAES_ASM_EXTENDED_KEY
> +	add		r4, sp, #0x90			@ pass key schedule
> +#else
> +	add		r4, r10, #248			@ pass key schedule
> +#endif
> +	veor		q6, q6, q14
> +	mov		r5, r1			@ pass rounds
> +	mov		r0, sp
> +
> +	bl		_bsaes_encrypt8
> +
> +	vld1.64		{q8-q9}, [r0,:128]!
> +	vld1.64		{q10-q11}, [r0,:128]!
> +	veor		q0, q0, q8
> +	vld1.64		{q12-q13}, [r0,:128]!
> +	veor		q1, q1, q9
> +	veor		q8, q4, q10
> +	vst1.8		{q0-q1}, [r8]!
> +	veor		q9, q6, q11
> +	vld1.64		{q14}, [r0,:128]!
> +	veor		q10, q3, q12
> +	vst1.8		{q8-q9}, [r8]!
> +	veor		q11, q7, q13
> +	veor		q12, q2, q14
> +	vst1.8		{q10-q11}, [r8]!
> +	vst1.8		{q12}, [r8]!
> +
> +	vld1.64		{q8}, [r0,:128]		@ next round tweak
> +	b		.Lxts_enc_done
> +.align	4
> +.Lxts_enc_6:
> +	vst1.64		{q14}, [r0,:128]		@ next round tweak
> +
> +	veor		q4, q4, q12
> +#ifndef	BSAES_ASM_EXTENDED_KEY
> +	add		r4, sp, #0x90			@ pass key schedule
> +#else
> +	add		r4, r10, #248			@ pass key schedule
> +#endif
> +	veor		q5, q5, q13
> +	mov		r5, r1			@ pass rounds
> +	mov		r0, sp
> +
> +	bl		_bsaes_encrypt8
> +
> +	vld1.64		{q8-q9}, [r0,:128]!
> +	vld1.64		{q10-q11}, [r0,:128]!
> +	veor		q0, q0, q8
> +	vld1.64		{q12-q13}, [r0,:128]!
> +	veor		q1, q1, q9
> +	veor		q8, q4, q10
> +	vst1.8		{q0-q1}, [r8]!
> +	veor		q9, q6, q11
> +	veor		q10, q3, q12
> +	vst1.8		{q8-q9}, [r8]!
> +	veor		q11, q7, q13
> +	vst1.8		{q10-q11}, [r8]!
> +
> +	vld1.64		{q8}, [r0,:128]		@ next round tweak
> +	b		.Lxts_enc_done
> +
> +@ put this in range for both ARM and Thumb mode adr instructions
> +.align	5
> +.Lxts_magic:
> +	.quad	1, 0x87
> +
> +.align	5
> +.Lxts_enc_5:
> +	vst1.64		{q13}, [r0,:128]		@ next round tweak
> +
> +	veor		q3, q3, q11
> +#ifndef	BSAES_ASM_EXTENDED_KEY
> +	add		r4, sp, #0x90			@ pass key schedule
> +#else
> +	add		r4, r10, #248			@ pass key schedule
> +#endif
> +	veor		q4, q4, q12
> +	mov		r5, r1			@ pass rounds
> +	mov		r0, sp
> +
> +	bl		_bsaes_encrypt8
> +
> +	vld1.64		{q8-q9}, [r0,:128]!
> +	vld1.64		{q10-q11}, [r0,:128]!
> +	veor		q0, q0, q8
> +	vld1.64		{q12}, [r0,:128]!
> +	veor		q1, q1, q9
> +	veor		q8, q4, q10
> +	vst1.8		{q0-q1}, [r8]!
> +	veor		q9, q6, q11
> +	veor		q10, q3, q12
> +	vst1.8		{q8-q9}, [r8]!
> +	vst1.8		{q10}, [r8]!
> +
> +	vld1.64		{q8}, [r0,:128]		@ next round tweak
> +	b		.Lxts_enc_done
> +.align	4
> +.Lxts_enc_4:
> +	vst1.64		{q12}, [r0,:128]		@ next round tweak
> +
> +	veor		q2, q2, q10
> +#ifndef	BSAES_ASM_EXTENDED_KEY
> +	add		r4, sp, #0x90			@ pass key schedule
> +#else
> +	add		r4, r10, #248			@ pass key schedule
> +#endif
> +	veor		q3, q3, q11
> +	mov		r5, r1			@ pass rounds
> +	mov		r0, sp
> +
> +	bl		_bsaes_encrypt8
> +
> +	vld1.64		{q8-q9}, [r0,:128]!
> +	vld1.64		{q10-q11}, [r0,:128]!
> +	veor		q0, q0, q8
> +	veor		q1, q1, q9
> +	veor		q8, q4, q10
> +	vst1.8		{q0-q1}, [r8]!
> +	veor		q9, q6, q11
> +	vst1.8		{q8-q9}, [r8]!
> +
> +	vld1.64		{q8}, [r0,:128]		@ next round tweak
> +	b		.Lxts_enc_done
> +.align	4
> +.Lxts_enc_3:
> +	vst1.64		{q11}, [r0,:128]		@ next round tweak
> +
> +	veor		q1, q1, q9
> +#ifndef	BSAES_ASM_EXTENDED_KEY
> +	add		r4, sp, #0x90			@ pass key schedule
> +#else
> +	add		r4, r10, #248			@ pass key schedule
> +#endif
> +	veor		q2, q2, q10
> +	mov		r5, r1			@ pass rounds
> +	mov		r0, sp
> +
> +	bl		_bsaes_encrypt8
> +
> +	vld1.64		{q8-q9}, [r0,:128]!
> +	vld1.64		{q10}, [r0,:128]!
> +	veor		q0, q0, q8
> +	veor		q1, q1, q9
> +	veor		q8, q4, q10
> +	vst1.8		{q0-q1}, [r8]!
> +	vst1.8		{q8}, [r8]!
> +
> +	vld1.64		{q8}, [r0,:128]		@ next round tweak
> +	b		.Lxts_enc_done
> +.align	4
> +.Lxts_enc_2:
> +	vst1.64		{q10}, [r0,:128]		@ next round tweak
> +
> +	veor		q0, q0, q8
> +#ifndef	BSAES_ASM_EXTENDED_KEY
> +	add		r4, sp, #0x90			@ pass key schedule
> +#else
> +	add		r4, r10, #248			@ pass key schedule
> +#endif
> +	veor		q1, q1, q9
> +	mov		r5, r1			@ pass rounds
> +	mov		r0, sp
> +
> +	bl		_bsaes_encrypt8
> +
> +	vld1.64		{q8-q9}, [r0,:128]!
> +	veor		q0, q0, q8
> +	veor		q1, q1, q9
> +	vst1.8		{q0-q1}, [r8]!
> +
> +	vld1.64		{q8}, [r0,:128]		@ next round tweak
> +	b		.Lxts_enc_done
> +.align	4
> +.Lxts_enc_1:
> +	mov		r0, sp
> +	veor		q0, q8
> +	mov		r1, sp
> +	vst1.8		{q0}, [sp,:128]
> +	mov		r2, r10
> +	mov		r4, r3				@ preserve fp
> +
> +	bl		AES_encrypt
> +
> +	vld1.8		{q0}, [sp,:128]
> +	veor		q0, q0, q8
> +	vst1.8		{q0}, [r8]!
> +	mov		r3, r4
> +
> +	vmov		q8, q9		@ next round tweak
> +
> +.Lxts_enc_done:
> +#ifndef	XTS_CHAIN_TWEAK
> +	adds		r9, #0x10
> +	beq		.Lxts_enc_ret
> +	sub		r6, r8, #0x10
> +
> +.Lxts_enc_steal:
> +	ldrb		r0, [r7], #1
> +	ldrb		r1, [r8, #-0x10]
> +	strb		r0, [r8, #-0x10]
> +	strb		r1, [r8], #1
> +
> +	subs		r9, #1
> +	bhi		.Lxts_enc_steal
> +
> +	vld1.8		{q0}, [r6]
> +	mov		r0, sp
> +	veor		q0, q0, q8
> +	mov		r1, sp
> +	vst1.8		{q0}, [sp,:128]
> +	mov		r2, r10
> +	mov		r4, r3			@ preserve fp
> +
> +	bl		AES_encrypt
> +
> +	vld1.8		{q0}, [sp,:128]
> +	veor		q0, q0, q8
> +	vst1.8		{q0}, [r6]
> +	mov		r3, r4
> +#endif
> +
> +.Lxts_enc_ret:
> +	bic		r0, r3, #0xf
> +	vmov.i32	q0, #0
> +	vmov.i32	q1, #0
> +#ifdef	XTS_CHAIN_TWEAK
> +	ldr		r1, [r3, #0x20+VFP_ABI_FRAME]	@ chain tweak
> +#endif
> +.Lxts_enc_bzero:				@ wipe key schedule [if any]
> +	vstmia		sp!, {q0-q1}
> +	cmp		sp, r0
> +	bne		.Lxts_enc_bzero
> +
> +	mov		sp, r3
> +#ifdef	XTS_CHAIN_TWEAK
> +	vst1.8		{q8}, [r1]
> +#endif
> +	VFP_ABI_POP
> +	ldmia		sp!, {r4-r10, pc}	@ return
> +
> +.size	bsaes_xts_encrypt,.-bsaes_xts_encrypt
> +
> +.globl	bsaes_xts_decrypt
> +.type	bsaes_xts_decrypt,%function
> +.align	4
> +bsaes_xts_decrypt:
> +	mov	ip, sp
> +	stmdb	sp!, {r4-r10, lr}		@ 0x20
> +	VFP_ABI_PUSH
> +	mov	r6, sp				@ future r3
> +
> +	mov	r7, r0
> +	mov	r8, r1
> +	mov	r9, r2
> +	mov	r10, r3
> +
> +	sub	r0, sp, #0x10			@ 0x10
> +	bic	r0, #0xf			@ align at 16 bytes
> +	mov	sp, r0
> +
> +#ifdef	XTS_CHAIN_TWEAK
> +	ldr	r0, [ip]			@ pointer to input tweak
> +#else
> +	@ generate initial tweak
> +	ldr	r0, [ip, #4]			@ iv[]
> +	mov	r1, sp
> +	ldr	r2, [ip, #0]			@ key2
> +	bl	AES_encrypt
> +	mov	r0, sp				@ pointer to initial tweak
> +#endif
> +
> +	ldr	r1, [r10, #240]		@ get # of rounds
> +	mov	r3, r6
> +#ifndef	BSAES_ASM_EXTENDED_KEY
> +	@ allocate the key schedule on the stack
> +	sub	r12, sp, r1, lsl#7		@ 128 bytes per inner round key
> +	@ add	r12, #96			@ size of bit-sliced key schedule
> +	sub	r12, #48			@ place for tweak[9]
> +
> +	@ populate the key schedule
> +	mov	r4, r10			@ pass key
> +	mov	r5, r1			@ pass # of rounds
> +	mov	sp, r12
> +	add	r12, #0x90			@ pass key schedule
> +	bl	_bsaes_key_convert
> +	add	r4, sp, #0x90
> +	vldmia	r4, {q6}
> +	vstmia	r12,  {q15}		@ save last round key
> +	veor	q7, q7, q6	@ fix up round 0 key
> +	vstmia	r4, {q7}
> +#else
> +	ldr	r12, [r10, #244]
> +	eors	r12, #1
> +	beq	0f
> +
> +	str	r12, [r10, #244]
> +	mov	r4, r10			@ pass key
> +	mov	r5, r1			@ pass # of rounds
> +	add	r12, r10, #248			@ pass key schedule
> +	bl	_bsaes_key_convert
> +	add	r4, r10, #248
> +	vldmia	r4, {q6}
> +	vstmia	r12,  {q15}		@ save last round key
> +	veor	q7, q7, q6	@ fix up round 0 key
> +	vstmia	r4, {q7}
> +
> +.align	2
> +0:	sub	sp, #0x90			@ place for tweak[9]
> +#endif
> +	vld1.8	{q8}, [r0]			@ initial tweak
> +	adr	r2, .Lxts_magic
> +
> +	tst	r9, #0xf			@ if not multiple of 16
> +	it	ne				@ Thumb2 thing, sanity check in ARM
> +	subne	r9, #0x10			@ subtract another 16 bytes
> +	subs	r9, #0x80
> +
> +	blo	.Lxts_dec_short
> +	b	.Lxts_dec_loop
> +
> +.align	4
> +.Lxts_dec_loop:
> +	vldmia		r2, {q5}	@ load XTS magic
> +	vshr.s64	q6, q8, #63
> +	mov		r0, sp
> +	vand		q6, q6, q5
> +	vadd.u64	q9, q8, q8
> +	vst1.64		{q8}, [r0,:128]!
> +	vswp		d13,d12
> +	vshr.s64	q7, q9, #63
> +	veor		q9, q9, q6
> +	vand		q7, q7, q5
> +	vadd.u64	q10, q9, q9
> +	vst1.64		{q9}, [r0,:128]!
> +	vswp		d15,d14
> +	vshr.s64	q6, q10, #63
> +	veor		q10, q10, q7
> +	vand		q6, q6, q5
> +	vld1.8		{q0}, [r7]!
> +	vadd.u64	q11, q10, q10
> +	vst1.64		{q10}, [r0,:128]!
> +	vswp		d13,d12
> +	vshr.s64	q7, q11, #63
> +	veor		q11, q11, q6
> +	vand		q7, q7, q5
> +	vld1.8		{q1}, [r7]!
> +	veor		q0, q0, q8
> +	vadd.u64	q12, q11, q11
> +	vst1.64		{q11}, [r0,:128]!
> +	vswp		d15,d14
> +	vshr.s64	q6, q12, #63
> +	veor		q12, q12, q7
> +	vand		q6, q6, q5
> +	vld1.8		{q2}, [r7]!
> +	veor		q1, q1, q9
> +	vadd.u64	q13, q12, q12
> +	vst1.64		{q12}, [r0,:128]!
> +	vswp		d13,d12
> +	vshr.s64	q7, q13, #63
> +	veor		q13, q13, q6
> +	vand		q7, q7, q5
> +	vld1.8		{q3}, [r7]!
> +	veor		q2, q2, q10
> +	vadd.u64	q14, q13, q13
> +	vst1.64		{q13}, [r0,:128]!
> +	vswp		d15,d14
> +	vshr.s64	q6, q14, #63
> +	veor		q14, q14, q7
> +	vand		q6, q6, q5
> +	vld1.8		{q4}, [r7]!
> +	veor		q3, q3, q11
> +	vadd.u64	q15, q14, q14
> +	vst1.64		{q14}, [r0,:128]!
> +	vswp		d13,d12
> +	vshr.s64	q7, q15, #63
> +	veor		q15, q15, q6
> +	vand		q7, q7, q5
> +	vld1.8		{q5}, [r7]!
> +	veor		q4, q4, q12
> +	vadd.u64	q8, q15, q15
> +	vst1.64		{q15}, [r0,:128]!
> +	vswp		d15,d14
> +	veor		q8, q8, q7
> +	vst1.64		{q8}, [r0,:128]		@ next round tweak
> +
> +	vld1.8		{q6-q7}, [r7]!
> +	veor		q5, q5, q13
> +#ifndef	BSAES_ASM_EXTENDED_KEY
> +	add		r4, sp, #0x90			@ pass key schedule
> +#else
> +	add		r4, r10, #248			@ pass key schedule
> +#endif
> +	veor		q6, q6, q14
> +	mov		r5, r1			@ pass rounds
> +	veor		q7, q7, q15
> +	mov		r0, sp
> +
> +	bl		_bsaes_decrypt8
> +
> +	vld1.64		{q8-q9}, [r0,:128]!
> +	vld1.64		{q10-q11}, [r0,:128]!
> +	veor		q0, q0, q8
> +	vld1.64		{q12-q13}, [r0,:128]!
> +	veor		q1, q1, q9
> +	veor		q8, q6, q10
> +	vst1.8		{q0-q1}, [r8]!
> +	veor		q9, q4, q11
> +	vld1.64		{q14-q15}, [r0,:128]!
> +	veor		q10, q2, q12
> +	vst1.8		{q8-q9}, [r8]!
> +	veor		q11, q7, q13
> +	veor		q12, q3, q14
> +	vst1.8		{q10-q11}, [r8]!
> +	veor		q13, q5, q15
> +	vst1.8		{q12-q13}, [r8]!
> +
> +	vld1.64		{q8}, [r0,:128]		@ next round tweak
> +
> +	subs		r9, #0x80
> +	bpl		.Lxts_dec_loop
> +
> +.Lxts_dec_short:
> +	adds		r9, #0x70
> +	bmi		.Lxts_dec_done
> +
> +	vldmia		r2, {q5}	@ load XTS magic
> +	vshr.s64	q7, q8, #63
> +	mov		r0, sp
> +	vand		q7, q7, q5
> +	vadd.u64	q9, q8, q8
> +	vst1.64		{q8}, [r0,:128]!
> +	vswp		d15,d14
> +	vshr.s64	q6, q9, #63
> +	veor		q9, q9, q7
> +	vand		q6, q6, q5
> +	vadd.u64	q10, q9, q9
> +	vst1.64		{q9}, [r0,:128]!
> +	vswp		d13,d12
> +	vshr.s64	q7, q10, #63
> +	veor		q10, q10, q6
> +	vand		q7, q7, q5
> +	vld1.8		{q0}, [r7]!
> +	subs		r9, #0x10
> +	bmi		.Lxts_dec_1
> +	vadd.u64	q11, q10, q10
> +	vst1.64		{q10}, [r0,:128]!
> +	vswp		d15,d14
> +	vshr.s64	q6, q11, #63
> +	veor		q11, q11, q7
> +	vand		q6, q6, q5
> +	vld1.8		{q1}, [r7]!
> +	subs		r9, #0x10
> +	bmi		.Lxts_dec_2
> +	veor		q0, q0, q8
> +	vadd.u64	q12, q11, q11
> +	vst1.64		{q11}, [r0,:128]!
> +	vswp		d13,d12
> +	vshr.s64	q7, q12, #63
> +	veor		q12, q12, q6
> +	vand		q7, q7, q5
> +	vld1.8		{q2}, [r7]!
> +	subs		r9, #0x10
> +	bmi		.Lxts_dec_3
> +	veor		q1, q1, q9
> +	vadd.u64	q13, q12, q12
> +	vst1.64		{q12}, [r0,:128]!
> +	vswp		d15,d14
> +	vshr.s64	q6, q13, #63
> +	veor		q13, q13, q7
> +	vand		q6, q6, q5
> +	vld1.8		{q3}, [r7]!
> +	subs		r9, #0x10
> +	bmi		.Lxts_dec_4
> +	veor		q2, q2, q10
> +	vadd.u64	q14, q13, q13
> +	vst1.64		{q13}, [r0,:128]!
> +	vswp		d13,d12
> +	vshr.s64	q7, q14, #63
> +	veor		q14, q14, q6
> +	vand		q7, q7, q5
> +	vld1.8		{q4}, [r7]!
> +	subs		r9, #0x10
> +	bmi		.Lxts_dec_5
> +	veor		q3, q3, q11
> +	vadd.u64	q15, q14, q14
> +	vst1.64		{q14}, [r0,:128]!
> +	vswp		d15,d14
> +	vshr.s64	q6, q15, #63
> +	veor		q15, q15, q7
> +	vand		q6, q6, q5
> +	vld1.8		{q5}, [r7]!
> +	subs		r9, #0x10
> +	bmi		.Lxts_dec_6
> +	veor		q4, q4, q12
> +	sub		r9, #0x10
> +	vst1.64		{q15}, [r0,:128]		@ next round tweak
> +
> +	vld1.8		{q6}, [r7]!
> +	veor		q5, q5, q13
> +#ifndef	BSAES_ASM_EXTENDED_KEY
> +	add		r4, sp, #0x90			@ pass key schedule
> +#else
> +	add		r4, r10, #248			@ pass key schedule
> +#endif
> +	veor		q6, q6, q14
> +	mov		r5, r1			@ pass rounds
> +	mov		r0, sp
> +
> +	bl		_bsaes_decrypt8
> +
> +	vld1.64		{q8-q9}, [r0,:128]!
> +	vld1.64		{q10-q11}, [r0,:128]!
> +	veor		q0, q0, q8
> +	vld1.64		{q12-q13}, [r0,:128]!
> +	veor		q1, q1, q9
> +	veor		q8, q6, q10
> +	vst1.8		{q0-q1}, [r8]!
> +	veor		q9, q4, q11
> +	vld1.64		{q14}, [r0,:128]!
> +	veor		q10, q2, q12
> +	vst1.8		{q8-q9}, [r8]!
> +	veor		q11, q7, q13
> +	veor		q12, q3, q14
> +	vst1.8		{q10-q11}, [r8]!
> +	vst1.8		{q12}, [r8]!
> +
> +	vld1.64		{q8}, [r0,:128]		@ next round tweak
> +	b		.Lxts_dec_done
> +.align	4
> +.Lxts_dec_6:
> +	vst1.64		{q14}, [r0,:128]		@ next round tweak
> +
> +	veor		q4, q4, q12
> +#ifndef	BSAES_ASM_EXTENDED_KEY
> +	add		r4, sp, #0x90			@ pass key schedule
> +#else
> +	add		r4, r10, #248			@ pass key schedule
> +#endif
> +	veor		q5, q5, q13
> +	mov		r5, r1			@ pass rounds
> +	mov		r0, sp
> +
> +	bl		_bsaes_decrypt8
> +
> +	vld1.64		{q8-q9}, [r0,:128]!
> +	vld1.64		{q10-q11}, [r0,:128]!
> +	veor		q0, q0, q8
> +	vld1.64		{q12-q13}, [r0,:128]!
> +	veor		q1, q1, q9
> +	veor		q8, q6, q10
> +	vst1.8		{q0-q1}, [r8]!
> +	veor		q9, q4, q11
> +	veor		q10, q2, q12
> +	vst1.8		{q8-q9}, [r8]!
> +	veor		q11, q7, q13
> +	vst1.8		{q10-q11}, [r8]!
> +
> +	vld1.64		{q8}, [r0,:128]		@ next round tweak
> +	b		.Lxts_dec_done
> +.align	4
> +.Lxts_dec_5:
> +	vst1.64		{q13}, [r0,:128]		@ next round tweak
> +
> +	veor		q3, q3, q11
> +#ifndef	BSAES_ASM_EXTENDED_KEY
> +	add		r4, sp, #0x90			@ pass key schedule
> +#else
> +	add		r4, r10, #248			@ pass key schedule
> +#endif
> +	veor		q4, q4, q12
> +	mov		r5, r1			@ pass rounds
> +	mov		r0, sp
> +
> +	bl		_bsaes_decrypt8
> +
> +	vld1.64		{q8-q9}, [r0,:128]!
> +	vld1.64		{q10-q11}, [r0,:128]!
> +	veor		q0, q0, q8
> +	vld1.64		{q12}, [r0,:128]!
> +	veor		q1, q1, q9
> +	veor		q8, q6, q10
> +	vst1.8		{q0-q1}, [r8]!
> +	veor		q9, q4, q11
> +	veor		q10, q2, q12
> +	vst1.8		{q8-q9}, [r8]!
> +	vst1.8		{q10}, [r8]!
> +
> +	vld1.64		{q8}, [r0,:128]		@ next round tweak
> +	b		.Lxts_dec_done
> +.align	4
> +.Lxts_dec_4:
> +	vst1.64		{q12}, [r0,:128]		@ next round tweak
> +
> +	veor		q2, q2, q10
> +#ifndef	BSAES_ASM_EXTENDED_KEY
> +	add		r4, sp, #0x90			@ pass key schedule
> +#else
> +	add		r4, r10, #248			@ pass key schedule
> +#endif
> +	veor		q3, q3, q11
> +	mov		r5, r1			@ pass rounds
> +	mov		r0, sp
> +
> +	bl		_bsaes_decrypt8
> +
> +	vld1.64		{q8-q9}, [r0,:128]!
> +	vld1.64		{q10-q11}, [r0,:128]!
> +	veor		q0, q0, q8
> +	veor		q1, q1, q9
> +	veor		q8, q6, q10
> +	vst1.8		{q0-q1}, [r8]!
> +	veor		q9, q4, q11
> +	vst1.8		{q8-q9}, [r8]!
> +
> +	vld1.64		{q8}, [r0,:128]		@ next round tweak
> +	b		.Lxts_dec_done
> +.align	4
> +.Lxts_dec_3:
> +	vst1.64		{q11}, [r0,:128]		@ next round tweak
> +
> +	veor		q1, q1, q9
> +#ifndef	BSAES_ASM_EXTENDED_KEY
> +	add		r4, sp, #0x90			@ pass key schedule
> +#else
> +	add		r4, r10, #248			@ pass key schedule
> +#endif
> +	veor		q2, q2, q10
> +	mov		r5, r1			@ pass rounds
> +	mov		r0, sp
> +
> +	bl		_bsaes_decrypt8
> +
> +	vld1.64		{q8-q9}, [r0,:128]!
> +	vld1.64		{q10}, [r0,:128]!
> +	veor		q0, q0, q8
> +	veor		q1, q1, q9
> +	veor		q8, q6, q10
> +	vst1.8		{q0-q1}, [r8]!
> +	vst1.8		{q8}, [r8]!
> +
> +	vld1.64		{q8}, [r0,:128]		@ next round tweak
> +	b		.Lxts_dec_done
> +.align	4
> +.Lxts_dec_2:
> +	vst1.64		{q10}, [r0,:128]		@ next round tweak
> +
> +	veor		q0, q0, q8
> +#ifndef	BSAES_ASM_EXTENDED_KEY
> +	add		r4, sp, #0x90			@ pass key schedule
> +#else
> +	add		r4, r10, #248			@ pass key schedule
> +#endif
> +	veor		q1, q1, q9
> +	mov		r5, r1			@ pass rounds
> +	mov		r0, sp
> +
> +	bl		_bsaes_decrypt8
> +
> +	vld1.64		{q8-q9}, [r0,:128]!
> +	veor		q0, q0, q8
> +	veor		q1, q1, q9
> +	vst1.8		{q0-q1}, [r8]!
> +
> +	vld1.64		{q8}, [r0,:128]		@ next round tweak
> +	b		.Lxts_dec_done
> +.align	4
> +.Lxts_dec_1:
> +	mov		r0, sp
> +	veor		q0, q8
> +	mov		r1, sp
> +	vst1.8		{q0}, [sp,:128]
> +	mov		r2, r10
> +	mov		r4, r3				@ preserve fp
> +	mov		r5, r2			@ preserve magic
> +
> +	bl		AES_decrypt
> +
> +	vld1.8		{q0}, [sp,:128]
> +	veor		q0, q0, q8
> +	vst1.8		{q0}, [r8]!
> +	mov		r3, r4
> +	mov		r2, r5
> +
> +	vmov		q8, q9		@ next round tweak
> +
> +.Lxts_dec_done:
> +#ifndef	XTS_CHAIN_TWEAK
> +	adds		r9, #0x10
> +	beq		.Lxts_dec_ret
> +
> +	@ calculate one round of extra tweak for the stolen ciphertext
> +	vldmia		r2, {q5}
> +	vshr.s64	q6, q8, #63
> +	vand		q6, q6, q5
> +	vadd.u64	q9, q8, q8
> +	vswp		d13,d12
> +	veor		q9, q9, q6
> +
> +	@ perform the final decryption with the last tweak value
> +	vld1.8		{q0}, [r7]!
> +	mov		r0, sp
> +	veor		q0, q0, q9
> +	mov		r1, sp
> +	vst1.8		{q0}, [sp,:128]
> +	mov		r2, r10
> +	mov		r4, r3			@ preserve fp
> +
> +	bl		AES_decrypt
> +
> +	vld1.8		{q0}, [sp,:128]
> +	veor		q0, q0, q9
> +	vst1.8		{q0}, [r8]
> +
> +	mov		r6, r8
> +.Lxts_dec_steal:
> +	ldrb		r1, [r8]
> +	ldrb		r0, [r7], #1
> +	strb		r1, [r8, #0x10]
> +	strb		r0, [r8], #1
> +
> +	subs		r9, #1
> +	bhi		.Lxts_dec_steal
> +
> +	vld1.8		{q0}, [r6]
> +	mov		r0, sp
> +	veor		q0, q8
> +	mov		r1, sp
> +	vst1.8		{q0}, [sp,:128]
> +	mov		r2, r10
> +
> +	bl		AES_decrypt
> +
> +	vld1.8		{q0}, [sp,:128]
> +	veor		q0, q0, q8
> +	vst1.8		{q0}, [r6]
> +	mov		r3, r4
> +#endif
> +
> +.Lxts_dec_ret:
> +	bic		r0, r3, #0xf
> +	vmov.i32	q0, #0
> +	vmov.i32	q1, #0
> +#ifdef	XTS_CHAIN_TWEAK
> +	ldr		r1, [r3, #0x20+VFP_ABI_FRAME]	@ chain tweak
> +#endif
> +.Lxts_dec_bzero:				@ wipe key schedule [if any]
> +	vstmia		sp!, {q0-q1}
> +	cmp		sp, r0
> +	bne		.Lxts_dec_bzero
> +
> +	mov		sp, r3
> +#ifdef	XTS_CHAIN_TWEAK
> +	vst1.8		{q8}, [r1]
> +#endif
> +	VFP_ABI_POP
> +	ldmia		sp!, {r4-r10, pc}	@ return
> +
> +.size	bsaes_xts_decrypt,.-bsaes_xts_decrypt
> +#endif
> diff --git a/arch/arm/crypto/aesbs-glue.c b/arch/arm/crypto/aesbs-glue.c
> new file mode 100644
> index 0000000..e809443
> --- /dev/null
> +++ b/arch/arm/crypto/aesbs-glue.c
> @@ -0,0 +1,435 @@
> +/*
> + * linux/arch/arm/crypto/aesbs-glue.c - glue code for NEON bit sliced AES
> + *
> + * Copyright (C) 2013 Linaro Ltd <ard.biesheuvel at linaro.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <asm/neon.h>
> +#include <crypto/aes.h>
> +#include <crypto/ablk_helper.h>
> +#include <crypto/algapi.h>
> +#include <linux/module.h>
> +
> +#include "aes_glue.h"
> +
> +#define BIT_SLICED_KEY_MAXSIZE	(128 * (AES_MAXNR - 1) + 2 * AES_BLOCK_SIZE)
> +
> +struct BS_KEY {
> +	struct AES_KEY	rk;
> +	int		converted;
> +	u8 __aligned(8)	bs[BIT_SLICED_KEY_MAXSIZE];
> +} __aligned(8);
> +
> +asmlinkage void bsaes_enc_key_convert(u8 out[], struct AES_KEY const *in);
> +asmlinkage void bsaes_dec_key_convert(u8 out[], struct AES_KEY const *in);
> +
> +asmlinkage void bsaes_cbc_encrypt(u8 const in[], u8 out[], u32 bytes,
> +				  struct BS_KEY *key, u8 iv[]);
> +
> +asmlinkage void bsaes_ctr32_encrypt_blocks(u8 const in[], u8 out[], u32 blocks,
> +					   struct BS_KEY *key, u8 const iv[]);
> +
> +asmlinkage void bsaes_xts_encrypt(u8 const in[], u8 out[], u32 bytes,
> +				  struct BS_KEY *key, u8 tweak[]);
> +
> +asmlinkage void bsaes_xts_decrypt(u8 const in[], u8 out[], u32 bytes,
> +				  struct BS_KEY *key, u8 tweak[]);
> +
> +struct aesbs_cbc_ctx {
> +	struct AES_KEY	enc;
> +	struct BS_KEY	dec;
> +};
> +
> +struct aesbs_ctr_ctx {
> +	struct BS_KEY	enc;
> +};
> +
> +struct aesbs_xts_ctx {
> +	struct BS_KEY	enc;
> +	struct BS_KEY	dec;
> +	struct AES_KEY	twkey;
> +};
> +
> +static int aesbs_cbc_set_key(struct crypto_tfm *tfm, const u8 *in_key,
> +			     unsigned int key_len)
> +{
> +	struct aesbs_cbc_ctx *ctx = crypto_tfm_ctx(tfm);
> +	int bits = key_len * 8;
> +
> +	if (private_AES_set_encrypt_key(in_key, bits, &ctx->enc)) {
> +		tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
> +		return -EINVAL;
> +	}
> +	ctx->dec.rk = ctx->enc;
> +	private_AES_set_decrypt_key(in_key, bits, &ctx->dec.rk);
> +	ctx->dec.converted = 0;
> +	return 0;
> +}
> +
> +static int aesbs_ctr_set_key(struct crypto_tfm *tfm, const u8 *in_key,
> +			     unsigned int key_len)
> +{
> +	struct aesbs_ctr_ctx *ctx = crypto_tfm_ctx(tfm);
> +	int bits = key_len * 8;
> +
> +	if (private_AES_set_encrypt_key(in_key, bits, &ctx->enc.rk)) {
> +		tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
> +		return -EINVAL;
> +	}
> +	ctx->enc.converted = 0;
> +	return 0;
> +}
> +
> +static int aesbs_xts_set_key(struct crypto_tfm *tfm, const u8 *in_key,
> +			     unsigned int key_len)
> +{
> +	struct aesbs_xts_ctx *ctx = crypto_tfm_ctx(tfm);
> +	int bits = key_len * 4;
> +
> +	if (private_AES_set_encrypt_key(in_key, bits, &ctx->enc.rk)) {
> +		tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
> +		return -EINVAL;
> +	}
> +	ctx->dec.rk = ctx->enc.rk;
> +	private_AES_set_decrypt_key(in_key, bits, &ctx->dec.rk);
> +	private_AES_set_encrypt_key(in_key + key_len / 2, bits, &ctx->twkey);
> +	ctx->enc.converted = ctx->dec.converted = 0;
> +	return 0;
> +}
> +
> +static int aesbs_cbc_encrypt(struct blkcipher_desc *desc,
> +			     struct scatterlist *dst,
> +			     struct scatterlist *src, unsigned int nbytes)
> +{
> +	struct aesbs_cbc_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
> +	struct blkcipher_walk walk;
> +	int err;
> +
> +	blkcipher_walk_init(&walk, dst, src, nbytes);
> +	err = blkcipher_walk_virt(desc, &walk);
> +
> +	while (walk.nbytes) {
> +		u32 blocks = walk.nbytes / AES_BLOCK_SIZE;
> +		u8 *src = walk.src.virt.addr;
> +
> +		if (walk.dst.virt.addr == walk.src.virt.addr) {
> +			u8 *iv = walk.iv;
> +
> +			do {
> +				crypto_xor(src, iv, AES_BLOCK_SIZE);
> +				AES_encrypt(src, src, &ctx->enc);
> +				iv = src;
> +				src += AES_BLOCK_SIZE;
> +			} while (--blocks);
> +			memcpy(walk.iv, iv, AES_BLOCK_SIZE);
> +		} else {
> +			u8 *dst = walk.dst.virt.addr;
> +
> +			do {
> +				crypto_xor(walk.iv, src, AES_BLOCK_SIZE);
> +				AES_encrypt(walk.iv, dst, &ctx->enc);
> +				memcpy(walk.iv, dst, AES_BLOCK_SIZE);
> +				src += AES_BLOCK_SIZE;
> +				dst += AES_BLOCK_SIZE;
> +			} while (--blocks);
> +		}
> +		err = blkcipher_walk_done(desc, &walk, 0);
> +	}
> +	return err;
> +}
> +
> +static int aesbs_cbc_decrypt(struct blkcipher_desc *desc,
> +			     struct scatterlist *dst,
> +			     struct scatterlist *src, unsigned int nbytes)
> +{
> +	struct aesbs_cbc_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
> +	struct blkcipher_walk walk;
> +	int err;
> +
> +	blkcipher_walk_init(&walk, dst, src, nbytes);
> +	err = blkcipher_walk_virt_block(desc, &walk, 8 * AES_BLOCK_SIZE);
> +
> +	while ((walk.nbytes / AES_BLOCK_SIZE) >= 8) {
> +		kernel_neon_begin();
> +		bsaes_cbc_encrypt(walk.src.virt.addr, walk.dst.virt.addr,
> +				  walk.nbytes, &ctx->dec, walk.iv);
> +		kernel_neon_end();
> +		err = blkcipher_walk_done(desc, &walk, 0);
> +	}
> +	while (walk.nbytes) {
> +		u32 blocks = walk.nbytes / AES_BLOCK_SIZE;
> +		u8 *dst = walk.dst.virt.addr;
> +		u8 *src = walk.src.virt.addr;
> +		u8 *iv = walk.iv;
> +
> +		do {
> +			u8 bk[2][AES_BLOCK_SIZE];
> +
> +			if (walk.dst.virt.addr == walk.src.virt.addr)
> +				memcpy(bk[blocks & 1], src, AES_BLOCK_SIZE);
> +
> +			AES_decrypt(src, dst, &ctx->dec.rk);
> +			crypto_xor(dst, iv, AES_BLOCK_SIZE);
> +
> +			if (walk.dst.virt.addr == walk.src.virt.addr)
> +				iv = bk[blocks & 1];
> +			else
> +				iv = src;
> +
> +			dst += AES_BLOCK_SIZE;
> +			src += AES_BLOCK_SIZE;
> +		} while (--blocks);
> +		err = blkcipher_walk_done(desc, &walk, 0);
> +	}
> +	return err;
> +}
> +
> +static void inc_be128_ctr(__be32 ctr[], u32 addend)
> +{
> +	int i;
> +
> +	for (i = 3; i >= 0; i--, addend = 1) {
> +		u32 n = be32_to_cpu(ctr[i]) + addend;
> +
> +		ctr[i] = cpu_to_be32(n);
> +		if (n >= addend)
> +			break;
> +	}
> +}
> +
> +static int aesbs_ctr_encrypt(struct blkcipher_desc *desc,
> +			     struct scatterlist *dst, struct scatterlist *src,
> +			     unsigned int nbytes)
> +{
> +	struct aesbs_ctr_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
> +	struct blkcipher_walk walk;
> +	u32 blocks;
> +	int err;
> +
> +	blkcipher_walk_init(&walk, dst, src, nbytes);
> +	err = blkcipher_walk_virt_block(desc, &walk, 8 * AES_BLOCK_SIZE);
> +
> +	while ((blocks = walk.nbytes / AES_BLOCK_SIZE)) {
> +		u32 tail = walk.nbytes % AES_BLOCK_SIZE;
> +		__be32 *ctr = (__be32 *)walk.iv;
> +		u32 headroom = UINT_MAX - be32_to_cpu(ctr[3]);
> +
> +		/* avoid 32 bit counter overflow in the NEON code */
> +		if (unlikely(headroom < blocks)) {
> +			blocks = headroom + 1;
> +			tail = walk.nbytes - blocks * AES_BLOCK_SIZE;
> +		}
> +		kernel_neon_begin();
> +		bsaes_ctr32_encrypt_blocks(walk.src.virt.addr,
> +					   walk.dst.virt.addr, blocks,
> +					   &ctx->enc, walk.iv);
> +		kernel_neon_end();
> +		inc_be128_ctr(ctr, blocks);
> +
> +		nbytes -= blocks * AES_BLOCK_SIZE;
> +		if (nbytes && nbytes == tail && nbytes <= AES_BLOCK_SIZE)
> +			break;
> +
> +		err = blkcipher_walk_done(desc, &walk, tail);
> +	}
> +	if (walk.nbytes) {
> +		u8 *tdst = walk.dst.virt.addr + blocks * AES_BLOCK_SIZE;
> +		u8 *tsrc = walk.src.virt.addr + blocks * AES_BLOCK_SIZE;
> +		u8 ks[AES_BLOCK_SIZE];
> +
> +		AES_encrypt(walk.iv, ks, &ctx->enc.rk);
> +		if (tdst != tsrc)
> +			memcpy(tdst, tsrc, nbytes);
> +		crypto_xor(tdst, ks, nbytes);
> +		err = blkcipher_walk_done(desc, &walk, 0);
> +	}
> +	return err;
> +}
> +
> +static int aesbs_xts_encrypt(struct blkcipher_desc *desc,
> +			     struct scatterlist *dst,
> +			     struct scatterlist *src, unsigned int nbytes)
> +{
> +	struct aesbs_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
> +	struct blkcipher_walk walk;
> +	int err;
> +
> +	blkcipher_walk_init(&walk, dst, src, nbytes);
> +	err = blkcipher_walk_virt_block(desc, &walk, 8 * AES_BLOCK_SIZE);
> +
> +	/* generate the initial tweak */
> +	AES_encrypt(walk.iv, walk.iv, &ctx->twkey);
> +
> +	while (walk.nbytes) {
> +		kernel_neon_begin();
> +		bsaes_xts_encrypt(walk.src.virt.addr, walk.dst.virt.addr,
> +				  walk.nbytes, &ctx->enc, walk.iv);
> +		kernel_neon_end();
> +		err = blkcipher_walk_done(desc, &walk, 0);
> +	}
> +	return err;
> +}
> +
> +static int aesbs_xts_decrypt(struct blkcipher_desc *desc,
> +			     struct scatterlist *dst,
> +			     struct scatterlist *src, unsigned int nbytes)
> +{
> +	struct aesbs_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
> +	struct blkcipher_walk walk;
> +	int err;
> +
> +	blkcipher_walk_init(&walk, dst, src, nbytes);
> +	err = blkcipher_walk_virt_block(desc, &walk, 8 * AES_BLOCK_SIZE);
> +
> +	/* generate the initial tweak */
> +	AES_encrypt(walk.iv, walk.iv, &ctx->twkey);
> +
> +	while (walk.nbytes) {
> +		kernel_neon_begin();
> +		bsaes_xts_decrypt(walk.src.virt.addr, walk.dst.virt.addr,
> +				  walk.nbytes, &ctx->dec, walk.iv);
> +		kernel_neon_end();
> +		err = blkcipher_walk_done(desc, &walk, 0);
> +	}
> +	return err;
> +}
> +
> +static struct crypto_alg aesbs_algs[] = { {
> +	.cra_name		= "__cbc-aes-neonbs",
> +	.cra_driver_name	= "__driver-cbc-aes-neonbs",
> +	.cra_priority		= 0,
> +	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
> +	.cra_blocksize		= AES_BLOCK_SIZE,
> +	.cra_ctxsize		= sizeof(struct aesbs_cbc_ctx),
> +	.cra_alignmask		= 7,
> +	.cra_type		= &crypto_blkcipher_type,
> +	.cra_module		= THIS_MODULE,
> +	.cra_blkcipher = {
> +		.min_keysize	= AES_MIN_KEY_SIZE,
> +		.max_keysize	= AES_MAX_KEY_SIZE,
> +		.ivsize		= AES_BLOCK_SIZE,
> +		.setkey		= aesbs_cbc_set_key,
> +		.encrypt	= aesbs_cbc_encrypt,
> +		.decrypt	= aesbs_cbc_decrypt,
> +	},
> +}, {
> +	.cra_name		= "__ctr-aes-neonbs",
> +	.cra_driver_name	= "__driver-ctr-aes-neonbs",
> +	.cra_priority		= 0,
> +	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
> +	.cra_blocksize		= 1,
> +	.cra_ctxsize		= sizeof(struct aesbs_ctr_ctx),
> +	.cra_alignmask		= 7,
> +	.cra_type		= &crypto_blkcipher_type,
> +	.cra_module		= THIS_MODULE,
> +	.cra_blkcipher = {
> +		.min_keysize	= AES_MIN_KEY_SIZE,
> +		.max_keysize	= AES_MAX_KEY_SIZE,
> +		.ivsize		= AES_BLOCK_SIZE,
> +		.setkey		= aesbs_ctr_set_key,
> +		.encrypt	= aesbs_ctr_encrypt,
> +		.decrypt	= aesbs_ctr_encrypt,
> +	},
> +}, {
> +	.cra_name		= "__xts-aes-neonbs",
> +	.cra_driver_name	= "__driver-xts-aes-neonbs",
> +	.cra_priority		= 0,
> +	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
> +	.cra_blocksize		= AES_BLOCK_SIZE,
> +	.cra_ctxsize		= sizeof(struct aesbs_xts_ctx),
> +	.cra_alignmask		= 7,
> +	.cra_type		= &crypto_blkcipher_type,
> +	.cra_module		= THIS_MODULE,
> +	.cra_blkcipher = {
> +		.min_keysize	= 2 * AES_MIN_KEY_SIZE,
> +		.max_keysize	= 2 * AES_MAX_KEY_SIZE,
> +		.ivsize		= AES_BLOCK_SIZE,
> +		.setkey		= aesbs_xts_set_key,
> +		.encrypt	= aesbs_xts_encrypt,
> +		.decrypt	= aesbs_xts_decrypt,
> +	},
> +}, {
> +	.cra_name		= "cbc(aes)",
> +	.cra_driver_name	= "cbc-aes-neonbs",
> +	.cra_priority		= 300,
> +	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
> +	.cra_blocksize		= AES_BLOCK_SIZE,
> +	.cra_ctxsize		= sizeof(struct async_helper_ctx),
> +	.cra_alignmask		= 7,
> +	.cra_type		= &crypto_ablkcipher_type,
> +	.cra_module		= THIS_MODULE,
> +	.cra_init		= ablk_init,
> +	.cra_exit		= ablk_exit,
> +	.cra_ablkcipher = {
> +		.min_keysize	= AES_MIN_KEY_SIZE,
> +		.max_keysize	= AES_MAX_KEY_SIZE,
> +		.ivsize		= AES_BLOCK_SIZE,
> +		.setkey		= ablk_set_key,
> +		.encrypt	= __ablk_encrypt,
> +		.decrypt	= ablk_decrypt,
> +	}
> +}, {
> +	.cra_name		= "ctr(aes)",
> +	.cra_driver_name	= "ctr-aes-neonbs",
> +	.cra_priority		= 300,
> +	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
> +	.cra_blocksize		= 1,
> +	.cra_ctxsize		= sizeof(struct async_helper_ctx),
> +	.cra_alignmask		= 7,
> +	.cra_type		= &crypto_ablkcipher_type,
> +	.cra_module		= THIS_MODULE,
> +	.cra_init		= ablk_init,
> +	.cra_exit		= ablk_exit,
> +	.cra_ablkcipher = {
> +		.min_keysize	= AES_MIN_KEY_SIZE,
> +		.max_keysize	= AES_MAX_KEY_SIZE,
> +		.ivsize		= AES_BLOCK_SIZE,
> +		.setkey		= ablk_set_key,
> +		.encrypt	= ablk_encrypt,
> +		.decrypt	= ablk_decrypt,
> +	}
> +}, {
> +	.cra_name		= "xts(aes)",
> +	.cra_driver_name	= "xts-aes-neonbs",
> +	.cra_priority		= 300,
> +	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
> +	.cra_blocksize		= AES_BLOCK_SIZE,
> +	.cra_ctxsize		= sizeof(struct async_helper_ctx),
> +	.cra_alignmask		= 7,
> +	.cra_type		= &crypto_ablkcipher_type,
> +	.cra_module		= THIS_MODULE,
> +	.cra_init		= ablk_init,
> +	.cra_exit		= ablk_exit,
> +	.cra_ablkcipher = {
> +		.min_keysize	= 2 * AES_MIN_KEY_SIZE,
> +		.max_keysize	= 2 * AES_MAX_KEY_SIZE,
> +		.ivsize		= AES_BLOCK_SIZE,
> +		.setkey		= ablk_set_key,
> +		.encrypt	= ablk_encrypt,
> +		.decrypt	= ablk_decrypt,
> +	}
> +} };
> +
> +static int __init aesbs_mod_init(void)
> +{
> +	if (!cpu_has_neon())
> +		return -ENODEV;
> +
> +	return crypto_register_algs(aesbs_algs, ARRAY_SIZE(aesbs_algs));
> +}
> +
> +static void __exit aesbs_mod_exit(void)
> +{
> +	crypto_unregister_algs(aesbs_algs, ARRAY_SIZE(aesbs_algs));
> +}
> +
> +module_init(aesbs_mod_init);
> +module_exit(aesbs_mod_exit);
> +
> +MODULE_DESCRIPTION("Bit sliced AES in CBC/CTR/XTS modes using NEON");
> +MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel at linaro.org>");
> +MODULE_LICENSE("GPL");
> diff --git a/crypto/Kconfig b/crypto/Kconfig
> index 8179ae6..4d6e656 100644
> --- a/crypto/Kconfig
> +++ b/crypto/Kconfig
> @@ -780,6 +780,22 @@ config CRYPTO_AES_ARM
>  
>  	  See <http://csrc.nist.gov/encryption/aes/> for more information.
>  
> +config CRYPTO_AES_ARM_BS
> +	tristate "Bit sliced AES using NEON instructions"
> +	depends on ARM && KERNEL_MODE_NEON
> +	select CRYPTO_ALGAPI
> +	select CRYPTO_AES_ARM
> +	select CRYPTO_ABLK_HELPER
> +	help
> +	  Use a faster and more secure NEON based implementation of AES in CBC,
> +	  CTR and XTS modes
> +
> +	  Bit sliced AES gives around 45% speedup on Cortex-A15 for CTR mode
> +	  and for XTS mode encryption, CBC and XTS mode decryption speedup is
> +	  around 25%. (CBC encryption speed is not affected by this driver.)
> +	  This implementation does not rely on any lookup tables so it is
> +	  believed to be invulnerable to cache timing attacks.
> +
>  config CRYPTO_ANUBIS
>  	tristate "Anubis cipher algorithm"
>  	select CRYPTO_ALGAPI
> -- 
> 1.8.1.2
> 



More information about the linux-arm-kernel mailing list