Experiments with AES-AltiVec
Subsystems (2)
cover Experiments with AES-AltiVec
I tried to use SIMD instructions for AES. This is stage 1 with AltiVec support, the next will be on SPUs. Unfortunately it is slower than the generic code on my ps3. It might be faster on some other machine. I'm interrested in hearing numbers from other people.
--
RFC 1/3 cryptoapi: AES with AltiVec support
That's the best I could do. I get
Average: 4728 msec, approx. 33840 kb/sec || 33 mb/sec on encryption
Average: 5364 msec, approx. 29828 kb/sec || 29 mb/sec on decryption
the generic module is faster:
Average: 3853 msec, approx. 41526 kb/sec || 40 mb/sec on encryption
Average: 3736 msec, approx. 42826 kb/sec || 41 mb/sec on decryption
AltiVec measurement was done with "kernel altivec patch" see next patch. Without it is slower:
Average: 7079 msec, approx. 22602 kb/sec || 22 mb/sec on encryption
Average: 10083 msec, approx. 15868 kb/sec || 15 mb/sec on decryption
It would be nice if someone could play around with different machines. This has been on a ps3.
crypto/aes-alti.c new file +136 -0
@@ -0,0 +1,136 @@ +/* +* based on crypto/aes.c +* +*/ + +#include <linux/module.h> +#include <linux/crypto.h> +#include <asm/byteorder.h> +#include <asm/system.h> + +#include "aes-altivec.h" + +#define AES_MIN_KEY_SIZE 16 +#define AES_MAX_KEY_SIZE 32 + +#define AES_BLOCK_SIZE 16 + +/* max rounds is 14. Every round needs 1 vector as key (=4 ints or 16 bytes) +* The first slot is the given key +*/ + +#define MAX_AES_ROUNDS 15 +#define MAX_AES_KEYSIZE_INT (MAX_AES_ROUNDS *4) +#define MAX_AES_KEYSIZE_BYTE (MAX_AES_KEYSIZE_INT *4) + +struct aes_ctx { +#ifdef KERN_EMU +unsigned char pad0; +unsigned char pad1; +unsigned char pad2; +unsigned char pad3; +#endif +unsigned char key_enc_ch[MAX_AES_KEYSIZE_BYTE ];// __attribute__ ((aligned (16))); +unsigned char key_dec_ch[MAX_AES_KEYSIZE_BYTE ];// __attribute__ ((aligned (16))); +unsigned int key_length; +}; + +static int aes_set_key (struct crypto_tfm *tfm,const u8 *in_key, +unsigned int key_len) +{ +struct aes_ctx *ctx =crypto_tfm_ctx (tfm); +u32 *flags = &tfm->crt_flags; +u32 i; + +switch (key_len) { +case 16 : +break ; + +case 24 : +break ; + +case 32 : +break ; + +default : + *flags |=CRYPTO_TFM_RES_BAD_KEY_LEN ; +return -EINVAL ; + } + +preempt_disable (); +enable_kernel_altivec (); + +printk ("ctx @ %p\n" , ctx); + ctx->key_length = key_len; + i =expand_key (in_key, key_len/4 , ctx->key_enc_ch, ctx->key_dec_ch); + +preempt_enable (); +return i; +} + +static void aes_encrypt (struct crypto_tfm *tfm,u8 *out,const u8 *in) +{ +const struct aes_ctx *ctx =crypto_tfm_ctx (tfm); + +preempt_disable (); +enable_kernel_altivec (); + +aes_encrypt_altivec (in, out, ctx->key_enc_ch, ctx->key_length); + +preempt_enable (); +} + +static void aes_decrypt (struct crypto_tfm *tfm,u8 *out,const u8 *in) +{ +const struct aes_ctx *ctx =crypto_tfm_ctx (tfm); + +preempt_disable (); +enable_kernel_altivec (); + +aes_decrypt_altivec (in, out, ctx->key_dec_ch, ctx->key_length); + +preempt_enable (); +} + + +static struct crypto_alg aes_alg = { + .cra_name ="aes" , + .cra_driver_name ="aes-altivec" , + .cra_priority =123 , + .cra_flags =CRYPTO_ALG_TYPE_CIPHER , + .cra_blocksize =AES_BLOCK_SIZE , + .cra_ctxsize =sizeof (struct aes_ctx ), + .cra_alignmask =15 , + .cra_module =THIS_MODULE , + .cra_list =LIST_HEAD_INIT (aes_alg.cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize =AES_MIN_KEY_SIZE , + .cia_max_keysize =AES_MAX_KEY_SIZE , + .cia_setkey = aes_set_key, + .cia_encrypt = aes_encrypt, + .cia_decrypt = aes_decrypt + } + } +}; + +static int __init aes_init (void ) +{ +if (!(cpu_has_feature (CPU_FTR_ALTIVEC ))) { +printk ("aes-alti: No altivec unit available\n" ); +return -ENODEV ; + } + +return crypto_register_alg (&aes_alg); +} + +static void __exit aes_fini(void) +{ +crypto_unregister_alg (&aes_alg); +} + +module_init (aes_init); +module_exit (aes_fini); + +MODULE_DESCRIPTION ("Rijndael (AES) Cipher Algorithm" ); +MODULE_LICENSE ("GPL" );
crypto/aes-altivec.c new file +706 -0
706 lines not on this page · raw message
crypto/aes-altivec.h new file +12 -0
@@ -0,0 +1,12 @@ +#ifndef __AES_ALTIVEC_H__ +#define __AES_ALTIVEC_H__ + +extern int expand_key (const unsigned char *key,unsigned int keylen, +unsigned char exp_enc_key[15 *4 *4 ],unsigned char expanded_dec_key[15 *4 *4 ]); + +extern int aes_encrypt_altivec (const unsigned char *in,unsigned char *out, +const unsigned char *kp,unsigned int key_len); + +extern int aes_decrypt_altivec (const unsigned char *in,unsigned char *out, +const unsigned char *kp,unsigned char key_len); +#endif
crypto/Kconfig +15 -0
@@ -325,6 +325,21 @@ config CRYPTO_AES_X86_64 See <http://csrc.nist.gov/encryption/aes/> for more information. +config CRYPTO_AES_ALTIVEC + tristate "AES with AltiVec support" + select CRYPTO_ALGAPI + depends on ALTIVEC + help + AES cipher algorithms (FIPS-197). AES uses the Rijndael + algorithm. This implementation has AltiVec support. + +config CRYPTO_AES_ALTIVEC_TABLE + bool "Use table lookup for decryption" + depends on CRYPTO_AES_ALTIVEC + help + Use precomputed tables for decryption instead of computing + "by hand" in GF. This solution is slower. + config CRYPTO_CAST5 tristate "CAST5 (CAST-128) cipher algorithm" select CRYPTO_ALGAPI
crypto/Makefile +4 -0
@@ -48,3 +48,7 @@ obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += mich obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o + +CFLAGS_aes-altivec.o += -O3 -maltivec -mcpu=cell +aes_altivec-objs := aes-alti.o aes-altivec.o +obj-$(CONFIG_CRYPTO_AES_ALTIVEC) += aes_altivec.o
--
Re: [RFC 1/3] cryptoapi: AES with AltiVec support
Just a few things I noticed in this version:
crypto/aes-altivec.c line 473
Quoted 8 lines · Sebastian Siewior
crypto/aes-altivec.c new file +8
-0+#ifdef CONFIG_CRYPTO_AES_ALTIVEC_TABLE + +/* 19 operations, 1x 8 memory loads */ + imm_04h =vec_splat_u8 (0x04 ); + imm_0fh =vec_splat_u8 (0x0f ); + + state_high =vec_sr (state, imm_04h); + state_low =vec_and (state, imm_0fh);
Why do you need to and with 0x0f here? I thought vec_perm simply ignored the high bits anyway.
Quoted 8 lines
crypto/aes-altivec.c new file +8
-0+ mul_08_hi =vec_perm (gf_mul_8_high, gf_mul_8_high, state_high); + mul_0a_hi =vec_perm (gf_mul_a_high, gf_mul_a_high, state_high); + mul_0c_hi =vec_perm (gf_mul_c_high, gf_mul_c_high, state_high); + mul_0e_hi =vec_perm (gf_mul_e_high, gf_mul_e_high, state_high); + + mul_08_lo =vec_perm (gf_mul_8_low, gf_mul_8_low, state_low); + mul_0a_lo =vec_perm (gf_mul_a_low, gf_mul_a_low, state_low); + mul_0c_lo =vec_perm (gf_mul_c_low, gf_mul_c_low, state_low);
crypto/aes-altivec.c line 492
Quoted 10 lines
crypto/aes-altivec.c new file +10
-0+ mul_0e_lo =vec_perm (gf_mul_e_low, gf_mul_e_low, state_low); + + mul_08 =vec_xor (mul_08_hi, mul_08_lo); + mul_0a =vec_xor (mul_0a_hi, mul_0a_lo); + mul_0c =vec_xor (mul_0c_hi, mul_0c_lo); + mul_0e =vec_xor (mul_0e_hi, mul_0e_lo); + + mul_09 =vec_xor (mul_08, state); + mul_0b =vec_xor (mul_0a, state); + mul_0d =vec_xor (mul_0c, state);
What are the last three xor used for? I'd think you can have the values for 0x9, 0xb and 0xd in the table directly.
crypto/aes-altivec.c line 581
Quoted 7 lines
crypto/aes-altivec.c new file +7
-0+int aes_decrypt_altivec (const unsigned char *in,unsigned char *out, +const unsigned char *kp,unsigned char key_len) +{ +unsigned char i; + vector unsigned char pstate; + const vector unsigned char *key; + unsigned char tmpbuf[16] __attribute__ ((aligned (16)));
My understanding is that gcc will not align the latter on the stack now does it warn about the fact that the attribute gets ignored. Have you checked that the variable is really put into a 16 byte aligned stack slot? Does it even make a difference?
Quoted 15 lines
crypto/aes-altivec.c new file +15
-0+memcpy (tmpbuf, in,sizeof (tmpbuf)); + pstate =vec_ld (0 , tmpbuf); + + key = (const vector unsigned char*) kp; + + pstate =vec_xor (pstate, *key++); + +switch (key_len) { +case 32 :/* 14 rounds */ + pstate =InvNormalRound (pstate, *key++); + pstate =InvNormalRound (pstate, *key++); + +case 24 :/* 12 rounds */ + pstate =InvNormalRound (pstate, *key++); + pstate =InvNormalRound (pstate, *key++);
crypto/aes-altivec.c line 607
Quoted 10 lines
crypto/aes-altivec.c new file +10
-0+ +case 16 :/* 10 rounds */ +for (i=0 ; i<9 ; i++) + pstate =InvNormalRound (pstate, *key++); + +break ; + +default : +BUG (); + }
Did this manual partial unrolling actually make a difference compared this?
for (i=0; i<(5 + key_len / 8); i++) pstate = InvNormalRound(pstate, *key++);
If they are the same speed, there should probably be no unrolling, because the larger object code will be bad for the instruction cache.
crypto/Makefile obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += mich · line 52
Quoted 9 lines
===================================================================
crypto/Makefile +2
-0@@ -48,3 +48,7 @@ obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += mich obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o + +CFLAGS_aes-altivec.o += -O3 -maltivec -mcpu=cell
mcpu=cell probably breaks on most compilers. This needs some experiments, but most systems should either leave this out or specify the cpu they are actually compiling for.
Some time ago, I did a patch to extend the CPU selection in Kconfig so you can choose sensible mcpu= and mtune= flags semi-automatically.
Arnd <><
Re: [RFC 1/3] cryptoapi: AES with AltiVec support
Quoted 10 lines · Arnd Bergmann
Just a few things I noticed in this version:
crypto/aes-altivec.c line 473
Quoted 5 lines
crypto/aes-altivec.c new file +5
-0+ imm_04h =vec_splat_u8 (0x04 ); + imm_0fh =vec_splat_u8 (0x0f ); + + state_high =vec_sr (state, imm_04h); + state_low =vec_and (state, imm_0fh);Why do you need to and with
0x0fhere? I thoughtvec_permsimply ignored the high bits anyway.
Yes it does, my bad
Quoted 6 lines
crypto/aes-altivec.c line 492
Quoted 3 lines
crypto/aes-altivec.c new file +3
-0+ mul_09 =vec_xor (mul_08, state); + mul_0b =vec_xor (mul_0a, state); + mul_0d =vec_xor (mul_0c, state);What are the last three xor used for? I'd think you can have the values for
0x9,0xband0xdin the table directly.
Yes. With recomputing table the performance seems to be unchanged.
Quoted 4 lines
Quoted 4 lines
crypto/aes-altivec.c new file +4
-0+int aes_decrypt_altivec (const unsigned char *in,unsigned char *out, +const unsigned char *kp,unsigned char key_len) +{ +unsigned char i;
Quoted 8 lines
crypto/aes-altivec.c line 368
Quoted 3 lines
crypto/aes-altivec.c new file +3
-0+ vector unsigned char pstate; + const vector unsigned char *key; + unsigned char tmpbuf[16] __attribute__ ((aligned (16)));My understanding is that gcc will not align the latter on the stack now does it warn about the fact that the attribute gets ignored. Have you checked that the variable is really put into a 16 byte aligned stack slot? Does it even make a difference?
Quote from the PPC64 ABI [1]:
r1: The stack pointer (stored in r1) shall maintain quadword alignment. It shall always point to the lowest allocated valid stack frame, and grow toward low addresses. The contents of the word at that address always point to the previously allocated stack frame.
...
PPC32 ABI[2] page 32 contains the same sentence about r1. The compiler does not behave correctly on >16 byte alignment and should warn you.
Quoted 22 lines
Quoted 8 lines
crypto/aes-altivec.c new file +8
-0+switch (key_len) { +case 32 :/* 14 rounds */ + pstate =InvNormalRound (pstate, *key++); + pstate =InvNormalRound (pstate, *key++); + +case 24 :/* 12 rounds */ + pstate =InvNormalRound (pstate, *key++); + pstate =InvNormalRound (pstate, *key++);crypto/aes-altivec.c line 607
Quoted 10 lines
crypto/aes-altivec.c new file +10
-0+ +case 16 :/* 10 rounds */ +for (i=0 ; i<9 ; i++) + pstate =InvNormalRound (pstate, *key++); + +break ; + +default : +BUG (); + }Did this manual partial unrolling actually make a difference compared this?
Quoted 2 lines
for (i=0; i<(5 + key_len / 8); i++) pstate = InvNormalRound(pstate, *key++);
The numbers for encryption change from 33mb/sec to 23mb/sec and for decryption from 29mb/sec to 26mb/sec. The table decryption, however, improves from 19mb/sec to 23mb/sec.
Quoted 3 lines
If they are the same speed, there should probably be no unrolling, because the larger object code will be bad for the instruction cache.
I don't force him to unroll the code, there is no inline keyword there. ppu-gcc from SDK 2.1 unrolls the code, gentoo's gcc 4.1.2 doesn't.
Quoted 9 lines
Quoted 1 line
+CFLAGS_aes-altivec.o += -O3 -maltivec -mcpu=cell
mcpu=cell probably breaks on most compilers. This needs some experiments, but most systems should either leave this out or specify the cpu they are actually compiling for.
Some time ago, I did a patch to extend the CPU selection in
Kconfigso you can choose sensible mcpu= and mtune= flags semi-automatically.
I have no cpu selection in my current Kconfig. Will take a look on that patch
Quoted 2 lines
Arnd <><
Sebastian
[1] ftp://ftp.linuxppc64.org/pub/people/sjmunroe/PPC64-VMXabi.txt [2]http://www.cloudcaptech.com/MPC555%20Resources/Programming%20Environment/SVR4abippc.pdf
Re: [RFC 1/3] cryptoapi: AES with AltiVec support
In reply to Sebastian Siewiorcrypto/Makefile obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += mich · line 54
Quoted 11 lines
==================================================================
crypto/Makefile +4
-0@@ -48,3 +48,7 @@ obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += mich obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o + +CFLAGS_aes-altivec.o += -O3 -maltivec -mcpu=cell +aes_altivec-objs := aes-alti.o aes-altivec.o +obj-$(CONFIG_CRYPTO_AES_ALTIVEC) += aes_altivec.o
Ideally (and I know the RAID6 code isnt doing it), the
code that contains enable_kernel_altivec/disable_kernel_altivec should -not- itself be compiled with -malitvec. You don't want the compiler to "inadvertently" generate altivec instructions outside of those calls (in the function prolog for example).
I noticed quite a bit of memcpy's around too... see if you can limit usage of these.
Ben.
Re: [RFC 1/3] cryptoapi: AES with AltiVec support
Quoted 6 lines · Benjamin Herrenschmidt
Quoted 6 lines
==================================================================
crypto/Makefile +0
-0@@ -48,3 +48,7 @@ obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += mich obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
Quoted 11 lines
crypto/Makefile obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += mich · line 54
Quoted 5 lines
crypto/Makefile +4
-0obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o + +CFLAGS_aes-altivec.o += -O3 -maltivec -mcpu=cell +aes_altivec-objs := aes-alti.o aes-altivec.o +obj-$(CONFIG_CRYPTO_AES_ALTIVEC) += aes_altivec.oIdeally (and I know the RAID6 code isnt doing it), the
code that contains enable_kernel_altivec/disable_kernel_altivec should -not- itself be compiled with -malitvec. You don't want the compiler to "inadvertently" generate altivec instructions outside of those calls (in the function prolog for example).
Yes. aes-altivec.o contains the -maltivec flag and is the only module using AltiVec. aes-alti.o uses enable_kernel_altivec & disable_kernel_altivec and calls then the AltiVec module. The raid6 code compiles the raid[1,2,4,8].c files with -maltivec flag and uses the noinline keyword in the function that uses AltiVec.
Should I prefer the latter or were you confused with with the - _ in the filename and you recommend renaming them?
Quoted 2 lines
I noticed quite a bit of memcpy's around too... see if you can limit usage of these.
I check if I can be be sure that the data is always properly aligned
Quoted 3 lines
Ben.
Sebastian
Re: [RFC 1/3] cryptoapi: AES with AltiVec support
Quoted 9 lines
Yes. aes-altivec.o contains the -maltivec flag and is the only module using AltiVec. aes-alti.o uses
enable_kernel_altivec&disable_kernel_altivecand calls then the AltiVec module. The raid6 code compiles the raid[1,2,4,8].c files with -maltivec flag and uses the noinline keyword in the function that uses AltiVec. Should I prefer the latter or were you confused with with the - _ in the filename and you recommend renaming them?
Nah, your stuff looks fine, I got confused.
Ben.
RFC 2/3 PowerPC: lazy altivec enabling in kernel
In reply to Sebastian SiewiorThis works right only for 64bit kernel and will break any 32bit kernel. Switching on altivec takes some time due to the MSR access. The speed-up is about 50% in my aes-code. It might be usefull for the raid module as well.
arch/powerpc/kernel/head_64.S +7 -0
@@ -1229,6 +1229,13 @@ altivec_unavailable_common: #ifdef CONFIG_ALTIVEC BEGIN_FTR_SECTION bne .load_up_altivec /* if from user, just load it up */ + /* + * the kernel is going to use AltiVec. + * hopefully enable_kernel_altivec() has been called + */ + bl .altivec_enable_for_kernel_exception + b .ret_from_except + END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) #endif bl .save_nvgprs
arch/powerpc/kernel/misc_64.S +10 -0
@@ -493,6 +493,8 @@ _GLOBAL(giveup_altivec) mfmsr r5 oris r5,r5,MSR_VEC@h mtmsrd r5 /* enable use of VMX now */ + +giveup_user_altivec_save_vmx: isync cmpdi 0,r3,0 beqlr- /* if no previous owner, done */
@@ -516,6 +518,14 @@ _GLOBAL(giveup_altivec) #endif /* CONFIG_SMP */ blr +/* + * giveup_user_altivec(tsk) + * Same as giveup_altivec() but lets the exception handler + * enable AltiVec + */ +_GLOBAL(giveup_user_altivec) + b save_vmx + #endif /* CONFIG_ALTIVEC */ _GLOBAL(kernel_execve)
arch/powerpc/kernel/process.c +11 -5
@@ -119,15 +119,21 @@ int dump_task_fpu(struct task_struct *ts#ifdef CONFIG_ALTIVEC void enable_kernel_altivec (void ) { -WARN_ON (preemptible ()); +BUG_ON (preemptible ()); +/* +* enable_kernel_altivec() will just save current AltiVec registers (if needed) and +* return to caller (with MSR_VEC unchanged (probably not set)). The first AltiVec +* instruction will raise an exception and the exception will enable the AltiVec for +* the kernel. This is done to avoid the expensive "enable altivec" operation if it +* is allready enabled. However, you have to disable preemtion while you are using +* AltiVec. +*/ #ifdef CONFIG_SMP if (current->thread.regs && (current->thread.regs->msr &MSR_VEC )) -giveup_altivec (current); -else -giveup_altivec (NULL );/* just enable AltiVec for kernel - force */ +giveup_user_altivec (current);#else -giveup_altivec (last_task_used_altivec); +giveup_user_altivec (last_task_used_altivec);#endif /* CONFIG_SMP */ }EXPORT_SYMBOL (enable_kernel_altivec);
arch/powerpc/kernel/traps.c +6 -0
@@ -886,6 +886,12 @@ void altivec_unavailable_exception(strucdie ("Unrecoverable VMX/Altivec Unavailable Exception" , regs,SIGABRT ); } +void altivec_enable_for_kernel_exception (struct pt_regs *regs) +{ +printk ("altivec_enable_for_kernel_exception: AltiVec mode on for kernel\n" ); + regs->msr |=MSR_VEC ; +} +void performance_monitor_exception (struct pt_regs *regs) {perf_irq (regs);
include/asm-powerpc/system.h +1 -0
@@ -129,6 +129,7 @@ extern void enable_kernel_fp(void);extern void flush_fp_to_thread (struct task_struct *);extern void enable_kernel_altivec (void );extern void giveup_altivec (struct task_struct *); +extern void giveup_user_altivec (struct task_struct *);extern void load_up_altivec (struct task_struct *);extern int emulate_altivec (struct pt_regs *);extern void giveup_spe (struct task_struct *);
--
RFC 3/3 cryptoapi: speed test
In reply to Sebastian SiewiorThis has been used for performance testing in my aes altivec code.
crypto/limi-speed.c new file +138 -0
@@ -0,0 +1,138 @@ +/* +* Code derived von crypt/tcrypt.h +* +* Small speed test with time resolution in msec. +* Author: Sebastian Siewior (bigeasy _at_ breakpoint.cc) +* License: GPL v2 +*/ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/scatterlist.h> +#include <linux/crypto.h> +#include <linux/jiffies.h> +#include <linux/types.h> + +static char *in; + +static unsigned int buff_size =16 *1024 ; +module_param (buff_size, uint,0444 ); +MODULE_PARM_DESC (buff_size,"Buffer allocated by kmalloc()" ); + +static unsigned int keylen =16 ; +module_param (keylen, uint,0444 ); +MODULE_PARM_DESC (keylen,"Length of the key (16,24 or 32 bits" ); + +static unsigned int mode =0 ; +module_param (mode, uint,0444 ); +MODULE_PARM_DESC (mode,"0 -> encryption else decryption" ); + +static unsigned int big_loops =10 ; +module_param (big_loops, uint,0444 ); +MODULE_PARM_DESC (big_loops,"Number of mensurations." ); + +static unsigned int small_loops =10000 ; +module_param (small_loops, uint,0444 ); +MODULE_PARM_DESC (small_loops,"loops within one mesurement." ); + + +static int __init init (void ) +{ +struct scatterlist sg[1 ]; +struct crypto_blkcipher *tfm; +struct blkcipher_desc desc; +unsigned int i; +unsigned int ret; +unsigned int iv_len; +unsigned long start, end; +unsigned long total =0 ; +unsigned long size_kb; +unsigned char key[32 ] = {1 ,2 ,3 ,4 ,5 ,6 }; + +printk ("Limi-speed: buff_size: %u, keylen: %d, mode: %s\n" , buff_size, keylen, mode ?"decryption" :"encryption" ); +printk ("loops: %d, iterations: %d, " , big_loops, small_loops); + size_kb = small_loops * buff_size /1024 ; +printk ("=> %lu kb or %lu mb a loop\n" , size_kb, size_kb/1024 ); + +if (keylen !=16 && keylen !=24 && keylen !=32 ) { +printk ("Invalid keysize\n" ); +return -EINVAL ; + } + + in =kmalloc (buff_size,GFP_KERNEL ); +if (in ==NULL ) { +printk ("Failed to allocate memory.\n" ); +return -ENOMEM ; + } + +memset (in,0x24 , buff_size); + +sg_set_buf (sg, in, buff_size); + + tfm =crypto_alloc_blkcipher ("cbc(aes)" ,0 ,CRYPTO_ALG_ASYNC ); + +if (IS_ERR (tfm)) { +printk ("failed to load transform for cbc(aes): %ld\n" ,PTR_ERR (tfm)); + goto leave; + } + +crypto_blkcipher_setkey (tfm, key, keylen); + + iv_len =crypto_blkcipher_ivsize (tfm); +if (iv_len) +crypto_blkcipher_set_iv (tfm, in, iv_len); + + desc.tfm = tfm; + desc.flags =0 ; + +preempt_disable (); +enable_kernel_altivec (); + +for (i=0 ; i<big_loops; i++) { +int j; + start = jiffies; + ret =0 ; + +for (j=0 ; j < small_loops && !ret; j++) { + +if (!mode) + ret =crypto_blkcipher_encrypt (&desc, sg, sg, buff_size); +else + ret =crypto_blkcipher_decrypt (&desc, sg, sg, buff_size); + } + +if (ret) { +printk ("encryption failed: %d after (i,j) (%u,%u) iterations\n" , ret, i, j); + goto leave_loop; + } + end = jiffies; +if ( !time_after (start, end)) { +printk ("Run: %u msec\n" ,jiffies_to_msecs (end - start)); + total +=jiffies_to_msecs (end - start); + }else { +printk ("Run: %u msec\n" ,jiffies_to_msecs (start - end)); + total +=jiffies_to_msecs (start - end); + } + } + + total /= big_loops; + size_kb *=1000 ; + size_kb /= total; +printk ("Average: %lu msec, approx. %lu kb/sec || %lu mb/sec \n" , total, + size_kb, size_kb/1024 ); + +leave_loop: +preempt_enable (); +crypto_free_blkcipher (tfm); + +leave: +kfree (in); +return -ENODEV ; +} + +static void __exit fini(void) { } + +module_init (init); +module_exit (fini); + +MODULE_LICENSE ("GPL" );
crypto/Kconfig +6 -0
@@ -462,6 +462,12 @@ config CRYPTO_TEST help Quick & dirty crypto test module. +config CRYPTO_LIMI_SPEED + tristate "Crypto algorithm speed test with msec resolution" + help + insmod/modprobe the module, and watch dmesg for results. + Test is for aes only. + source "drivers/crypto/Kconfig" endif # if CRYPTO
crypto/Makefile +1 -0
@@ -52,3 +52,4 @@ obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o CFLAGS_aes-altivec.o += -O3 -maltivec -mcpu=cell aes_altivec-objs := aes-alti.o aes-altivec.o obj-$(CONFIG_CRYPTO_AES_ALTIVEC) += aes_altivec.o +obj-$(CONFIG_CRYPTO_LIMI_SPEED) += limi-speed.o
--