diff options
Diffstat (limited to 'drivers/crypto')
-rw-r--r-- | drivers/crypto/padlock-aes.c | 81 |
1 files changed, 46 insertions, 35 deletions
diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c index 87f92c39b5f0..e1d8776c6972 100644 --- a/drivers/crypto/padlock-aes.c +++ b/drivers/crypto/padlock-aes.c | |||
@@ -18,9 +18,17 @@ | |||
18 | #include <linux/percpu.h> | 18 | #include <linux/percpu.h> |
19 | #include <linux/smp.h> | 19 | #include <linux/smp.h> |
20 | #include <asm/byteorder.h> | 20 | #include <asm/byteorder.h> |
21 | #include <asm/processor.h> | ||
21 | #include <asm/i387.h> | 22 | #include <asm/i387.h> |
22 | #include "padlock.h" | 23 | #include "padlock.h" |
23 | 24 | ||
25 | /* number of data blocks actually fetched for each xcrypt insn */ | ||
26 | static unsigned int ecb_fetch_blocks = 2; | ||
27 | static unsigned int cbc_fetch_blocks = 1; | ||
28 | |||
29 | #define ecb_fetch_bytes (ecb_fetch_blocks * AES_BLOCK_SIZE) | ||
30 | #define cbc_fetch_bytes (cbc_fetch_blocks * AES_BLOCK_SIZE) | ||
31 | |||
24 | /* Control word. */ | 32 | /* Control word. */ |
25 | struct cword { | 33 | struct cword { |
26 | unsigned int __attribute__ ((__packed__)) | 34 | unsigned int __attribute__ ((__packed__)) |
@@ -173,63 +181,59 @@ static inline void padlock_store_cword(struct cword *cword) | |||
173 | */ | 181 | */ |
174 | 182 | ||
175 | static inline void padlock_xcrypt(const u8 *input, u8 *output, void *key, | 183 | static inline void padlock_xcrypt(const u8 *input, u8 *output, void *key, |
176 | struct cword *control_word) | 184 | struct cword *control_word, int count) |
177 | { | 185 | { |
178 | asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ | 186 | asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ |
179 | : "+S"(input), "+D"(output) | 187 | : "+S"(input), "+D"(output) |
180 | : "d"(control_word), "b"(key), "c"(1)); | 188 | : "d"(control_word), "b"(key), "c"(count)); |
181 | } | 189 | } |
182 | 190 | ||
183 | static void aes_crypt_copy(const u8 *in, u8 *out, u32 *key, struct cword *cword) | 191 | static void aes_crypt_copy(const u8 *in, u8 *out, u32 *key, |
192 | struct cword *cword, int count) | ||
184 | { | 193 | { |
185 | u8 buf[AES_BLOCK_SIZE * 2 + PADLOCK_ALIGNMENT - 1]; | 194 | /* |
195 | * Padlock prefetches extra data so we must provide mapped input buffers. | ||
196 | * Assume there are at least 16 bytes of stack already in use. | ||
197 | */ | ||
198 | u8 buf[AES_BLOCK_SIZE * 7 + PADLOCK_ALIGNMENT - 1]; | ||
186 | u8 *tmp = PTR_ALIGN(&buf[0], PADLOCK_ALIGNMENT); | 199 | u8 *tmp = PTR_ALIGN(&buf[0], PADLOCK_ALIGNMENT); |
187 | 200 | ||
188 | memcpy(tmp, in, AES_BLOCK_SIZE); | 201 | memcpy(tmp, in, count * AES_BLOCK_SIZE); |
189 | padlock_xcrypt(tmp, out, key, cword); | 202 | padlock_xcrypt(tmp, out, key, cword, count); |
190 | } | 203 | } |
191 | 204 | ||
192 | static inline void aes_crypt(const u8 *in, u8 *out, u32 *key, | 205 | static inline void aes_crypt(const u8 *in, u8 *out, u32 *key, |
193 | struct cword *cword) | 206 | struct cword *cword, int count) |
194 | { | 207 | { |
195 | /* padlock_xcrypt requires at least two blocks of data. */ | 208 | /* Padlock in ECB mode fetches at least ecb_fetch_bytes of data. |
196 | if (unlikely(!(((unsigned long)in ^ (PAGE_SIZE - AES_BLOCK_SIZE)) & | 209 | * We could avoid some copying here but it's probably not worth it. |
197 | (PAGE_SIZE - 1)))) { | 210 | */ |
198 | aes_crypt_copy(in, out, key, cword); | 211 | if (unlikely(((unsigned long)in & PAGE_SIZE) + ecb_fetch_bytes > PAGE_SIZE)) { |
212 | aes_crypt_copy(in, out, key, cword, count); | ||
199 | return; | 213 | return; |
200 | } | 214 | } |
201 | 215 | ||
202 | padlock_xcrypt(in, out, key, cword); | 216 | padlock_xcrypt(in, out, key, cword, count); |
203 | } | 217 | } |
204 | 218 | ||
205 | static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key, | 219 | static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key, |
206 | void *control_word, u32 count) | 220 | void *control_word, u32 count) |
207 | { | 221 | { |
208 | if (count == 1) { | 222 | u32 initial = count & (ecb_fetch_blocks - 1); |
209 | aes_crypt(input, output, key, control_word); | 223 | |
224 | if (count < ecb_fetch_blocks) { | ||
225 | aes_crypt(input, output, key, control_word, count); | ||
210 | return; | 226 | return; |
211 | } | 227 | } |
212 | 228 | ||
213 | asm volatile ("test $1, %%cl;" | 229 | if (initial) |
214 | "je 1f;" | 230 | asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ |
215 | #ifndef CONFIG_X86_64 | 231 | : "+S"(input), "+D"(output) |
216 | "lea -1(%%ecx), %%eax;" | 232 | : "d"(control_word), "b"(key), "c"(initial)); |
217 | "mov $1, %%ecx;" | 233 | |
218 | #else | 234 | asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ |
219 | "lea -1(%%rcx), %%rax;" | ||
220 | "mov $1, %%rcx;" | ||
221 | #endif | ||
222 | ".byte 0xf3,0x0f,0xa7,0xc8;" /* rep xcryptecb */ | ||
223 | #ifndef CONFIG_X86_64 | ||
224 | "mov %%eax, %%ecx;" | ||
225 | #else | ||
226 | "mov %%rax, %%rcx;" | ||
227 | #endif | ||
228 | "1:" | ||
229 | ".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ | ||
230 | : "+S"(input), "+D"(output) | 235 | : "+S"(input), "+D"(output) |
231 | : "d"(control_word), "b"(key), "c"(count) | 236 | : "d"(control_word), "b"(key), "c"(count - initial)); |
232 | : "ax"); | ||
233 | } | 237 | } |
234 | 238 | ||
235 | static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key, | 239 | static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key, |
@@ -249,7 +253,7 @@ static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) | |||
249 | 253 | ||
250 | padlock_reset_key(&ctx->cword.encrypt); | 254 | padlock_reset_key(&ctx->cword.encrypt); |
251 | ts_state = irq_ts_save(); | 255 | ts_state = irq_ts_save(); |
252 | aes_crypt(in, out, ctx->E, &ctx->cword.encrypt); | 256 | aes_crypt(in, out, ctx->E, &ctx->cword.encrypt, 1); |
253 | irq_ts_restore(ts_state); | 257 | irq_ts_restore(ts_state); |
254 | padlock_store_cword(&ctx->cword.encrypt); | 258 | padlock_store_cword(&ctx->cword.encrypt); |
255 | } | 259 | } |
@@ -261,7 +265,7 @@ static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) | |||
261 | 265 | ||
262 | padlock_reset_key(&ctx->cword.encrypt); | 266 | padlock_reset_key(&ctx->cword.encrypt); |
263 | ts_state = irq_ts_save(); | 267 | ts_state = irq_ts_save(); |
264 | aes_crypt(in, out, ctx->D, &ctx->cword.decrypt); | 268 | aes_crypt(in, out, ctx->D, &ctx->cword.decrypt, 1); |
265 | irq_ts_restore(ts_state); | 269 | irq_ts_restore(ts_state); |
266 | padlock_store_cword(&ctx->cword.encrypt); | 270 | padlock_store_cword(&ctx->cword.encrypt); |
267 | } | 271 | } |
@@ -454,6 +458,7 @@ static struct crypto_alg cbc_aes_alg = { | |||
454 | static int __init padlock_init(void) | 458 | static int __init padlock_init(void) |
455 | { | 459 | { |
456 | int ret; | 460 | int ret; |
461 | struct cpuinfo_x86 *c = &cpu_data(0); | ||
457 | 462 | ||
458 | if (!cpu_has_xcrypt) { | 463 | if (!cpu_has_xcrypt) { |
459 | printk(KERN_NOTICE PFX "VIA PadLock not detected.\n"); | 464 | printk(KERN_NOTICE PFX "VIA PadLock not detected.\n"); |
@@ -476,6 +481,12 @@ static int __init padlock_init(void) | |||
476 | 481 | ||
477 | printk(KERN_NOTICE PFX "Using VIA PadLock ACE for AES algorithm.\n"); | 482 | printk(KERN_NOTICE PFX "Using VIA PadLock ACE for AES algorithm.\n"); |
478 | 483 | ||
484 | if (c->x86 == 6 && c->x86_model == 15 && c->x86_mask == 2) { | ||
485 | ecb_fetch_blocks = 8; | ||
486 | cbc_fetch_blocks = 4; /* NOTE: notused */ | ||
487 | printk(KERN_NOTICE PFX "VIA Nano stepping 2 detected: enabling workaround.\n"); | ||
488 | } | ||
489 | |||
479 | out: | 490 | out: |
480 | return ret; | 491 | return ret; |
481 | 492 | ||