Commit 420a4b20 authored by Herbert Xu's avatar Herbert Xu

crypto: padlock - Avoid resetting cword on successive operations

Resetting the control word is quite expensive.  Fortunately this
isn't an issue for the common operations such as CBC and ECB as
the whole operation is done through a single call.  However, modes
such as LRW and XTS have to call padlock over and over again for
one operation which really hurts if each call resets the control
word.

This patch uses an idea by Sebastian Siewior to store the last
control word used on a CPU and only reset the control word if
that changes.

Note that any task switch automatically resets the control word
so we only need to be accurate with regard to the stored control
word when no task switches occur.
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 1c06da81
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/percpu.h>
#include <linux/smp.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <asm/i387.h> #include <asm/i387.h>
#include "padlock.h" #include "padlock.h"
...@@ -49,6 +51,8 @@ struct aes_ctx { ...@@ -49,6 +51,8 @@ struct aes_ctx {
u32 *D; u32 *D;
}; };
static DEFINE_PER_CPU(struct cword *, last_cword);
/* Tells whether the ACE is capable to generate /* Tells whether the ACE is capable to generate
the extended key for a given key_len. */ the extended key for a given key_len. */
static inline int static inline int
...@@ -89,6 +93,7 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, ...@@ -89,6 +93,7 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
const __le32 *key = (const __le32 *)in_key; const __le32 *key = (const __le32 *)in_key;
u32 *flags = &tfm->crt_flags; u32 *flags = &tfm->crt_flags;
struct crypto_aes_ctx gen_aes; struct crypto_aes_ctx gen_aes;
int cpu;
if (key_len % 8) { if (key_len % 8) {
*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
...@@ -118,7 +123,7 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, ...@@ -118,7 +123,7 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
/* Don't generate extended keys if the hardware can do it. */ /* Don't generate extended keys if the hardware can do it. */
if (aes_hw_extkey_available(key_len)) if (aes_hw_extkey_available(key_len))
return 0; goto ok;
ctx->D = ctx->d_data; ctx->D = ctx->d_data;
ctx->cword.encrypt.keygen = 1; ctx->cword.encrypt.keygen = 1;
...@@ -131,17 +136,32 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, ...@@ -131,17 +136,32 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
memcpy(ctx->E, gen_aes.key_enc, AES_MAX_KEYLENGTH); memcpy(ctx->E, gen_aes.key_enc, AES_MAX_KEYLENGTH);
memcpy(ctx->D, gen_aes.key_dec, AES_MAX_KEYLENGTH); memcpy(ctx->D, gen_aes.key_dec, AES_MAX_KEYLENGTH);
ok:
for_each_online_cpu(cpu)
if (&ctx->cword.encrypt == per_cpu(last_cword, cpu) ||
&ctx->cword.decrypt == per_cpu(last_cword, cpu))
per_cpu(last_cword, cpu) = NULL;
return 0; return 0;
} }
/* ====== Encryption/decryption routines ====== */ /* ====== Encryption/decryption routines ====== */
/* These are the real call to PadLock. */ /* These are the real call to PadLock. */
static inline void padlock_reset_key(void) static inline void padlock_reset_key(struct cword *cword)
{ {
int cpu = raw_smp_processor_id();
if (cword != per_cpu(last_cword, cpu))
asm volatile ("pushfl; popfl"); asm volatile ("pushfl; popfl");
} }
static inline void padlock_store_cword(struct cword *cword)
{
per_cpu(last_cword, raw_smp_processor_id()) = cword;
}
/* /*
* While the padlock instructions don't use FP/SSE registers, they * While the padlock instructions don't use FP/SSE registers, they
* generate a spurious DNA fault when cr0.ts is '1'. These instructions * generate a spurious DNA fault when cr0.ts is '1'. These instructions
...@@ -149,7 +169,7 @@ static inline void padlock_reset_key(void) ...@@ -149,7 +169,7 @@ static inline void padlock_reset_key(void)
*/ */
static inline void padlock_xcrypt(const u8 *input, u8 *output, void *key, static inline void padlock_xcrypt(const u8 *input, u8 *output, void *key,
void *control_word) struct cword *control_word)
{ {
asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */
: "+S"(input), "+D"(output) : "+S"(input), "+D"(output)
...@@ -213,22 +233,24 @@ static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) ...@@ -213,22 +233,24 @@ static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
{ {
struct aes_ctx *ctx = aes_ctx(tfm); struct aes_ctx *ctx = aes_ctx(tfm);
int ts_state; int ts_state;
padlock_reset_key();
padlock_reset_key(&ctx->cword.encrypt);
ts_state = irq_ts_save(); ts_state = irq_ts_save();
aes_crypt(in, out, ctx->E, &ctx->cword.encrypt); aes_crypt(in, out, ctx->E, &ctx->cword.encrypt);
irq_ts_restore(ts_state); irq_ts_restore(ts_state);
padlock_store_cword(&ctx->cword.encrypt);
} }
static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
{ {
struct aes_ctx *ctx = aes_ctx(tfm); struct aes_ctx *ctx = aes_ctx(tfm);
int ts_state; int ts_state;
padlock_reset_key();
padlock_reset_key(&ctx->cword.encrypt);
ts_state = irq_ts_save(); ts_state = irq_ts_save();
aes_crypt(in, out, ctx->D, &ctx->cword.decrypt); aes_crypt(in, out, ctx->D, &ctx->cword.decrypt);
irq_ts_restore(ts_state); irq_ts_restore(ts_state);
padlock_store_cword(&ctx->cword.encrypt);
} }
static struct crypto_alg aes_alg = { static struct crypto_alg aes_alg = {
...@@ -261,7 +283,7 @@ static int ecb_aes_encrypt(struct blkcipher_desc *desc, ...@@ -261,7 +283,7 @@ static int ecb_aes_encrypt(struct blkcipher_desc *desc,
int err; int err;
int ts_state; int ts_state;
padlock_reset_key(); padlock_reset_key(&ctx->cword.encrypt);
blkcipher_walk_init(&walk, dst, src, nbytes); blkcipher_walk_init(&walk, dst, src, nbytes);
err = blkcipher_walk_virt(desc, &walk); err = blkcipher_walk_virt(desc, &walk);
...@@ -276,6 +298,8 @@ static int ecb_aes_encrypt(struct blkcipher_desc *desc, ...@@ -276,6 +298,8 @@ static int ecb_aes_encrypt(struct blkcipher_desc *desc,
} }
irq_ts_restore(ts_state); irq_ts_restore(ts_state);
padlock_store_cword(&ctx->cword.encrypt);
return err; return err;
} }
...@@ -288,7 +312,7 @@ static int ecb_aes_decrypt(struct blkcipher_desc *desc, ...@@ -288,7 +312,7 @@ static int ecb_aes_decrypt(struct blkcipher_desc *desc,
int err; int err;
int ts_state; int ts_state;
padlock_reset_key(); padlock_reset_key(&ctx->cword.decrypt);
blkcipher_walk_init(&walk, dst, src, nbytes); blkcipher_walk_init(&walk, dst, src, nbytes);
err = blkcipher_walk_virt(desc, &walk); err = blkcipher_walk_virt(desc, &walk);
...@@ -302,6 +326,9 @@ static int ecb_aes_decrypt(struct blkcipher_desc *desc, ...@@ -302,6 +326,9 @@ static int ecb_aes_decrypt(struct blkcipher_desc *desc,
err = blkcipher_walk_done(desc, &walk, nbytes); err = blkcipher_walk_done(desc, &walk, nbytes);
} }
irq_ts_restore(ts_state); irq_ts_restore(ts_state);
padlock_store_cword(&ctx->cword.encrypt);
return err; return err;
} }
...@@ -336,7 +363,7 @@ static int cbc_aes_encrypt(struct blkcipher_desc *desc, ...@@ -336,7 +363,7 @@ static int cbc_aes_encrypt(struct blkcipher_desc *desc,
int err; int err;
int ts_state; int ts_state;
padlock_reset_key(); padlock_reset_key(&ctx->cword.encrypt);
blkcipher_walk_init(&walk, dst, src, nbytes); blkcipher_walk_init(&walk, dst, src, nbytes);
err = blkcipher_walk_virt(desc, &walk); err = blkcipher_walk_virt(desc, &walk);
...@@ -353,6 +380,8 @@ static int cbc_aes_encrypt(struct blkcipher_desc *desc, ...@@ -353,6 +380,8 @@ static int cbc_aes_encrypt(struct blkcipher_desc *desc,
} }
irq_ts_restore(ts_state); irq_ts_restore(ts_state);
padlock_store_cword(&ctx->cword.decrypt);
return err; return err;
} }
...@@ -365,7 +394,7 @@ static int cbc_aes_decrypt(struct blkcipher_desc *desc, ...@@ -365,7 +394,7 @@ static int cbc_aes_decrypt(struct blkcipher_desc *desc,
int err; int err;
int ts_state; int ts_state;
padlock_reset_key(); padlock_reset_key(&ctx->cword.encrypt);
blkcipher_walk_init(&walk, dst, src, nbytes); blkcipher_walk_init(&walk, dst, src, nbytes);
err = blkcipher_walk_virt(desc, &walk); err = blkcipher_walk_virt(desc, &walk);
...@@ -380,6 +409,9 @@ static int cbc_aes_decrypt(struct blkcipher_desc *desc, ...@@ -380,6 +409,9 @@ static int cbc_aes_decrypt(struct blkcipher_desc *desc,
} }
irq_ts_restore(ts_state); irq_ts_restore(ts_state);
padlock_store_cword(&ctx->cword.encrypt);
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment