162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Cryptographic API. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Support for VIA PadLock hardware crypto engine. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (c) 2004 Michal Ludvig <michal@logix.cz> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <crypto/algapi.h> 1262306a36Sopenharmony_ci#include <crypto/aes.h> 1362306a36Sopenharmony_ci#include <crypto/internal/skcipher.h> 1462306a36Sopenharmony_ci#include <crypto/padlock.h> 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/init.h> 1762306a36Sopenharmony_ci#include <linux/types.h> 1862306a36Sopenharmony_ci#include <linux/errno.h> 1962306a36Sopenharmony_ci#include <linux/interrupt.h> 2062306a36Sopenharmony_ci#include <linux/kernel.h> 2162306a36Sopenharmony_ci#include <linux/mm.h> 2262306a36Sopenharmony_ci#include <linux/percpu.h> 2362306a36Sopenharmony_ci#include <linux/smp.h> 2462306a36Sopenharmony_ci#include <linux/slab.h> 2562306a36Sopenharmony_ci#include <asm/cpu_device_id.h> 2662306a36Sopenharmony_ci#include <asm/byteorder.h> 2762306a36Sopenharmony_ci#include <asm/processor.h> 2862306a36Sopenharmony_ci#include <asm/fpu/api.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* 3162306a36Sopenharmony_ci * Number of data blocks actually fetched for each xcrypt insn. 3262306a36Sopenharmony_ci * Processors with prefetch errata will fetch extra blocks. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_cistatic unsigned int ecb_fetch_blocks = 2; 3562306a36Sopenharmony_ci#define MAX_ECB_FETCH_BLOCKS (8) 3662306a36Sopenharmony_ci#define ecb_fetch_bytes (ecb_fetch_blocks * AES_BLOCK_SIZE) 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic unsigned int cbc_fetch_blocks = 1; 3962306a36Sopenharmony_ci#define MAX_CBC_FETCH_BLOCKS (4) 4062306a36Sopenharmony_ci#define cbc_fetch_bytes (cbc_fetch_blocks * AES_BLOCK_SIZE) 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* Control word. */ 4362306a36Sopenharmony_cistruct cword { 4462306a36Sopenharmony_ci unsigned int __attribute__ ((__packed__)) 4562306a36Sopenharmony_ci rounds:4, 4662306a36Sopenharmony_ci algo:3, 4762306a36Sopenharmony_ci keygen:1, 4862306a36Sopenharmony_ci interm:1, 4962306a36Sopenharmony_ci encdec:1, 5062306a36Sopenharmony_ci ksize:2; 5162306a36Sopenharmony_ci} __attribute__ ((__aligned__(PADLOCK_ALIGNMENT))); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* Whenever making any changes to the following 5462306a36Sopenharmony_ci * structure *make sure* you keep E, d_data 5562306a36Sopenharmony_ci * and cword aligned on 16 Bytes boundaries and 5662306a36Sopenharmony_ci * the Hardware can access 16 * 16 bytes of E and d_data 5762306a36Sopenharmony_ci * (only the first 15 * 16 bytes matter but the HW reads 5862306a36Sopenharmony_ci * more). 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_cistruct aes_ctx { 6162306a36Sopenharmony_ci u32 E[AES_MAX_KEYLENGTH_U32] 6262306a36Sopenharmony_ci __attribute__ ((__aligned__(PADLOCK_ALIGNMENT))); 6362306a36Sopenharmony_ci u32 d_data[AES_MAX_KEYLENGTH_U32] 6462306a36Sopenharmony_ci __attribute__ ((__aligned__(PADLOCK_ALIGNMENT))); 6562306a36Sopenharmony_ci struct { 6662306a36Sopenharmony_ci struct cword encrypt; 6762306a36Sopenharmony_ci struct cword decrypt; 6862306a36Sopenharmony_ci } cword; 6962306a36Sopenharmony_ci u32 *D; 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic DEFINE_PER_CPU(struct cword *, paes_last_cword); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* Tells whether the ACE is capable to generate 7562306a36Sopenharmony_ci the extended key for a given key_len. */ 7662306a36Sopenharmony_cistatic inline int 7762306a36Sopenharmony_ciaes_hw_extkey_available(uint8_t key_len) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci /* TODO: We should check the actual CPU model/stepping 8062306a36Sopenharmony_ci as it's possible that the capability will be 8162306a36Sopenharmony_ci added in the next CPU revisions. */ 8262306a36Sopenharmony_ci if (key_len == 16) 8362306a36Sopenharmony_ci return 1; 8462306a36Sopenharmony_ci return 0; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic inline struct aes_ctx *aes_ctx_common(void *ctx) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci unsigned long addr = (unsigned long)ctx; 9062306a36Sopenharmony_ci unsigned long align = PADLOCK_ALIGNMENT; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (align <= crypto_tfm_ctx_alignment()) 9362306a36Sopenharmony_ci align = 1; 9462306a36Sopenharmony_ci return (struct aes_ctx *)ALIGN(addr, align); 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic inline struct aes_ctx *aes_ctx(struct crypto_tfm *tfm) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci return aes_ctx_common(crypto_tfm_ctx(tfm)); 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic inline struct aes_ctx *skcipher_aes_ctx(struct crypto_skcipher *tfm) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci return aes_ctx_common(crypto_skcipher_ctx(tfm)); 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, 10862306a36Sopenharmony_ci unsigned int key_len) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci struct aes_ctx *ctx = aes_ctx(tfm); 11162306a36Sopenharmony_ci const __le32 *key = (const __le32 *)in_key; 11262306a36Sopenharmony_ci struct crypto_aes_ctx gen_aes; 11362306a36Sopenharmony_ci int cpu; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci if (key_len % 8) 11662306a36Sopenharmony_ci return -EINVAL; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci /* 11962306a36Sopenharmony_ci * If the hardware is capable of generating the extended key 12062306a36Sopenharmony_ci * itself we must supply the plain key for both encryption 12162306a36Sopenharmony_ci * and decryption. 12262306a36Sopenharmony_ci */ 12362306a36Sopenharmony_ci ctx->D = ctx->E; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci ctx->E[0] = le32_to_cpu(key[0]); 12662306a36Sopenharmony_ci ctx->E[1] = le32_to_cpu(key[1]); 12762306a36Sopenharmony_ci ctx->E[2] = le32_to_cpu(key[2]); 12862306a36Sopenharmony_ci ctx->E[3] = le32_to_cpu(key[3]); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* Prepare control words. */ 13162306a36Sopenharmony_ci memset(&ctx->cword, 0, sizeof(ctx->cword)); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci ctx->cword.decrypt.encdec = 1; 13462306a36Sopenharmony_ci ctx->cword.encrypt.rounds = 10 + (key_len - 16) / 4; 13562306a36Sopenharmony_ci ctx->cword.decrypt.rounds = ctx->cword.encrypt.rounds; 13662306a36Sopenharmony_ci ctx->cword.encrypt.ksize = (key_len - 16) / 8; 13762306a36Sopenharmony_ci ctx->cword.decrypt.ksize = ctx->cword.encrypt.ksize; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci /* Don't generate extended keys if the hardware can do it. */ 14062306a36Sopenharmony_ci if (aes_hw_extkey_available(key_len)) 14162306a36Sopenharmony_ci goto ok; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci ctx->D = ctx->d_data; 14462306a36Sopenharmony_ci ctx->cword.encrypt.keygen = 1; 14562306a36Sopenharmony_ci ctx->cword.decrypt.keygen = 1; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci if (aes_expandkey(&gen_aes, in_key, key_len)) 14862306a36Sopenharmony_ci return -EINVAL; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci memcpy(ctx->E, gen_aes.key_enc, AES_MAX_KEYLENGTH); 15162306a36Sopenharmony_ci memcpy(ctx->D, gen_aes.key_dec, AES_MAX_KEYLENGTH); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ciok: 15462306a36Sopenharmony_ci for_each_online_cpu(cpu) 15562306a36Sopenharmony_ci if (&ctx->cword.encrypt == per_cpu(paes_last_cword, cpu) || 15662306a36Sopenharmony_ci &ctx->cword.decrypt == per_cpu(paes_last_cword, cpu)) 15762306a36Sopenharmony_ci per_cpu(paes_last_cword, cpu) = NULL; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci return 0; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic int aes_set_key_skcipher(struct crypto_skcipher *tfm, const u8 *in_key, 16362306a36Sopenharmony_ci unsigned int key_len) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci return aes_set_key(crypto_skcipher_tfm(tfm), in_key, key_len); 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci/* ====== Encryption/decryption routines ====== */ 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci/* These are the real call to PadLock. */ 17162306a36Sopenharmony_cistatic inline void padlock_reset_key(struct cword *cword) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci int cpu = raw_smp_processor_id(); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (cword != per_cpu(paes_last_cword, cpu)) 17662306a36Sopenharmony_ci#ifndef CONFIG_X86_64 17762306a36Sopenharmony_ci asm volatile ("pushfl; popfl"); 17862306a36Sopenharmony_ci#else 17962306a36Sopenharmony_ci asm volatile ("pushfq; popfq"); 18062306a36Sopenharmony_ci#endif 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic inline void padlock_store_cword(struct cword *cword) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci per_cpu(paes_last_cword, raw_smp_processor_id()) = cword; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci/* 18962306a36Sopenharmony_ci * While the padlock instructions don't use FP/SSE registers, they 19062306a36Sopenharmony_ci * generate a spurious DNA fault when CR0.TS is '1'. Fortunately, 19162306a36Sopenharmony_ci * the kernel doesn't use CR0.TS. 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic inline void rep_xcrypt_ecb(const u8 *input, u8 *output, void *key, 19562306a36Sopenharmony_ci struct cword *control_word, int count) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ 19862306a36Sopenharmony_ci : "+S"(input), "+D"(output) 19962306a36Sopenharmony_ci : "d"(control_word), "b"(key), "c"(count)); 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic inline u8 *rep_xcrypt_cbc(const u8 *input, u8 *output, void *key, 20362306a36Sopenharmony_ci u8 *iv, struct cword *control_word, int count) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci asm volatile (".byte 0xf3,0x0f,0xa7,0xd0" /* rep xcryptcbc */ 20662306a36Sopenharmony_ci : "+S" (input), "+D" (output), "+a" (iv) 20762306a36Sopenharmony_ci : "d" (control_word), "b" (key), "c" (count)); 20862306a36Sopenharmony_ci return iv; 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic void ecb_crypt_copy(const u8 *in, u8 *out, u32 *key, 21262306a36Sopenharmony_ci struct cword *cword, int count) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci /* 21562306a36Sopenharmony_ci * Padlock prefetches extra data so we must provide mapped input buffers. 21662306a36Sopenharmony_ci * Assume there are at least 16 bytes of stack already in use. 21762306a36Sopenharmony_ci */ 21862306a36Sopenharmony_ci u8 buf[AES_BLOCK_SIZE * (MAX_ECB_FETCH_BLOCKS - 1) + PADLOCK_ALIGNMENT - 1]; 21962306a36Sopenharmony_ci u8 *tmp = PTR_ALIGN(&buf[0], PADLOCK_ALIGNMENT); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci memcpy(tmp, in, count * AES_BLOCK_SIZE); 22262306a36Sopenharmony_ci rep_xcrypt_ecb(tmp, out, key, cword, count); 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic u8 *cbc_crypt_copy(const u8 *in, u8 *out, u32 *key, 22662306a36Sopenharmony_ci u8 *iv, struct cword *cword, int count) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci /* 22962306a36Sopenharmony_ci * Padlock prefetches extra data so we must provide mapped input buffers. 23062306a36Sopenharmony_ci * Assume there are at least 16 bytes of stack already in use. 23162306a36Sopenharmony_ci */ 23262306a36Sopenharmony_ci u8 buf[AES_BLOCK_SIZE * (MAX_CBC_FETCH_BLOCKS - 1) + PADLOCK_ALIGNMENT - 1]; 23362306a36Sopenharmony_ci u8 *tmp = PTR_ALIGN(&buf[0], PADLOCK_ALIGNMENT); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci memcpy(tmp, in, count * AES_BLOCK_SIZE); 23662306a36Sopenharmony_ci return rep_xcrypt_cbc(tmp, out, key, iv, cword, count); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic inline void ecb_crypt(const u8 *in, u8 *out, u32 *key, 24062306a36Sopenharmony_ci struct cword *cword, int count) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci /* Padlock in ECB mode fetches at least ecb_fetch_bytes of data. 24362306a36Sopenharmony_ci * We could avoid some copying here but it's probably not worth it. 24462306a36Sopenharmony_ci */ 24562306a36Sopenharmony_ci if (unlikely(offset_in_page(in) + ecb_fetch_bytes > PAGE_SIZE)) { 24662306a36Sopenharmony_ci ecb_crypt_copy(in, out, key, cword, count); 24762306a36Sopenharmony_ci return; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci rep_xcrypt_ecb(in, out, key, cword, count); 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic inline u8 *cbc_crypt(const u8 *in, u8 *out, u32 *key, 25462306a36Sopenharmony_ci u8 *iv, struct cword *cword, int count) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci /* Padlock in CBC mode fetches at least cbc_fetch_bytes of data. */ 25762306a36Sopenharmony_ci if (unlikely(offset_in_page(in) + cbc_fetch_bytes > PAGE_SIZE)) 25862306a36Sopenharmony_ci return cbc_crypt_copy(in, out, key, iv, cword, count); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci return rep_xcrypt_cbc(in, out, key, iv, cword, count); 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key, 26462306a36Sopenharmony_ci void *control_word, u32 count) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci u32 initial = count & (ecb_fetch_blocks - 1); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (count < ecb_fetch_blocks) { 26962306a36Sopenharmony_ci ecb_crypt(input, output, key, control_word, count); 27062306a36Sopenharmony_ci return; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci count -= initial; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (initial) 27662306a36Sopenharmony_ci asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ 27762306a36Sopenharmony_ci : "+S"(input), "+D"(output) 27862306a36Sopenharmony_ci : "d"(control_word), "b"(key), "c"(initial)); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ 28162306a36Sopenharmony_ci : "+S"(input), "+D"(output) 28262306a36Sopenharmony_ci : "d"(control_word), "b"(key), "c"(count)); 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key, 28662306a36Sopenharmony_ci u8 *iv, void *control_word, u32 count) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci u32 initial = count & (cbc_fetch_blocks - 1); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (count < cbc_fetch_blocks) 29162306a36Sopenharmony_ci return cbc_crypt(input, output, key, iv, control_word, count); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci count -= initial; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (initial) 29662306a36Sopenharmony_ci asm volatile (".byte 0xf3,0x0f,0xa7,0xd0" /* rep xcryptcbc */ 29762306a36Sopenharmony_ci : "+S" (input), "+D" (output), "+a" (iv) 29862306a36Sopenharmony_ci : "d" (control_word), "b" (key), "c" (initial)); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci asm volatile (".byte 0xf3,0x0f,0xa7,0xd0" /* rep xcryptcbc */ 30162306a36Sopenharmony_ci : "+S" (input), "+D" (output), "+a" (iv) 30262306a36Sopenharmony_ci : "d" (control_word), "b" (key), "c" (count)); 30362306a36Sopenharmony_ci return iv; 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic void padlock_aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci struct aes_ctx *ctx = aes_ctx(tfm); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci padlock_reset_key(&ctx->cword.encrypt); 31162306a36Sopenharmony_ci ecb_crypt(in, out, ctx->E, &ctx->cword.encrypt, 1); 31262306a36Sopenharmony_ci padlock_store_cword(&ctx->cword.encrypt); 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic void padlock_aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci struct aes_ctx *ctx = aes_ctx(tfm); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci padlock_reset_key(&ctx->cword.encrypt); 32062306a36Sopenharmony_ci ecb_crypt(in, out, ctx->D, &ctx->cword.decrypt, 1); 32162306a36Sopenharmony_ci padlock_store_cword(&ctx->cword.encrypt); 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic struct crypto_alg aes_alg = { 32562306a36Sopenharmony_ci .cra_name = "aes", 32662306a36Sopenharmony_ci .cra_driver_name = "aes-padlock", 32762306a36Sopenharmony_ci .cra_priority = PADLOCK_CRA_PRIORITY, 32862306a36Sopenharmony_ci .cra_flags = CRYPTO_ALG_TYPE_CIPHER, 32962306a36Sopenharmony_ci .cra_blocksize = AES_BLOCK_SIZE, 33062306a36Sopenharmony_ci .cra_ctxsize = sizeof(struct aes_ctx), 33162306a36Sopenharmony_ci .cra_alignmask = PADLOCK_ALIGNMENT - 1, 33262306a36Sopenharmony_ci .cra_module = THIS_MODULE, 33362306a36Sopenharmony_ci .cra_u = { 33462306a36Sopenharmony_ci .cipher = { 33562306a36Sopenharmony_ci .cia_min_keysize = AES_MIN_KEY_SIZE, 33662306a36Sopenharmony_ci .cia_max_keysize = AES_MAX_KEY_SIZE, 33762306a36Sopenharmony_ci .cia_setkey = aes_set_key, 33862306a36Sopenharmony_ci .cia_encrypt = padlock_aes_encrypt, 33962306a36Sopenharmony_ci .cia_decrypt = padlock_aes_decrypt, 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci}; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic int ecb_aes_encrypt(struct skcipher_request *req) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 34762306a36Sopenharmony_ci struct aes_ctx *ctx = skcipher_aes_ctx(tfm); 34862306a36Sopenharmony_ci struct skcipher_walk walk; 34962306a36Sopenharmony_ci unsigned int nbytes; 35062306a36Sopenharmony_ci int err; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci padlock_reset_key(&ctx->cword.encrypt); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci err = skcipher_walk_virt(&walk, req, false); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 35762306a36Sopenharmony_ci padlock_xcrypt_ecb(walk.src.virt.addr, walk.dst.virt.addr, 35862306a36Sopenharmony_ci ctx->E, &ctx->cword.encrypt, 35962306a36Sopenharmony_ci nbytes / AES_BLOCK_SIZE); 36062306a36Sopenharmony_ci nbytes &= AES_BLOCK_SIZE - 1; 36162306a36Sopenharmony_ci err = skcipher_walk_done(&walk, nbytes); 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci padlock_store_cword(&ctx->cword.encrypt); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci return err; 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic int ecb_aes_decrypt(struct skcipher_request *req) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 37262306a36Sopenharmony_ci struct aes_ctx *ctx = skcipher_aes_ctx(tfm); 37362306a36Sopenharmony_ci struct skcipher_walk walk; 37462306a36Sopenharmony_ci unsigned int nbytes; 37562306a36Sopenharmony_ci int err; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci padlock_reset_key(&ctx->cword.decrypt); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci err = skcipher_walk_virt(&walk, req, false); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 38262306a36Sopenharmony_ci padlock_xcrypt_ecb(walk.src.virt.addr, walk.dst.virt.addr, 38362306a36Sopenharmony_ci ctx->D, &ctx->cword.decrypt, 38462306a36Sopenharmony_ci nbytes / AES_BLOCK_SIZE); 38562306a36Sopenharmony_ci nbytes &= AES_BLOCK_SIZE - 1; 38662306a36Sopenharmony_ci err = skcipher_walk_done(&walk, nbytes); 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci padlock_store_cword(&ctx->cword.encrypt); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci return err; 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic struct skcipher_alg ecb_aes_alg = { 39562306a36Sopenharmony_ci .base.cra_name = "ecb(aes)", 39662306a36Sopenharmony_ci .base.cra_driver_name = "ecb-aes-padlock", 39762306a36Sopenharmony_ci .base.cra_priority = PADLOCK_COMPOSITE_PRIORITY, 39862306a36Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 39962306a36Sopenharmony_ci .base.cra_ctxsize = sizeof(struct aes_ctx), 40062306a36Sopenharmony_ci .base.cra_alignmask = PADLOCK_ALIGNMENT - 1, 40162306a36Sopenharmony_ci .base.cra_module = THIS_MODULE, 40262306a36Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 40362306a36Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 40462306a36Sopenharmony_ci .setkey = aes_set_key_skcipher, 40562306a36Sopenharmony_ci .encrypt = ecb_aes_encrypt, 40662306a36Sopenharmony_ci .decrypt = ecb_aes_decrypt, 40762306a36Sopenharmony_ci}; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic int cbc_aes_encrypt(struct skcipher_request *req) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 41262306a36Sopenharmony_ci struct aes_ctx *ctx = skcipher_aes_ctx(tfm); 41362306a36Sopenharmony_ci struct skcipher_walk walk; 41462306a36Sopenharmony_ci unsigned int nbytes; 41562306a36Sopenharmony_ci int err; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci padlock_reset_key(&ctx->cword.encrypt); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci err = skcipher_walk_virt(&walk, req, false); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 42262306a36Sopenharmony_ci u8 *iv = padlock_xcrypt_cbc(walk.src.virt.addr, 42362306a36Sopenharmony_ci walk.dst.virt.addr, ctx->E, 42462306a36Sopenharmony_ci walk.iv, &ctx->cword.encrypt, 42562306a36Sopenharmony_ci nbytes / AES_BLOCK_SIZE); 42662306a36Sopenharmony_ci memcpy(walk.iv, iv, AES_BLOCK_SIZE); 42762306a36Sopenharmony_ci nbytes &= AES_BLOCK_SIZE - 1; 42862306a36Sopenharmony_ci err = skcipher_walk_done(&walk, nbytes); 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci padlock_store_cword(&ctx->cword.decrypt); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci return err; 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic int cbc_aes_decrypt(struct skcipher_request *req) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 43962306a36Sopenharmony_ci struct aes_ctx *ctx = skcipher_aes_ctx(tfm); 44062306a36Sopenharmony_ci struct skcipher_walk walk; 44162306a36Sopenharmony_ci unsigned int nbytes; 44262306a36Sopenharmony_ci int err; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci padlock_reset_key(&ctx->cword.encrypt); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci err = skcipher_walk_virt(&walk, req, false); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 44962306a36Sopenharmony_ci padlock_xcrypt_cbc(walk.src.virt.addr, walk.dst.virt.addr, 45062306a36Sopenharmony_ci ctx->D, walk.iv, &ctx->cword.decrypt, 45162306a36Sopenharmony_ci nbytes / AES_BLOCK_SIZE); 45262306a36Sopenharmony_ci nbytes &= AES_BLOCK_SIZE - 1; 45362306a36Sopenharmony_ci err = skcipher_walk_done(&walk, nbytes); 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci padlock_store_cword(&ctx->cword.encrypt); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci return err; 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic struct skcipher_alg cbc_aes_alg = { 46262306a36Sopenharmony_ci .base.cra_name = "cbc(aes)", 46362306a36Sopenharmony_ci .base.cra_driver_name = "cbc-aes-padlock", 46462306a36Sopenharmony_ci .base.cra_priority = PADLOCK_COMPOSITE_PRIORITY, 46562306a36Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 46662306a36Sopenharmony_ci .base.cra_ctxsize = sizeof(struct aes_ctx), 46762306a36Sopenharmony_ci .base.cra_alignmask = PADLOCK_ALIGNMENT - 1, 46862306a36Sopenharmony_ci .base.cra_module = THIS_MODULE, 46962306a36Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 47062306a36Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 47162306a36Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 47262306a36Sopenharmony_ci .setkey = aes_set_key_skcipher, 47362306a36Sopenharmony_ci .encrypt = cbc_aes_encrypt, 47462306a36Sopenharmony_ci .decrypt = cbc_aes_decrypt, 47562306a36Sopenharmony_ci}; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic const struct x86_cpu_id padlock_cpu_id[] = { 47862306a36Sopenharmony_ci X86_MATCH_FEATURE(X86_FEATURE_XCRYPT, NULL), 47962306a36Sopenharmony_ci {} 48062306a36Sopenharmony_ci}; 48162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(x86cpu, padlock_cpu_id); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cistatic int __init padlock_init(void) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci int ret; 48662306a36Sopenharmony_ci struct cpuinfo_x86 *c = &cpu_data(0); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci if (!x86_match_cpu(padlock_cpu_id)) 48962306a36Sopenharmony_ci return -ENODEV; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci if (!boot_cpu_has(X86_FEATURE_XCRYPT_EN)) { 49262306a36Sopenharmony_ci printk(KERN_NOTICE PFX "VIA PadLock detected, but not enabled. Hmm, strange...\n"); 49362306a36Sopenharmony_ci return -ENODEV; 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci if ((ret = crypto_register_alg(&aes_alg)) != 0) 49762306a36Sopenharmony_ci goto aes_err; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci if ((ret = crypto_register_skcipher(&ecb_aes_alg)) != 0) 50062306a36Sopenharmony_ci goto ecb_aes_err; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci if ((ret = crypto_register_skcipher(&cbc_aes_alg)) != 0) 50362306a36Sopenharmony_ci goto cbc_aes_err; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci printk(KERN_NOTICE PFX "Using VIA PadLock ACE for AES algorithm.\n"); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci if (c->x86 == 6 && c->x86_model == 15 && c->x86_stepping == 2) { 50862306a36Sopenharmony_ci ecb_fetch_blocks = MAX_ECB_FETCH_BLOCKS; 50962306a36Sopenharmony_ci cbc_fetch_blocks = MAX_CBC_FETCH_BLOCKS; 51062306a36Sopenharmony_ci printk(KERN_NOTICE PFX "VIA Nano stepping 2 detected: enabling workaround.\n"); 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ciout: 51462306a36Sopenharmony_ci return ret; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_cicbc_aes_err: 51762306a36Sopenharmony_ci crypto_unregister_skcipher(&ecb_aes_alg); 51862306a36Sopenharmony_ciecb_aes_err: 51962306a36Sopenharmony_ci crypto_unregister_alg(&aes_alg); 52062306a36Sopenharmony_ciaes_err: 52162306a36Sopenharmony_ci printk(KERN_ERR PFX "VIA PadLock AES initialization failed.\n"); 52262306a36Sopenharmony_ci goto out; 52362306a36Sopenharmony_ci} 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_cistatic void __exit padlock_fini(void) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci crypto_unregister_skcipher(&cbc_aes_alg); 52862306a36Sopenharmony_ci crypto_unregister_skcipher(&ecb_aes_alg); 52962306a36Sopenharmony_ci crypto_unregister_alg(&aes_alg); 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cimodule_init(padlock_init); 53362306a36Sopenharmony_cimodule_exit(padlock_fini); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ciMODULE_DESCRIPTION("VIA PadLock AES algorithm support"); 53662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 53762306a36Sopenharmony_ciMODULE_AUTHOR("Michal Ludvig"); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("aes"); 540