2019-05-17 01:40:02 +10:00
// SPDX-License-Identifier: GPL-2.0
2021-03-21 01:55:25 +05:30
/*
2015-02-06 14:59:05 -02:00
* GHASH routines supporting VMX instructions on the Power 8
*
2019-05-17 01:40:02 +10:00
* Copyright ( C ) 2015 , 2019 International Business Machines Inc .
2015-02-06 14:59:05 -02:00
*
* Author : Marcelo Henrique Cerri < mhcerri @ br . ibm . com >
2019-05-17 01:40:02 +10:00
*
* Extended by Daniel Axtens < dja @ axtens . net > to replace the fallback
* mechanism . The new approach is based on arm64 code , which is :
* Copyright ( C ) 2014 - 2018 Linaro Ltd . < ard . biesheuvel @ linaro . org >
2015-02-06 14:59:05 -02:00
*/
# include <linux/types.h>
# include <linux/err.h>
# include <linux/crypto.h>
# include <linux/delay.h>
2019-04-12 22:33:12 -07:00
# include <asm/simd.h>
2015-02-06 14:59:05 -02:00
# include <asm/switch_to.h>
# include <crypto/aes.h>
2016-09-28 13:42:10 -03:00
# include <crypto/ghash.h>
2015-02-06 14:59:05 -02:00
# include <crypto/scatterwalk.h>
# include <crypto/internal/hash.h>
2019-04-12 22:33:12 -07:00
# include <crypto/internal/simd.h>
2015-02-06 14:59:05 -02:00
# include <crypto/b128ops.h>
void gcm_init_p8 ( u128 htable [ 16 ] , const u64 Xi [ 2 ] ) ;
void gcm_gmult_p8 ( u64 Xi [ 2 ] , const u128 htable [ 16 ] ) ;
void gcm_ghash_p8 ( u64 Xi [ 2 ] , const u128 htable [ 16 ] ,
2015-06-15 16:55:46 +08:00
const u8 * in , size_t len ) ;
2015-02-06 14:59:05 -02:00
struct p8_ghash_ctx {
2019-05-17 01:40:02 +10:00
/* key used by vector asm */
2015-06-15 16:55:46 +08:00
u128 htable [ 16 ] ;
2019-05-17 01:40:02 +10:00
/* key used by software fallback */
be128 key ;
2015-02-06 14:59:05 -02:00
} ;
struct p8_ghash_desc_ctx {
2015-06-15 16:55:46 +08:00
u64 shash [ 2 ] ;
u8 buffer [ GHASH_DIGEST_SIZE ] ;
int bytes ;
2015-02-06 14:59:05 -02:00
} ;
static int p8_ghash_init ( struct shash_desc * desc )
{
2015-06-15 16:55:46 +08:00
struct p8_ghash_desc_ctx * dctx = shash_desc_ctx ( desc ) ;
dctx - > bytes = 0 ;
memset ( dctx - > shash , 0 , GHASH_DIGEST_SIZE ) ;
2019-05-17 01:40:02 +10:00
return 0 ;
2015-02-06 14:59:05 -02:00
}
static int p8_ghash_setkey ( struct crypto_shash * tfm , const u8 * key ,
2015-06-15 16:55:46 +08:00
unsigned int keylen )
2015-02-06 14:59:05 -02:00
{
2015-06-15 16:55:46 +08:00
struct p8_ghash_ctx * ctx = crypto_tfm_ctx ( crypto_shash_tfm ( tfm ) ) ;
2015-02-06 14:59:05 -02:00
2016-09-28 13:42:10 -03:00
if ( keylen ! = GHASH_BLOCK_SIZE )
2015-06-15 16:55:46 +08:00
return - EINVAL ;
2015-02-06 14:59:05 -02:00
2015-06-22 21:04:48 -07:00
preempt_disable ( ) ;
2015-06-15 16:55:46 +08:00
pagefault_disable ( ) ;
2015-07-13 13:51:39 -03:00
enable_kernel_vsx ( ) ;
2015-06-15 16:55:46 +08:00
gcm_init_p8 ( ctx - > htable , ( const u64 * ) key ) ;
2015-10-29 11:44:05 +11:00
disable_kernel_vsx ( ) ;
2015-06-15 16:55:46 +08:00
pagefault_enable ( ) ;
2015-06-22 21:04:48 -07:00
preempt_enable ( ) ;
2019-05-17 01:40:02 +10:00
memcpy ( & ctx - > key , key , GHASH_BLOCK_SIZE ) ;
return 0 ;
}
static inline void __ghash_block ( struct p8_ghash_ctx * ctx ,
struct p8_ghash_desc_ctx * dctx )
{
if ( crypto_simd_usable ( ) ) {
preempt_disable ( ) ;
pagefault_disable ( ) ;
enable_kernel_vsx ( ) ;
gcm_ghash_p8 ( dctx - > shash , ctx - > htable ,
dctx - > buffer , GHASH_DIGEST_SIZE ) ;
disable_kernel_vsx ( ) ;
pagefault_enable ( ) ;
preempt_enable ( ) ;
} else {
crypto_xor ( ( u8 * ) dctx - > shash , dctx - > buffer , GHASH_BLOCK_SIZE ) ;
gf128mul_lle ( ( be128 * ) dctx - > shash , & ctx - > key ) ;
}
}
static inline void __ghash_blocks ( struct p8_ghash_ctx * ctx ,
struct p8_ghash_desc_ctx * dctx ,
const u8 * src , unsigned int srclen )
{
if ( crypto_simd_usable ( ) ) {
preempt_disable ( ) ;
pagefault_disable ( ) ;
enable_kernel_vsx ( ) ;
gcm_ghash_p8 ( dctx - > shash , ctx - > htable ,
src , srclen ) ;
disable_kernel_vsx ( ) ;
pagefault_enable ( ) ;
preempt_enable ( ) ;
} else {
while ( srclen > = GHASH_BLOCK_SIZE ) {
crypto_xor ( ( u8 * ) dctx - > shash , src , GHASH_BLOCK_SIZE ) ;
gf128mul_lle ( ( be128 * ) dctx - > shash , & ctx - > key ) ;
srclen - = GHASH_BLOCK_SIZE ;
src + = GHASH_BLOCK_SIZE ;
}
}
2015-02-06 14:59:05 -02:00
}
static int p8_ghash_update ( struct shash_desc * desc ,
2015-06-15 16:55:46 +08:00
const u8 * src , unsigned int srclen )
2015-02-06 14:59:05 -02:00
{
2015-06-15 16:55:46 +08:00
unsigned int len ;
struct p8_ghash_ctx * ctx = crypto_tfm_ctx ( crypto_shash_tfm ( desc - > tfm ) ) ;
struct p8_ghash_desc_ctx * dctx = shash_desc_ctx ( desc ) ;
2019-05-17 01:40:02 +10:00
if ( dctx - > bytes ) {
if ( dctx - > bytes + srclen < GHASH_DIGEST_SIZE ) {
2015-06-15 16:55:46 +08:00
memcpy ( dctx - > buffer + dctx - > bytes , src ,
2019-05-17 01:40:02 +10:00
srclen ) ;
dctx - > bytes + = srclen ;
return 0 ;
2015-06-15 16:55:46 +08:00
}
2019-05-17 01:40:02 +10:00
memcpy ( dctx - > buffer + dctx - > bytes , src ,
GHASH_DIGEST_SIZE - dctx - > bytes ) ;
__ghash_block ( ctx , dctx ) ;
src + = GHASH_DIGEST_SIZE - dctx - > bytes ;
srclen - = GHASH_DIGEST_SIZE - dctx - > bytes ;
dctx - > bytes = 0 ;
}
len = srclen & ~ ( GHASH_DIGEST_SIZE - 1 ) ;
if ( len ) {
__ghash_blocks ( ctx , dctx , src , len ) ;
src + = len ;
srclen - = len ;
2015-06-15 16:55:46 +08:00
}
2019-05-17 01:40:02 +10:00
if ( srclen ) {
memcpy ( dctx - > buffer , src , srclen ) ;
dctx - > bytes = srclen ;
}
return 0 ;
2015-02-06 14:59:05 -02:00
}
static int p8_ghash_final ( struct shash_desc * desc , u8 * out )
{
2015-06-15 16:55:46 +08:00
int i ;
struct p8_ghash_ctx * ctx = crypto_tfm_ctx ( crypto_shash_tfm ( desc - > tfm ) ) ;
struct p8_ghash_desc_ctx * dctx = shash_desc_ctx ( desc ) ;
2019-05-17 01:40:02 +10:00
if ( dctx - > bytes ) {
for ( i = dctx - > bytes ; i < GHASH_DIGEST_SIZE ; i + + )
dctx - > buffer [ i ] = 0 ;
__ghash_block ( ctx , dctx ) ;
dctx - > bytes = 0 ;
2015-06-15 16:55:46 +08:00
}
2019-05-17 01:40:02 +10:00
memcpy ( out , dctx - > shash , GHASH_DIGEST_SIZE ) ;
return 0 ;
2015-02-06 14:59:05 -02:00
}
struct shash_alg p8_ghash_alg = {
2015-06-15 16:55:46 +08:00
. digestsize = GHASH_DIGEST_SIZE ,
. init = p8_ghash_init ,
. update = p8_ghash_update ,
. final = p8_ghash_final ,
. setkey = p8_ghash_setkey ,
2016-09-28 13:42:10 -03:00
. descsize = sizeof ( struct p8_ghash_desc_ctx )
+ sizeof ( struct ghash_desc_ctx ) ,
2015-06-15 16:55:46 +08:00
. base = {
. cra_name = " ghash " ,
. cra_driver_name = " p8_ghash " ,
. cra_priority = 1000 ,
. cra_blocksize = GHASH_BLOCK_SIZE ,
. cra_ctxsize = sizeof ( struct p8_ghash_ctx ) ,
. cra_module = THIS_MODULE ,
} ,
2015-02-06 14:59:05 -02:00
} ;