2011-08-04 20:19:25 +02:00
/*
* Cryptographic API .
*
* Glue code for the SHA1 Secure Hash Algorithm assembler implementation using
* Supplemental SSE3 instructions .
*
* This file is based on sha1_generic . c
*
* Copyright ( c ) Alan Smithee .
* Copyright ( c ) Andrew McDonald < andrew @ mcdonald . org . uk >
* Copyright ( c ) Jean - Francois Dive < jef @ linuxbe . org >
* Copyright ( c ) Mathias Krause < minipli @ googlemail . com >
2014-03-20 15:14:00 -07:00
* Copyright ( c ) Chandramouli Narayanan < mouli @ linux . intel . com >
2011-08-04 20:19:25 +02:00
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation ; either version 2 of the License , or ( at your option )
* any later version .
*
*/
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
# include <crypto/internal/hash.h>
# include <linux/init.h>
# include <linux/module.h>
# include <linux/mm.h>
# include <linux/cryptohash.h>
# include <linux/types.h>
# include <crypto/sha.h>
2015-04-09 12:55:46 +02:00
# include <crypto/sha1_base.h>
2015-04-24 02:46:00 +02:00
# include <asm/fpu/api.h>
2011-08-04 20:19:25 +02:00
asmlinkage void sha1_transform_ssse3 ( u32 * digest , const char * data ,
unsigned int rounds ) ;
2012-05-24 11:13:42 +02:00
# ifdef CONFIG_AS_AVX
2011-08-04 20:19:25 +02:00
asmlinkage void sha1_transform_avx ( u32 * digest , const char * data ,
unsigned int rounds ) ;
# endif
2014-03-20 15:14:00 -07:00
# ifdef CONFIG_AS_AVX2
# define SHA1_AVX2_BLOCK_OPTSIZE 4 /* optimal 4*64 bytes of SHA1 blocks */
asmlinkage void sha1_transform_avx2 ( u32 * digest , const char * data ,
2015-04-09 12:55:46 +02:00
unsigned int rounds ) ;
2014-03-20 15:14:00 -07:00
# endif
2011-08-04 20:19:25 +02:00
2015-04-09 12:55:46 +02:00
static void ( * sha1_transform_asm ) ( u32 * , const char * , unsigned int ) ;
2011-08-04 20:19:25 +02:00
static int sha1_ssse3_update ( struct shash_desc * desc , const u8 * data ,
unsigned int len )
{
struct sha1_state * sctx = shash_desc_ctx ( desc ) ;
2015-04-09 12:55:46 +02:00
if ( ! irq_fpu_usable ( ) | |
( sctx - > count % SHA1_BLOCK_SIZE ) + len < SHA1_BLOCK_SIZE )
return crypto_sha1_update ( desc , data , len ) ;
2011-08-04 20:19:25 +02:00
2015-04-09 12:55:46 +02:00
/* make sure casting to sha1_block_fn() is safe */
BUILD_BUG_ON ( offsetof ( struct sha1_state , state ) ! = 0 ) ;
2011-08-04 20:19:25 +02:00
2015-04-09 12:55:46 +02:00
kernel_fpu_begin ( ) ;
sha1_base_do_update ( desc , data , len ,
( sha1_block_fn * ) sha1_transform_asm ) ;
kernel_fpu_end ( ) ;
2011-08-04 20:19:25 +02:00
return 0 ;
}
2015-04-09 12:55:46 +02:00
static int sha1_ssse3_finup ( struct shash_desc * desc , const u8 * data ,
unsigned int len , u8 * out )
2011-08-04 20:19:25 +02:00
{
2015-04-09 12:55:46 +02:00
if ( ! irq_fpu_usable ( ) )
return crypto_sha1_finup ( desc , data , len , out ) ;
2011-08-04 20:19:25 +02:00
2015-04-09 12:55:46 +02:00
kernel_fpu_begin ( ) ;
if ( len )
sha1_base_do_update ( desc , data , len ,
( sha1_block_fn * ) sha1_transform_asm ) ;
sha1_base_do_finalize ( desc , ( sha1_block_fn * ) sha1_transform_asm ) ;
kernel_fpu_end ( ) ;
2011-08-04 20:19:25 +02:00
2015-04-09 12:55:46 +02:00
return sha1_base_finish ( desc , out ) ;
2011-08-04 20:19:25 +02:00
}
2015-04-09 12:55:46 +02:00
/* Add padding and return the message digest. */
static int sha1_ssse3_final ( struct shash_desc * desc , u8 * out )
2011-08-04 20:19:25 +02:00
{
2015-04-09 12:55:46 +02:00
return sha1_ssse3_finup ( desc , NULL , 0 , out ) ;
2011-08-04 20:19:25 +02:00
}
2014-03-20 15:14:00 -07:00
# ifdef CONFIG_AS_AVX2
static void sha1_apply_transform_avx2 ( u32 * digest , const char * data ,
unsigned int rounds )
{
/* Select the optimal transform based on data block size */
if ( rounds > = SHA1_AVX2_BLOCK_OPTSIZE )
sha1_transform_avx2 ( digest , data , rounds ) ;
else
sha1_transform_avx ( digest , data , rounds ) ;
}
# endif
2011-08-04 20:19:25 +02:00
static struct shash_alg alg = {
. digestsize = SHA1_DIGEST_SIZE ,
2015-04-09 12:55:46 +02:00
. init = sha1_base_init ,
2011-08-04 20:19:25 +02:00
. update = sha1_ssse3_update ,
. final = sha1_ssse3_final ,
2015-04-09 12:55:46 +02:00
. finup = sha1_ssse3_finup ,
2011-08-04 20:19:25 +02:00
. descsize = sizeof ( struct sha1_state ) ,
. base = {
. cra_name = " sha1 " ,
. cra_driver_name = " sha1-ssse3 " ,
. cra_priority = 150 ,
. cra_flags = CRYPTO_ALG_TYPE_SHASH ,
. cra_blocksize = SHA1_BLOCK_SIZE ,
. cra_module = THIS_MODULE ,
}
} ;
2012-05-24 11:13:42 +02:00
# ifdef CONFIG_AS_AVX
2011-08-04 20:19:25 +02:00
static bool __init avx_usable ( void )
{
2015-04-28 10:11:24 +02:00
if ( ! cpu_has_xfeatures ( XSTATE_SSE | XSTATE_YMM , NULL ) ) {
if ( cpu_has_avx )
pr_info ( " AVX detected but unusable. \n " ) ;
2011-08-04 20:19:25 +02:00
return false ;
}
return true ;
}
2014-03-24 17:10:37 +01:00
# ifdef CONFIG_AS_AVX2
static bool __init avx2_usable ( void )
{
if ( avx_usable ( ) & & cpu_has_avx2 & & boot_cpu_has ( X86_FEATURE_BMI1 ) & &
boot_cpu_has ( X86_FEATURE_BMI2 ) )
return true ;
return false ;
}
# endif
2011-08-04 20:19:25 +02:00
# endif
static int __init sha1_ssse3_mod_init ( void )
{
2014-03-20 15:14:00 -07:00
char * algo_name ;
2014-03-24 17:10:37 +01:00
2011-08-04 20:19:25 +02:00
/* test for SSSE3 first */
2014-03-20 15:14:00 -07:00
if ( cpu_has_ssse3 ) {
2011-08-04 20:19:25 +02:00
sha1_transform_asm = sha1_transform_ssse3 ;
2014-03-20 15:14:00 -07:00
algo_name = " SSSE3 " ;
}
2011-08-04 20:19:25 +02:00
2012-05-24 11:13:42 +02:00
# ifdef CONFIG_AS_AVX
2011-08-04 20:19:25 +02:00
/* allow AVX to override SSSE3, it's a little faster */
2014-03-20 15:14:00 -07:00
if ( avx_usable ( ) ) {
2014-03-24 17:10:37 +01:00
sha1_transform_asm = sha1_transform_avx ;
algo_name = " AVX " ;
2014-03-20 15:14:00 -07:00
# ifdef CONFIG_AS_AVX2
2014-03-24 17:10:37 +01:00
/* allow AVX2 to override AVX, it's a little faster */
if ( avx2_usable ( ) ) {
2014-03-20 15:14:00 -07:00
sha1_transform_asm = sha1_apply_transform_avx2 ;
algo_name = " AVX2 " ;
}
# endif
}
2011-08-04 20:19:25 +02:00
# endif
if ( sha1_transform_asm ) {
2014-03-20 15:14:00 -07:00
pr_info ( " Using %s optimized SHA-1 implementation \n " , algo_name ) ;
2011-08-04 20:19:25 +02:00
return crypto_register_shash ( & alg ) ;
}
2014-03-20 15:14:00 -07:00
pr_info ( " Neither AVX nor AVX2 nor SSSE3 is available/usable. \n " ) ;
2011-08-04 20:19:25 +02:00
return - ENODEV ;
}
static void __exit sha1_ssse3_mod_fini ( void )
{
crypto_unregister_shash ( & alg ) ;
}
module_init ( sha1_ssse3_mod_init ) ;
module_exit ( sha1_ssse3_mod_fini ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " SHA1 Secure Hash Algorithm, Supplemental SSE3 accelerated " ) ;
2014-11-20 17:05:53 -08:00
MODULE_ALIAS_CRYPTO ( " sha1 " ) ;