2013-03-26 14:00:02 -07:00
/*
* Cryptographic API .
*
* Glue code for the SHA512 Secure Hash Algorithm assembler
* implementation using supplemental SSE3 / AVX / AVX2 instructions .
*
* This file is based on sha512_generic . c
*
* Copyright ( C ) 2013 Intel Corporation
* Author : Tim Chen < tim . c . chen @ linux . intel . com >
*
* 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 .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND ,
* EXPRESS OR IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY , FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT . IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER IN AN
* ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE .
*
*/
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
# include <crypto/internal/hash.h>
2019-03-12 22:12:48 -07:00
# include <crypto/internal/simd.h>
2013-03-26 14:00:02 -07:00
# include <linux/init.h>
# include <linux/module.h>
# include <linux/mm.h>
2019-03-12 22:12:48 -07:00
# include <linux/string.h>
2013-03-26 14:00:02 -07:00
# include <linux/types.h>
2020-11-12 21:20:21 -08:00
# include <crypto/sha2.h>
2015-04-09 12:55:48 +02:00
# include <crypto/sha512_base.h>
2019-03-12 22:12:48 -07:00
# include <asm/simd.h>
2013-03-26 14:00:02 -07:00
2020-01-14 19:57:29 -08:00
asmlinkage void sha512_transform_ssse3 ( struct sha512_state * state ,
const u8 * data , int blocks ) ;
2013-03-26 14:00:02 -07:00
2015-09-16 16:35:53 -07:00
static int sha512_update ( struct shash_desc * desc , const u8 * data ,
2020-01-14 19:57:29 -08:00
unsigned int len , sha512_block_fn * sha512_xform )
2013-03-26 14:00:02 -07:00
{
struct sha512_state * sctx = shash_desc_ctx ( desc ) ;
2019-03-12 22:12:48 -07:00
if ( ! crypto_simd_usable ( ) | |
2015-04-09 12:55:48 +02:00
( sctx - > count [ 0 ] % SHA512_BLOCK_SIZE ) + len < SHA512_BLOCK_SIZE )
return crypto_sha512_update ( desc , data , len ) ;
2013-03-26 14:00:02 -07:00
2020-01-14 19:57:29 -08:00
/*
* Make sure struct sha512_state begins directly with the SHA512
* 512 - bit internal state , as this is what the asm functions expect .
*/
2015-04-09 12:55:48 +02:00
BUILD_BUG_ON ( offsetof ( struct sha512_state , state ) ! = 0 ) ;
2013-03-26 14:00:02 -07:00
2015-04-09 12:55:48 +02:00
kernel_fpu_begin ( ) ;
2020-01-14 19:57:29 -08:00
sha512_base_do_update ( desc , data , len , sha512_xform ) ;
2015-04-09 12:55:48 +02:00
kernel_fpu_end ( ) ;
2013-03-26 14:00:02 -07:00
return 0 ;
}
2015-09-16 16:35:53 -07:00
static int sha512_finup ( struct shash_desc * desc , const u8 * data ,
2020-01-14 19:57:29 -08:00
unsigned int len , u8 * out , sha512_block_fn * sha512_xform )
2013-03-26 14:00:02 -07:00
{
2019-03-12 22:12:48 -07:00
if ( ! crypto_simd_usable ( ) )
2015-04-09 12:55:48 +02:00
return crypto_sha512_finup ( desc , data , len , out ) ;
2013-03-26 14:00:02 -07:00
2015-04-09 12:55:48 +02:00
kernel_fpu_begin ( ) ;
if ( len )
2020-01-14 19:57:29 -08:00
sha512_base_do_update ( desc , data , len , sha512_xform ) ;
sha512_base_do_finalize ( desc , sha512_xform ) ;
2015-04-09 12:55:48 +02:00
kernel_fpu_end ( ) ;
2013-03-26 14:00:02 -07:00
2015-04-09 12:55:48 +02:00
return sha512_base_finish ( desc , out ) ;
2013-03-26 14:00:02 -07:00
}
2015-09-16 16:35:53 -07:00
static int sha512_ssse3_update ( struct shash_desc * desc , const u8 * data ,
unsigned int len )
{
return sha512_update ( desc , data , len , sha512_transform_ssse3 ) ;
}
static int sha512_ssse3_finup ( struct shash_desc * desc , const u8 * data ,
unsigned int len , u8 * out )
{
return sha512_finup ( desc , data , len , out , sha512_transform_ssse3 ) ;
}
2013-03-26 14:00:02 -07:00
/* Add padding and return the message digest. */
static int sha512_ssse3_final ( struct shash_desc * desc , u8 * out )
{
2015-04-09 12:55:48 +02:00
return sha512_ssse3_finup ( desc , NULL , 0 , out ) ;
2013-05-21 17:10:44 +03:00
}
2015-09-16 16:35:53 -07:00
static struct shash_alg sha512_ssse3_algs [ ] = { {
2013-03-26 14:00:02 -07:00
. digestsize = SHA512_DIGEST_SIZE ,
2015-04-09 12:55:48 +02:00
. init = sha512_base_init ,
2013-03-26 14:00:02 -07:00
. update = sha512_ssse3_update ,
. final = sha512_ssse3_final ,
2015-04-09 12:55:48 +02:00
. finup = sha512_ssse3_finup ,
2013-03-26 14:00:02 -07:00
. descsize = sizeof ( struct sha512_state ) ,
. base = {
. cra_name = " sha512 " ,
. cra_driver_name = " sha512-ssse3 " ,
. cra_priority = 150 ,
. cra_blocksize = SHA512_BLOCK_SIZE ,
. cra_module = THIS_MODULE ,
}
2013-05-21 17:10:44 +03:00
} , {
. digestsize = SHA384_DIGEST_SIZE ,
2015-04-09 12:55:48 +02:00
. init = sha384_base_init ,
2013-05-21 17:10:44 +03:00
. update = sha512_ssse3_update ,
2015-04-09 12:55:48 +02:00
. final = sha512_ssse3_final ,
. finup = sha512_ssse3_finup ,
2013-05-21 17:10:44 +03:00
. descsize = sizeof ( struct sha512_state ) ,
. base = {
. cra_name = " sha384 " ,
. cra_driver_name = " sha384-ssse3 " ,
. cra_priority = 150 ,
. cra_blocksize = SHA384_BLOCK_SIZE ,
. cra_module = THIS_MODULE ,
}
} } ;
2013-03-26 14:00:02 -07:00
2015-09-16 16:35:53 -07:00
static int register_sha512_ssse3 ( void )
{
if ( boot_cpu_has ( X86_FEATURE_SSSE3 ) )
return crypto_register_shashes ( sha512_ssse3_algs ,
ARRAY_SIZE ( sha512_ssse3_algs ) ) ;
return 0 ;
}
static void unregister_sha512_ssse3 ( void )
{
if ( boot_cpu_has ( X86_FEATURE_SSSE3 ) )
crypto_unregister_shashes ( sha512_ssse3_algs ,
ARRAY_SIZE ( sha512_ssse3_algs ) ) ;
}
2020-01-14 19:57:29 -08:00
asmlinkage void sha512_transform_avx ( struct sha512_state * state ,
const u8 * data , int blocks ) ;
2015-09-16 16:35:53 -07:00
static bool avx_usable ( void )
2013-03-26 14:00:02 -07:00
{
2015-09-02 16:31:26 -07:00
if ( ! cpu_has_xfeatures ( XFEATURE_MASK_SSE | XFEATURE_MASK_YMM , NULL ) ) {
2016-04-04 22:24:56 +02:00
if ( boot_cpu_has ( X86_FEATURE_AVX ) )
2015-04-28 10:11:24 +02:00
pr_info ( " AVX detected but unusable. \n " ) ;
2013-03-26 14:00:02 -07:00
return false ;
}
return true ;
}
2015-09-16 16:35:53 -07:00
static int sha512_avx_update ( struct shash_desc * desc , const u8 * data ,
unsigned int len )
2013-03-26 14:00:02 -07:00
{
2015-09-16 16:35:53 -07:00
return sha512_update ( desc , data , len , sha512_transform_avx ) ;
}
2013-03-26 14:00:02 -07:00
2015-09-16 16:35:53 -07:00
static int sha512_avx_finup ( struct shash_desc * desc , const u8 * data ,
unsigned int len , u8 * out )
{
return sha512_finup ( desc , data , len , out , sha512_transform_avx ) ;
}
/* Add padding and return the message digest. */
static int sha512_avx_final ( struct shash_desc * desc , u8 * out )
{
return sha512_avx_finup ( desc , NULL , 0 , out ) ;
}
static struct shash_alg sha512_avx_algs [ ] = { {
. digestsize = SHA512_DIGEST_SIZE ,
. init = sha512_base_init ,
. update = sha512_avx_update ,
. final = sha512_avx_final ,
. finup = sha512_avx_finup ,
. descsize = sizeof ( struct sha512_state ) ,
. base = {
. cra_name = " sha512 " ,
. cra_driver_name = " sha512-avx " ,
. cra_priority = 160 ,
. cra_blocksize = SHA512_BLOCK_SIZE ,
. cra_module = THIS_MODULE ,
2013-03-26 14:00:02 -07:00
}
2015-09-16 16:35:53 -07:00
} , {
. digestsize = SHA384_DIGEST_SIZE ,
. init = sha384_base_init ,
. update = sha512_avx_update ,
. final = sha512_avx_final ,
. finup = sha512_avx_finup ,
. descsize = sizeof ( struct sha512_state ) ,
. base = {
. cra_name = " sha384 " ,
. cra_driver_name = " sha384-avx " ,
. cra_priority = 160 ,
. cra_blocksize = SHA384_BLOCK_SIZE ,
. cra_module = THIS_MODULE ,
}
} } ;
2013-03-26 14:00:02 -07:00
2015-09-16 16:35:53 -07:00
static int register_sha512_avx ( void )
{
if ( avx_usable ( ) )
return crypto_register_shashes ( sha512_avx_algs ,
ARRAY_SIZE ( sha512_avx_algs ) ) ;
return 0 ;
}
static void unregister_sha512_avx ( void )
{
if ( avx_usable ( ) )
crypto_unregister_shashes ( sha512_avx_algs ,
ARRAY_SIZE ( sha512_avx_algs ) ) ;
}
2020-01-14 19:57:29 -08:00
asmlinkage void sha512_transform_rorx ( struct sha512_state * state ,
const u8 * data , int blocks ) ;
2015-09-16 16:35:53 -07:00
static int sha512_avx2_update ( struct shash_desc * desc , const u8 * data ,
unsigned int len )
{
return sha512_update ( desc , data , len , sha512_transform_rorx ) ;
}
static int sha512_avx2_finup ( struct shash_desc * desc , const u8 * data ,
unsigned int len , u8 * out )
{
return sha512_finup ( desc , data , len , out , sha512_transform_rorx ) ;
}
/* Add padding and return the message digest. */
static int sha512_avx2_final ( struct shash_desc * desc , u8 * out )
{
return sha512_avx2_finup ( desc , NULL , 0 , out ) ;
}
static struct shash_alg sha512_avx2_algs [ ] = { {
. digestsize = SHA512_DIGEST_SIZE ,
. init = sha512_base_init ,
. update = sha512_avx2_update ,
. final = sha512_avx2_final ,
. finup = sha512_avx2_finup ,
. descsize = sizeof ( struct sha512_state ) ,
. base = {
. cra_name = " sha512 " ,
. cra_driver_name = " sha512-avx2 " ,
. cra_priority = 170 ,
. cra_blocksize = SHA512_BLOCK_SIZE ,
. cra_module = THIS_MODULE ,
}
} , {
. digestsize = SHA384_DIGEST_SIZE ,
. init = sha384_base_init ,
. update = sha512_avx2_update ,
. final = sha512_avx2_final ,
. finup = sha512_avx2_finup ,
. descsize = sizeof ( struct sha512_state ) ,
. base = {
. cra_name = " sha384 " ,
. cra_driver_name = " sha384-avx2 " ,
. cra_priority = 170 ,
. cra_blocksize = SHA384_BLOCK_SIZE ,
. cra_module = THIS_MODULE ,
}
} } ;
static bool avx2_usable ( void )
{
if ( avx_usable ( ) & & boot_cpu_has ( X86_FEATURE_AVX2 ) & &
boot_cpu_has ( X86_FEATURE_BMI2 ) )
return true ;
return false ;
}
static int register_sha512_avx2 ( void )
{
if ( avx2_usable ( ) )
return crypto_register_shashes ( sha512_avx2_algs ,
ARRAY_SIZE ( sha512_avx2_algs ) ) ;
return 0 ;
}
static void unregister_sha512_avx2 ( void )
{
if ( avx2_usable ( ) )
crypto_unregister_shashes ( sha512_avx2_algs ,
ARRAY_SIZE ( sha512_avx2_algs ) ) ;
}
static int __init sha512_ssse3_mod_init ( void )
{
if ( register_sha512_ssse3 ( ) )
goto fail ;
if ( register_sha512_avx ( ) ) {
unregister_sha512_ssse3 ( ) ;
goto fail ;
2013-03-26 14:00:02 -07:00
}
2015-09-16 16:35:53 -07:00
if ( register_sha512_avx2 ( ) ) {
unregister_sha512_avx ( ) ;
unregister_sha512_ssse3 ( ) ;
goto fail ;
}
return 0 ;
fail :
2013-03-26 14:00:02 -07:00
return - ENODEV ;
}
static void __exit sha512_ssse3_mod_fini ( void )
{
2015-09-16 16:35:53 -07:00
unregister_sha512_avx2 ( ) ;
unregister_sha512_avx ( ) ;
unregister_sha512_ssse3 ( ) ;
2013-03-26 14:00:02 -07:00
}
module_init ( sha512_ssse3_mod_init ) ;
module_exit ( sha512_ssse3_mod_fini ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " SHA512 Secure Hash Algorithm, Supplemental SSE3 accelerated " ) ;
2014-11-20 17:05:53 -08:00
MODULE_ALIAS_CRYPTO ( " sha512 " ) ;
2016-05-13 14:02:00 +02:00
MODULE_ALIAS_CRYPTO ( " sha512-ssse3 " ) ;
MODULE_ALIAS_CRYPTO ( " sha512-avx " ) ;
MODULE_ALIAS_CRYPTO ( " sha512-avx2 " ) ;
2014-11-20 17:05:53 -08:00
MODULE_ALIAS_CRYPTO ( " sha384 " ) ;
2016-05-13 14:02:00 +02:00
MODULE_ALIAS_CRYPTO ( " sha384-ssse3 " ) ;
MODULE_ALIAS_CRYPTO ( " sha384-avx " ) ;
MODULE_ALIAS_CRYPTO ( " sha384-avx2 " ) ;