18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Cryptographic API. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Support for VIA PadLock hardware crypto engine. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (c) 2004 Michal Ludvig <michal@logix.cz> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <crypto/algapi.h> 128c2ecf20Sopenharmony_ci#include <crypto/aes.h> 138c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h> 148c2ecf20Sopenharmony_ci#include <crypto/padlock.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/init.h> 178c2ecf20Sopenharmony_ci#include <linux/types.h> 188c2ecf20Sopenharmony_ci#include <linux/errno.h> 198c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 208c2ecf20Sopenharmony_ci#include <linux/kernel.h> 218c2ecf20Sopenharmony_ci#include <linux/mm.h> 228c2ecf20Sopenharmony_ci#include <linux/percpu.h> 238c2ecf20Sopenharmony_ci#include <linux/smp.h> 248c2ecf20Sopenharmony_ci#include <linux/slab.h> 258c2ecf20Sopenharmony_ci#include <asm/cpu_device_id.h> 268c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 278c2ecf20Sopenharmony_ci#include <asm/processor.h> 288c2ecf20Sopenharmony_ci#include <asm/fpu/api.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* 318c2ecf20Sopenharmony_ci * Number of data blocks actually fetched for each xcrypt insn. 328c2ecf20Sopenharmony_ci * Processors with prefetch errata will fetch extra blocks. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_cistatic unsigned int ecb_fetch_blocks = 2; 358c2ecf20Sopenharmony_ci#define MAX_ECB_FETCH_BLOCKS (8) 368c2ecf20Sopenharmony_ci#define ecb_fetch_bytes (ecb_fetch_blocks * AES_BLOCK_SIZE) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic unsigned int cbc_fetch_blocks = 1; 398c2ecf20Sopenharmony_ci#define MAX_CBC_FETCH_BLOCKS (4) 408c2ecf20Sopenharmony_ci#define cbc_fetch_bytes (cbc_fetch_blocks * AES_BLOCK_SIZE) 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* Control word. */ 438c2ecf20Sopenharmony_cistruct cword { 448c2ecf20Sopenharmony_ci unsigned int __attribute__ ((__packed__)) 458c2ecf20Sopenharmony_ci rounds:4, 468c2ecf20Sopenharmony_ci algo:3, 478c2ecf20Sopenharmony_ci keygen:1, 488c2ecf20Sopenharmony_ci interm:1, 498c2ecf20Sopenharmony_ci encdec:1, 508c2ecf20Sopenharmony_ci ksize:2; 518c2ecf20Sopenharmony_ci} __attribute__ ((__aligned__(PADLOCK_ALIGNMENT))); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* Whenever making any changes to the following 548c2ecf20Sopenharmony_ci * structure *make sure* you keep E, d_data 558c2ecf20Sopenharmony_ci * and cword aligned on 16 Bytes boundaries and 568c2ecf20Sopenharmony_ci * the Hardware can access 16 * 16 bytes of E and d_data 578c2ecf20Sopenharmony_ci * (only the first 15 * 16 bytes matter but the HW reads 588c2ecf20Sopenharmony_ci * more). 598c2ecf20Sopenharmony_ci */ 608c2ecf20Sopenharmony_cistruct aes_ctx { 618c2ecf20Sopenharmony_ci u32 E[AES_MAX_KEYLENGTH_U32] 628c2ecf20Sopenharmony_ci __attribute__ ((__aligned__(PADLOCK_ALIGNMENT))); 638c2ecf20Sopenharmony_ci u32 d_data[AES_MAX_KEYLENGTH_U32] 648c2ecf20Sopenharmony_ci __attribute__ ((__aligned__(PADLOCK_ALIGNMENT))); 658c2ecf20Sopenharmony_ci struct { 668c2ecf20Sopenharmony_ci struct cword encrypt; 678c2ecf20Sopenharmony_ci struct cword decrypt; 688c2ecf20Sopenharmony_ci } cword; 698c2ecf20Sopenharmony_ci u32 *D; 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(struct cword *, paes_last_cword); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/* Tells whether the ACE is capable to generate 758c2ecf20Sopenharmony_ci the extended key for a given key_len. */ 768c2ecf20Sopenharmony_cistatic inline int 778c2ecf20Sopenharmony_ciaes_hw_extkey_available(uint8_t key_len) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci /* TODO: We should check the actual CPU model/stepping 808c2ecf20Sopenharmony_ci as it's possible that the capability will be 818c2ecf20Sopenharmony_ci added in the next CPU revisions. */ 828c2ecf20Sopenharmony_ci if (key_len == 16) 838c2ecf20Sopenharmony_ci return 1; 848c2ecf20Sopenharmony_ci return 0; 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic inline struct aes_ctx *aes_ctx_common(void *ctx) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci unsigned long addr = (unsigned long)ctx; 908c2ecf20Sopenharmony_ci unsigned long align = PADLOCK_ALIGNMENT; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci if (align <= crypto_tfm_ctx_alignment()) 938c2ecf20Sopenharmony_ci align = 1; 948c2ecf20Sopenharmony_ci return (struct aes_ctx *)ALIGN(addr, align); 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic inline struct aes_ctx *aes_ctx(struct crypto_tfm *tfm) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci return aes_ctx_common(crypto_tfm_ctx(tfm)); 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic inline struct aes_ctx *skcipher_aes_ctx(struct crypto_skcipher *tfm) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci return aes_ctx_common(crypto_skcipher_ctx(tfm)); 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, 1088c2ecf20Sopenharmony_ci unsigned int key_len) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci struct aes_ctx *ctx = aes_ctx(tfm); 1118c2ecf20Sopenharmony_ci const __le32 *key = (const __le32 *)in_key; 1128c2ecf20Sopenharmony_ci struct crypto_aes_ctx gen_aes; 1138c2ecf20Sopenharmony_ci int cpu; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci if (key_len % 8) 1168c2ecf20Sopenharmony_ci return -EINVAL; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci /* 1198c2ecf20Sopenharmony_ci * If the hardware is capable of generating the extended key 1208c2ecf20Sopenharmony_ci * itself we must supply the plain key for both encryption 1218c2ecf20Sopenharmony_ci * and decryption. 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_ci ctx->D = ctx->E; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci ctx->E[0] = le32_to_cpu(key[0]); 1268c2ecf20Sopenharmony_ci ctx->E[1] = le32_to_cpu(key[1]); 1278c2ecf20Sopenharmony_ci ctx->E[2] = le32_to_cpu(key[2]); 1288c2ecf20Sopenharmony_ci ctx->E[3] = le32_to_cpu(key[3]); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* Prepare control words. */ 1318c2ecf20Sopenharmony_ci memset(&ctx->cword, 0, sizeof(ctx->cword)); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci ctx->cword.decrypt.encdec = 1; 1348c2ecf20Sopenharmony_ci ctx->cword.encrypt.rounds = 10 + (key_len - 16) / 4; 1358c2ecf20Sopenharmony_ci ctx->cword.decrypt.rounds = ctx->cword.encrypt.rounds; 1368c2ecf20Sopenharmony_ci ctx->cword.encrypt.ksize = (key_len - 16) / 8; 1378c2ecf20Sopenharmony_ci ctx->cword.decrypt.ksize = ctx->cword.encrypt.ksize; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci /* Don't generate extended keys if the hardware can do it. */ 1408c2ecf20Sopenharmony_ci if (aes_hw_extkey_available(key_len)) 1418c2ecf20Sopenharmony_ci goto ok; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci ctx->D = ctx->d_data; 1448c2ecf20Sopenharmony_ci ctx->cword.encrypt.keygen = 1; 1458c2ecf20Sopenharmony_ci ctx->cword.decrypt.keygen = 1; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci if (aes_expandkey(&gen_aes, in_key, key_len)) 1488c2ecf20Sopenharmony_ci return -EINVAL; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci memcpy(ctx->E, gen_aes.key_enc, AES_MAX_KEYLENGTH); 1518c2ecf20Sopenharmony_ci memcpy(ctx->D, gen_aes.key_dec, AES_MAX_KEYLENGTH); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ciok: 1548c2ecf20Sopenharmony_ci for_each_online_cpu(cpu) 1558c2ecf20Sopenharmony_ci if (&ctx->cword.encrypt == per_cpu(paes_last_cword, cpu) || 1568c2ecf20Sopenharmony_ci &ctx->cword.decrypt == per_cpu(paes_last_cword, cpu)) 1578c2ecf20Sopenharmony_ci per_cpu(paes_last_cword, cpu) = NULL; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci return 0; 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic int aes_set_key_skcipher(struct crypto_skcipher *tfm, const u8 *in_key, 1638c2ecf20Sopenharmony_ci unsigned int key_len) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci return aes_set_key(crypto_skcipher_tfm(tfm), in_key, key_len); 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci/* ====== Encryption/decryption routines ====== */ 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci/* These are the real call to PadLock. */ 1718c2ecf20Sopenharmony_cistatic inline void padlock_reset_key(struct cword *cword) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci int cpu = raw_smp_processor_id(); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (cword != per_cpu(paes_last_cword, cpu)) 1768c2ecf20Sopenharmony_ci#ifndef CONFIG_X86_64 1778c2ecf20Sopenharmony_ci asm volatile ("pushfl; popfl"); 1788c2ecf20Sopenharmony_ci#else 1798c2ecf20Sopenharmony_ci asm volatile ("pushfq; popfq"); 1808c2ecf20Sopenharmony_ci#endif 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic inline void padlock_store_cword(struct cword *cword) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci per_cpu(paes_last_cword, raw_smp_processor_id()) = cword; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci/* 1898c2ecf20Sopenharmony_ci * While the padlock instructions don't use FP/SSE registers, they 1908c2ecf20Sopenharmony_ci * generate a spurious DNA fault when CR0.TS is '1'. Fortunately, 1918c2ecf20Sopenharmony_ci * the kernel doesn't use CR0.TS. 1928c2ecf20Sopenharmony_ci */ 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic inline void rep_xcrypt_ecb(const u8 *input, u8 *output, void *key, 1958c2ecf20Sopenharmony_ci struct cword *control_word, int count) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ 1988c2ecf20Sopenharmony_ci : "+S"(input), "+D"(output) 1998c2ecf20Sopenharmony_ci : "d"(control_word), "b"(key), "c"(count)); 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic inline u8 *rep_xcrypt_cbc(const u8 *input, u8 *output, void *key, 2038c2ecf20Sopenharmony_ci u8 *iv, struct cword *control_word, int count) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci asm volatile (".byte 0xf3,0x0f,0xa7,0xd0" /* rep xcryptcbc */ 2068c2ecf20Sopenharmony_ci : "+S" (input), "+D" (output), "+a" (iv) 2078c2ecf20Sopenharmony_ci : "d" (control_word), "b" (key), "c" (count)); 2088c2ecf20Sopenharmony_ci return iv; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic void ecb_crypt_copy(const u8 *in, u8 *out, u32 *key, 2128c2ecf20Sopenharmony_ci struct cword *cword, int count) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci /* 2158c2ecf20Sopenharmony_ci * Padlock prefetches extra data so we must provide mapped input buffers. 2168c2ecf20Sopenharmony_ci * Assume there are at least 16 bytes of stack already in use. 2178c2ecf20Sopenharmony_ci */ 2188c2ecf20Sopenharmony_ci u8 buf[AES_BLOCK_SIZE * (MAX_ECB_FETCH_BLOCKS - 1) + PADLOCK_ALIGNMENT - 1]; 2198c2ecf20Sopenharmony_ci u8 *tmp = PTR_ALIGN(&buf[0], PADLOCK_ALIGNMENT); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci memcpy(tmp, in, count * AES_BLOCK_SIZE); 2228c2ecf20Sopenharmony_ci rep_xcrypt_ecb(tmp, out, key, cword, count); 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic u8 *cbc_crypt_copy(const u8 *in, u8 *out, u32 *key, 2268c2ecf20Sopenharmony_ci u8 *iv, struct cword *cword, int count) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci /* 2298c2ecf20Sopenharmony_ci * Padlock prefetches extra data so we must provide mapped input buffers. 2308c2ecf20Sopenharmony_ci * Assume there are at least 16 bytes of stack already in use. 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_ci u8 buf[AES_BLOCK_SIZE * (MAX_CBC_FETCH_BLOCKS - 1) + PADLOCK_ALIGNMENT - 1]; 2338c2ecf20Sopenharmony_ci u8 *tmp = PTR_ALIGN(&buf[0], PADLOCK_ALIGNMENT); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci memcpy(tmp, in, count * AES_BLOCK_SIZE); 2368c2ecf20Sopenharmony_ci return rep_xcrypt_cbc(tmp, out, key, iv, cword, count); 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic inline void ecb_crypt(const u8 *in, u8 *out, u32 *key, 2408c2ecf20Sopenharmony_ci struct cword *cword, int count) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci /* Padlock in ECB mode fetches at least ecb_fetch_bytes of data. 2438c2ecf20Sopenharmony_ci * We could avoid some copying here but it's probably not worth it. 2448c2ecf20Sopenharmony_ci */ 2458c2ecf20Sopenharmony_ci if (unlikely(offset_in_page(in) + ecb_fetch_bytes > PAGE_SIZE)) { 2468c2ecf20Sopenharmony_ci ecb_crypt_copy(in, out, key, cword, count); 2478c2ecf20Sopenharmony_ci return; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci rep_xcrypt_ecb(in, out, key, cword, count); 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic inline u8 *cbc_crypt(const u8 *in, u8 *out, u32 *key, 2548c2ecf20Sopenharmony_ci u8 *iv, struct cword *cword, int count) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci /* Padlock in CBC mode fetches at least cbc_fetch_bytes of data. */ 2578c2ecf20Sopenharmony_ci if (unlikely(offset_in_page(in) + cbc_fetch_bytes > PAGE_SIZE)) 2588c2ecf20Sopenharmony_ci return cbc_crypt_copy(in, out, key, iv, cword, count); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci return rep_xcrypt_cbc(in, out, key, iv, cword, count); 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key, 2648c2ecf20Sopenharmony_ci void *control_word, u32 count) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci u32 initial = count & (ecb_fetch_blocks - 1); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (count < ecb_fetch_blocks) { 2698c2ecf20Sopenharmony_ci ecb_crypt(input, output, key, control_word, count); 2708c2ecf20Sopenharmony_ci return; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci count -= initial; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (initial) 2768c2ecf20Sopenharmony_ci asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ 2778c2ecf20Sopenharmony_ci : "+S"(input), "+D"(output) 2788c2ecf20Sopenharmony_ci : "d"(control_word), "b"(key), "c"(initial)); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ 2818c2ecf20Sopenharmony_ci : "+S"(input), "+D"(output) 2828c2ecf20Sopenharmony_ci : "d"(control_word), "b"(key), "c"(count)); 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key, 2868c2ecf20Sopenharmony_ci u8 *iv, void *control_word, u32 count) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci u32 initial = count & (cbc_fetch_blocks - 1); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci if (count < cbc_fetch_blocks) 2918c2ecf20Sopenharmony_ci return cbc_crypt(input, output, key, iv, control_word, count); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci count -= initial; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (initial) 2968c2ecf20Sopenharmony_ci asm volatile (".byte 0xf3,0x0f,0xa7,0xd0" /* rep xcryptcbc */ 2978c2ecf20Sopenharmony_ci : "+S" (input), "+D" (output), "+a" (iv) 2988c2ecf20Sopenharmony_ci : "d" (control_word), "b" (key), "c" (initial)); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci asm volatile (".byte 0xf3,0x0f,0xa7,0xd0" /* rep xcryptcbc */ 3018c2ecf20Sopenharmony_ci : "+S" (input), "+D" (output), "+a" (iv) 3028c2ecf20Sopenharmony_ci : "d" (control_word), "b" (key), "c" (count)); 3038c2ecf20Sopenharmony_ci return iv; 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic void padlock_aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci struct aes_ctx *ctx = aes_ctx(tfm); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci padlock_reset_key(&ctx->cword.encrypt); 3118c2ecf20Sopenharmony_ci ecb_crypt(in, out, ctx->E, &ctx->cword.encrypt, 1); 3128c2ecf20Sopenharmony_ci padlock_store_cword(&ctx->cword.encrypt); 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_cistatic void padlock_aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci struct aes_ctx *ctx = aes_ctx(tfm); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci padlock_reset_key(&ctx->cword.encrypt); 3208c2ecf20Sopenharmony_ci ecb_crypt(in, out, ctx->D, &ctx->cword.decrypt, 1); 3218c2ecf20Sopenharmony_ci padlock_store_cword(&ctx->cword.encrypt); 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic struct crypto_alg aes_alg = { 3258c2ecf20Sopenharmony_ci .cra_name = "aes", 3268c2ecf20Sopenharmony_ci .cra_driver_name = "aes-padlock", 3278c2ecf20Sopenharmony_ci .cra_priority = PADLOCK_CRA_PRIORITY, 3288c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_TYPE_CIPHER, 3298c2ecf20Sopenharmony_ci .cra_blocksize = AES_BLOCK_SIZE, 3308c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct aes_ctx), 3318c2ecf20Sopenharmony_ci .cra_alignmask = PADLOCK_ALIGNMENT - 1, 3328c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 3338c2ecf20Sopenharmony_ci .cra_u = { 3348c2ecf20Sopenharmony_ci .cipher = { 3358c2ecf20Sopenharmony_ci .cia_min_keysize = AES_MIN_KEY_SIZE, 3368c2ecf20Sopenharmony_ci .cia_max_keysize = AES_MAX_KEY_SIZE, 3378c2ecf20Sopenharmony_ci .cia_setkey = aes_set_key, 3388c2ecf20Sopenharmony_ci .cia_encrypt = padlock_aes_encrypt, 3398c2ecf20Sopenharmony_ci .cia_decrypt = padlock_aes_decrypt, 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci}; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic int ecb_aes_encrypt(struct skcipher_request *req) 3458c2ecf20Sopenharmony_ci{ 3468c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 3478c2ecf20Sopenharmony_ci struct aes_ctx *ctx = skcipher_aes_ctx(tfm); 3488c2ecf20Sopenharmony_ci struct skcipher_walk walk; 3498c2ecf20Sopenharmony_ci unsigned int nbytes; 3508c2ecf20Sopenharmony_ci int err; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci padlock_reset_key(&ctx->cword.encrypt); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci err = skcipher_walk_virt(&walk, req, false); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 3578c2ecf20Sopenharmony_ci padlock_xcrypt_ecb(walk.src.virt.addr, walk.dst.virt.addr, 3588c2ecf20Sopenharmony_ci ctx->E, &ctx->cword.encrypt, 3598c2ecf20Sopenharmony_ci nbytes / AES_BLOCK_SIZE); 3608c2ecf20Sopenharmony_ci nbytes &= AES_BLOCK_SIZE - 1; 3618c2ecf20Sopenharmony_ci err = skcipher_walk_done(&walk, nbytes); 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci padlock_store_cword(&ctx->cword.encrypt); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci return err; 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistatic int ecb_aes_decrypt(struct skcipher_request *req) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 3728c2ecf20Sopenharmony_ci struct aes_ctx *ctx = skcipher_aes_ctx(tfm); 3738c2ecf20Sopenharmony_ci struct skcipher_walk walk; 3748c2ecf20Sopenharmony_ci unsigned int nbytes; 3758c2ecf20Sopenharmony_ci int err; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci padlock_reset_key(&ctx->cword.decrypt); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci err = skcipher_walk_virt(&walk, req, false); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 3828c2ecf20Sopenharmony_ci padlock_xcrypt_ecb(walk.src.virt.addr, walk.dst.virt.addr, 3838c2ecf20Sopenharmony_ci ctx->D, &ctx->cword.decrypt, 3848c2ecf20Sopenharmony_ci nbytes / AES_BLOCK_SIZE); 3858c2ecf20Sopenharmony_ci nbytes &= AES_BLOCK_SIZE - 1; 3868c2ecf20Sopenharmony_ci err = skcipher_walk_done(&walk, nbytes); 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci padlock_store_cword(&ctx->cword.encrypt); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci return err; 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic struct skcipher_alg ecb_aes_alg = { 3958c2ecf20Sopenharmony_ci .base.cra_name = "ecb(aes)", 3968c2ecf20Sopenharmony_ci .base.cra_driver_name = "ecb-aes-padlock", 3978c2ecf20Sopenharmony_ci .base.cra_priority = PADLOCK_COMPOSITE_PRIORITY, 3988c2ecf20Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 3998c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct aes_ctx), 4008c2ecf20Sopenharmony_ci .base.cra_alignmask = PADLOCK_ALIGNMENT - 1, 4018c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 4028c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 4038c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 4048c2ecf20Sopenharmony_ci .setkey = aes_set_key_skcipher, 4058c2ecf20Sopenharmony_ci .encrypt = ecb_aes_encrypt, 4068c2ecf20Sopenharmony_ci .decrypt = ecb_aes_decrypt, 4078c2ecf20Sopenharmony_ci}; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic int cbc_aes_encrypt(struct skcipher_request *req) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 4128c2ecf20Sopenharmony_ci struct aes_ctx *ctx = skcipher_aes_ctx(tfm); 4138c2ecf20Sopenharmony_ci struct skcipher_walk walk; 4148c2ecf20Sopenharmony_ci unsigned int nbytes; 4158c2ecf20Sopenharmony_ci int err; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci padlock_reset_key(&ctx->cword.encrypt); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci err = skcipher_walk_virt(&walk, req, false); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 4228c2ecf20Sopenharmony_ci u8 *iv = padlock_xcrypt_cbc(walk.src.virt.addr, 4238c2ecf20Sopenharmony_ci walk.dst.virt.addr, ctx->E, 4248c2ecf20Sopenharmony_ci walk.iv, &ctx->cword.encrypt, 4258c2ecf20Sopenharmony_ci nbytes / AES_BLOCK_SIZE); 4268c2ecf20Sopenharmony_ci memcpy(walk.iv, iv, AES_BLOCK_SIZE); 4278c2ecf20Sopenharmony_ci nbytes &= AES_BLOCK_SIZE - 1; 4288c2ecf20Sopenharmony_ci err = skcipher_walk_done(&walk, nbytes); 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci padlock_store_cword(&ctx->cword.decrypt); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci return err; 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic int cbc_aes_decrypt(struct skcipher_request *req) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 4398c2ecf20Sopenharmony_ci struct aes_ctx *ctx = skcipher_aes_ctx(tfm); 4408c2ecf20Sopenharmony_ci struct skcipher_walk walk; 4418c2ecf20Sopenharmony_ci unsigned int nbytes; 4428c2ecf20Sopenharmony_ci int err; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci padlock_reset_key(&ctx->cword.encrypt); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci err = skcipher_walk_virt(&walk, req, false); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 4498c2ecf20Sopenharmony_ci padlock_xcrypt_cbc(walk.src.virt.addr, walk.dst.virt.addr, 4508c2ecf20Sopenharmony_ci ctx->D, walk.iv, &ctx->cword.decrypt, 4518c2ecf20Sopenharmony_ci nbytes / AES_BLOCK_SIZE); 4528c2ecf20Sopenharmony_ci nbytes &= AES_BLOCK_SIZE - 1; 4538c2ecf20Sopenharmony_ci err = skcipher_walk_done(&walk, nbytes); 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci padlock_store_cword(&ctx->cword.encrypt); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci return err; 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic struct skcipher_alg cbc_aes_alg = { 4628c2ecf20Sopenharmony_ci .base.cra_name = "cbc(aes)", 4638c2ecf20Sopenharmony_ci .base.cra_driver_name = "cbc-aes-padlock", 4648c2ecf20Sopenharmony_ci .base.cra_priority = PADLOCK_COMPOSITE_PRIORITY, 4658c2ecf20Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 4668c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct aes_ctx), 4678c2ecf20Sopenharmony_ci .base.cra_alignmask = PADLOCK_ALIGNMENT - 1, 4688c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 4698c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 4708c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 4718c2ecf20Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 4728c2ecf20Sopenharmony_ci .setkey = aes_set_key_skcipher, 4738c2ecf20Sopenharmony_ci .encrypt = cbc_aes_encrypt, 4748c2ecf20Sopenharmony_ci .decrypt = cbc_aes_decrypt, 4758c2ecf20Sopenharmony_ci}; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_cistatic const struct x86_cpu_id padlock_cpu_id[] = { 4788c2ecf20Sopenharmony_ci X86_MATCH_FEATURE(X86_FEATURE_XCRYPT, NULL), 4798c2ecf20Sopenharmony_ci {} 4808c2ecf20Sopenharmony_ci}; 4818c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(x86cpu, padlock_cpu_id); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic int __init padlock_init(void) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci int ret; 4868c2ecf20Sopenharmony_ci struct cpuinfo_x86 *c = &cpu_data(0); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci if (!x86_match_cpu(padlock_cpu_id)) 4898c2ecf20Sopenharmony_ci return -ENODEV; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (!boot_cpu_has(X86_FEATURE_XCRYPT_EN)) { 4928c2ecf20Sopenharmony_ci printk(KERN_NOTICE PFX "VIA PadLock detected, but not enabled. Hmm, strange...\n"); 4938c2ecf20Sopenharmony_ci return -ENODEV; 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if ((ret = crypto_register_alg(&aes_alg)) != 0) 4978c2ecf20Sopenharmony_ci goto aes_err; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if ((ret = crypto_register_skcipher(&ecb_aes_alg)) != 0) 5008c2ecf20Sopenharmony_ci goto ecb_aes_err; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci if ((ret = crypto_register_skcipher(&cbc_aes_alg)) != 0) 5038c2ecf20Sopenharmony_ci goto cbc_aes_err; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci printk(KERN_NOTICE PFX "Using VIA PadLock ACE for AES algorithm.\n"); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (c->x86 == 6 && c->x86_model == 15 && c->x86_stepping == 2) { 5088c2ecf20Sopenharmony_ci ecb_fetch_blocks = MAX_ECB_FETCH_BLOCKS; 5098c2ecf20Sopenharmony_ci cbc_fetch_blocks = MAX_CBC_FETCH_BLOCKS; 5108c2ecf20Sopenharmony_ci printk(KERN_NOTICE PFX "VIA Nano stepping 2 detected: enabling workaround.\n"); 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ciout: 5148c2ecf20Sopenharmony_ci return ret; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cicbc_aes_err: 5178c2ecf20Sopenharmony_ci crypto_unregister_skcipher(&ecb_aes_alg); 5188c2ecf20Sopenharmony_ciecb_aes_err: 5198c2ecf20Sopenharmony_ci crypto_unregister_alg(&aes_alg); 5208c2ecf20Sopenharmony_ciaes_err: 5218c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "VIA PadLock AES initialization failed.\n"); 5228c2ecf20Sopenharmony_ci goto out; 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic void __exit padlock_fini(void) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci crypto_unregister_skcipher(&cbc_aes_alg); 5288c2ecf20Sopenharmony_ci crypto_unregister_skcipher(&ecb_aes_alg); 5298c2ecf20Sopenharmony_ci crypto_unregister_alg(&aes_alg); 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cimodule_init(padlock_init); 5338c2ecf20Sopenharmony_cimodule_exit(padlock_fini); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("VIA PadLock AES algorithm support"); 5368c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 5378c2ecf20Sopenharmony_ciMODULE_AUTHOR("Michal Ludvig"); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("aes"); 540