2015-02-06 14:57:22 -02:00
/**
* AES routines supporting VMX instructions on the Power 8
*
* Copyright ( C ) 2015 International Business Machines Inc .
*
* 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 ; version 2 only .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*
* Author : Marcelo Henrique Cerri < mhcerri @ br . ibm . com >
*/
# include <linux/types.h>
# include <linux/err.h>
# include <linux/crypto.h>
# include <linux/delay.h>
# include <linux/hardirq.h>
# include <asm/switch_to.h>
# include <crypto/aes.h>
# include "aesp8-ppc.h"
struct p8_aes_ctx {
2015-06-15 16:55:46 +08:00
struct crypto_cipher * fallback ;
struct aes_key enc_key ;
struct aes_key dec_key ;
2015-02-06 14:57:22 -02:00
} ;
static int p8_aes_init ( struct crypto_tfm * tfm )
{
2017-06-16 11:39:48 +03:00
const char * alg = crypto_tfm_alg_name ( tfm ) ;
2015-06-15 16:55:46 +08:00
struct crypto_cipher * fallback ;
struct p8_aes_ctx * ctx = crypto_tfm_ctx ( tfm ) ;
fallback = crypto_alloc_cipher ( alg , 0 , CRYPTO_ALG_NEED_FALLBACK ) ;
if ( IS_ERR ( fallback ) ) {
printk ( KERN_ERR
" Failed to allocate transformation for '%s': %ld \n " ,
alg , PTR_ERR ( fallback ) ) ;
return PTR_ERR ( fallback ) ;
}
crypto_cipher_set_flags ( fallback ,
crypto_cipher_get_flags ( ( struct
crypto_cipher * )
tfm ) ) ;
ctx - > fallback = fallback ;
return 0 ;
2015-02-06 14:57:22 -02:00
}
static void p8_aes_exit ( struct crypto_tfm * tfm )
{
2015-06-15 16:55:46 +08:00
struct p8_aes_ctx * ctx = crypto_tfm_ctx ( tfm ) ;
2015-02-06 14:57:22 -02:00
2015-06-15 16:55:46 +08:00
if ( ctx - > fallback ) {
crypto_free_cipher ( ctx - > fallback ) ;
ctx - > fallback = NULL ;
}
2015-02-06 14:57:22 -02:00
}
static int p8_aes_setkey ( struct crypto_tfm * tfm , const u8 * key ,
2015-06-15 16:55:46 +08:00
unsigned int keylen )
2015-02-06 14:57:22 -02:00
{
2015-06-15 16:55:46 +08:00
int ret ;
struct p8_aes_ctx * ctx = crypto_tfm_ctx ( tfm ) ;
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
ret = aes_p8_set_encrypt_key ( key , keylen * 8 , & ctx - > enc_key ) ;
ret + = aes_p8_set_decrypt_key ( key , keylen * 8 , & ctx - > dec_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 ( ) ;
2015-06-15 16:55:46 +08:00
ret + = crypto_cipher_setkey ( ctx - > fallback , key , keylen ) ;
return ret ;
2015-02-06 14:57:22 -02:00
}
static void p8_aes_encrypt ( struct crypto_tfm * tfm , u8 * dst , const u8 * src )
{
2015-06-15 16:55:46 +08:00
struct p8_aes_ctx * ctx = crypto_tfm_ctx ( tfm ) ;
if ( in_interrupt ( ) ) {
crypto_cipher_encrypt_one ( ctx - > fallback , dst , src ) ;
} else {
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
aes_p8_encrypt ( src , dst , & ctx - > enc_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 ( ) ;
2015-06-15 16:55:46 +08:00
}
2015-02-06 14:57:22 -02:00
}
static void p8_aes_decrypt ( struct crypto_tfm * tfm , u8 * dst , const u8 * src )
{
2015-06-15 16:55:46 +08:00
struct p8_aes_ctx * ctx = crypto_tfm_ctx ( tfm ) ;
if ( in_interrupt ( ) ) {
crypto_cipher_decrypt_one ( ctx - > fallback , dst , src ) ;
} else {
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
aes_p8_decrypt ( src , dst , & ctx - > dec_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 ( ) ;
2015-06-15 16:55:46 +08:00
}
2015-02-06 14:57:22 -02:00
}
struct crypto_alg p8_aes_alg = {
2015-06-15 16:55:46 +08:00
. cra_name = " aes " ,
. cra_driver_name = " p8_aes " ,
. cra_module = THIS_MODULE ,
. cra_priority = 1000 ,
. cra_type = NULL ,
. cra_flags = CRYPTO_ALG_TYPE_CIPHER | CRYPTO_ALG_NEED_FALLBACK ,
. cra_alignmask = 0 ,
. cra_blocksize = AES_BLOCK_SIZE ,
. cra_ctxsize = sizeof ( struct p8_aes_ctx ) ,
. cra_init = p8_aes_init ,
. cra_exit = p8_aes_exit ,
. cra_cipher = {
. cia_min_keysize = AES_MIN_KEY_SIZE ,
. cia_max_keysize = AES_MAX_KEY_SIZE ,
. cia_setkey = p8_aes_setkey ,
. cia_encrypt = p8_aes_encrypt ,
. cia_decrypt = p8_aes_decrypt ,
} ,
2015-02-06 14:57:22 -02:00
} ;