18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Glue code for AES implementation for SPE instructions (PPC) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Based on generic implementation. The assembler module takes care 68c2ecf20Sopenharmony_ci * about the SPE registers so it can run from interrupt context. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright (c) 2015 Markus Stockhausen <stockhausen@collogia.de> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <crypto/aes.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci#include <linux/types.h> 158c2ecf20Sopenharmony_ci#include <linux/errno.h> 168c2ecf20Sopenharmony_ci#include <linux/crypto.h> 178c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 188c2ecf20Sopenharmony_ci#include <asm/switch_to.h> 198c2ecf20Sopenharmony_ci#include <crypto/algapi.h> 208c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h> 218c2ecf20Sopenharmony_ci#include <crypto/xts.h> 228c2ecf20Sopenharmony_ci#include <crypto/gf128mul.h> 238c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* 268c2ecf20Sopenharmony_ci * MAX_BYTES defines the number of bytes that are allowed to be processed 278c2ecf20Sopenharmony_ci * between preempt_disable() and preempt_enable(). e500 cores can issue two 288c2ecf20Sopenharmony_ci * instructions per clock cycle using one 32/64 bit unit (SU1) and one 32 298c2ecf20Sopenharmony_ci * bit unit (SU2). One of these can be a memory access that is executed via 308c2ecf20Sopenharmony_ci * a single load and store unit (LSU). XTS-AES-256 takes ~780 operations per 318c2ecf20Sopenharmony_ci * 16 byte block block or 25 cycles per byte. Thus 768 bytes of input data 328c2ecf20Sopenharmony_ci * will need an estimated maximum of 20,000 cycles. Headroom for cache misses 338c2ecf20Sopenharmony_ci * included. Even with the low end model clocked at 667 MHz this equals to a 348c2ecf20Sopenharmony_ci * critical time window of less than 30us. The value has been chosen to 358c2ecf20Sopenharmony_ci * process a 512 byte disk block in one or a large 1400 bytes IPsec network 368c2ecf20Sopenharmony_ci * packet in two runs. 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_ci#define MAX_BYTES 768 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistruct ppc_aes_ctx { 428c2ecf20Sopenharmony_ci u32 key_enc[AES_MAX_KEYLENGTH_U32]; 438c2ecf20Sopenharmony_ci u32 key_dec[AES_MAX_KEYLENGTH_U32]; 448c2ecf20Sopenharmony_ci u32 rounds; 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistruct ppc_xts_ctx { 488c2ecf20Sopenharmony_ci u32 key_enc[AES_MAX_KEYLENGTH_U32]; 498c2ecf20Sopenharmony_ci u32 key_dec[AES_MAX_KEYLENGTH_U32]; 508c2ecf20Sopenharmony_ci u32 key_twk[AES_MAX_KEYLENGTH_U32]; 518c2ecf20Sopenharmony_ci u32 rounds; 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ciextern void ppc_encrypt_aes(u8 *out, const u8 *in, u32 *key_enc, u32 rounds); 558c2ecf20Sopenharmony_ciextern void ppc_decrypt_aes(u8 *out, const u8 *in, u32 *key_dec, u32 rounds); 568c2ecf20Sopenharmony_ciextern void ppc_encrypt_ecb(u8 *out, const u8 *in, u32 *key_enc, u32 rounds, 578c2ecf20Sopenharmony_ci u32 bytes); 588c2ecf20Sopenharmony_ciextern void ppc_decrypt_ecb(u8 *out, const u8 *in, u32 *key_dec, u32 rounds, 598c2ecf20Sopenharmony_ci u32 bytes); 608c2ecf20Sopenharmony_ciextern void ppc_encrypt_cbc(u8 *out, const u8 *in, u32 *key_enc, u32 rounds, 618c2ecf20Sopenharmony_ci u32 bytes, u8 *iv); 628c2ecf20Sopenharmony_ciextern void ppc_decrypt_cbc(u8 *out, const u8 *in, u32 *key_dec, u32 rounds, 638c2ecf20Sopenharmony_ci u32 bytes, u8 *iv); 648c2ecf20Sopenharmony_ciextern void ppc_crypt_ctr (u8 *out, const u8 *in, u32 *key_enc, u32 rounds, 658c2ecf20Sopenharmony_ci u32 bytes, u8 *iv); 668c2ecf20Sopenharmony_ciextern void ppc_encrypt_xts(u8 *out, const u8 *in, u32 *key_enc, u32 rounds, 678c2ecf20Sopenharmony_ci u32 bytes, u8 *iv, u32 *key_twk); 688c2ecf20Sopenharmony_ciextern void ppc_decrypt_xts(u8 *out, const u8 *in, u32 *key_dec, u32 rounds, 698c2ecf20Sopenharmony_ci u32 bytes, u8 *iv, u32 *key_twk); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ciextern void ppc_expand_key_128(u32 *key_enc, const u8 *key); 728c2ecf20Sopenharmony_ciextern void ppc_expand_key_192(u32 *key_enc, const u8 *key); 738c2ecf20Sopenharmony_ciextern void ppc_expand_key_256(u32 *key_enc, const u8 *key); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ciextern void ppc_generate_decrypt_key(u32 *key_dec,u32 *key_enc, 768c2ecf20Sopenharmony_ci unsigned int key_len); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic void spe_begin(void) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci /* disable preemption and save users SPE registers if required */ 818c2ecf20Sopenharmony_ci preempt_disable(); 828c2ecf20Sopenharmony_ci enable_kernel_spe(); 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic void spe_end(void) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci disable_kernel_spe(); 888c2ecf20Sopenharmony_ci /* reenable preemption */ 898c2ecf20Sopenharmony_ci preempt_enable(); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic int ppc_aes_setkey(struct crypto_tfm *tfm, const u8 *in_key, 938c2ecf20Sopenharmony_ci unsigned int key_len) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci struct ppc_aes_ctx *ctx = crypto_tfm_ctx(tfm); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci switch (key_len) { 988c2ecf20Sopenharmony_ci case AES_KEYSIZE_128: 998c2ecf20Sopenharmony_ci ctx->rounds = 4; 1008c2ecf20Sopenharmony_ci ppc_expand_key_128(ctx->key_enc, in_key); 1018c2ecf20Sopenharmony_ci break; 1028c2ecf20Sopenharmony_ci case AES_KEYSIZE_192: 1038c2ecf20Sopenharmony_ci ctx->rounds = 5; 1048c2ecf20Sopenharmony_ci ppc_expand_key_192(ctx->key_enc, in_key); 1058c2ecf20Sopenharmony_ci break; 1068c2ecf20Sopenharmony_ci case AES_KEYSIZE_256: 1078c2ecf20Sopenharmony_ci ctx->rounds = 6; 1088c2ecf20Sopenharmony_ci ppc_expand_key_256(ctx->key_enc, in_key); 1098c2ecf20Sopenharmony_ci break; 1108c2ecf20Sopenharmony_ci default: 1118c2ecf20Sopenharmony_ci return -EINVAL; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci ppc_generate_decrypt_key(ctx->key_dec, ctx->key_enc, key_len); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci return 0; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic int ppc_aes_setkey_skcipher(struct crypto_skcipher *tfm, 1208c2ecf20Sopenharmony_ci const u8 *in_key, unsigned int key_len) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci return ppc_aes_setkey(crypto_skcipher_tfm(tfm), in_key, key_len); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic int ppc_xts_setkey(struct crypto_skcipher *tfm, const u8 *in_key, 1268c2ecf20Sopenharmony_ci unsigned int key_len) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci struct ppc_xts_ctx *ctx = crypto_skcipher_ctx(tfm); 1298c2ecf20Sopenharmony_ci int err; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci err = xts_verify_key(tfm, in_key, key_len); 1328c2ecf20Sopenharmony_ci if (err) 1338c2ecf20Sopenharmony_ci return err; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci key_len >>= 1; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci switch (key_len) { 1388c2ecf20Sopenharmony_ci case AES_KEYSIZE_128: 1398c2ecf20Sopenharmony_ci ctx->rounds = 4; 1408c2ecf20Sopenharmony_ci ppc_expand_key_128(ctx->key_enc, in_key); 1418c2ecf20Sopenharmony_ci ppc_expand_key_128(ctx->key_twk, in_key + AES_KEYSIZE_128); 1428c2ecf20Sopenharmony_ci break; 1438c2ecf20Sopenharmony_ci case AES_KEYSIZE_192: 1448c2ecf20Sopenharmony_ci ctx->rounds = 5; 1458c2ecf20Sopenharmony_ci ppc_expand_key_192(ctx->key_enc, in_key); 1468c2ecf20Sopenharmony_ci ppc_expand_key_192(ctx->key_twk, in_key + AES_KEYSIZE_192); 1478c2ecf20Sopenharmony_ci break; 1488c2ecf20Sopenharmony_ci case AES_KEYSIZE_256: 1498c2ecf20Sopenharmony_ci ctx->rounds = 6; 1508c2ecf20Sopenharmony_ci ppc_expand_key_256(ctx->key_enc, in_key); 1518c2ecf20Sopenharmony_ci ppc_expand_key_256(ctx->key_twk, in_key + AES_KEYSIZE_256); 1528c2ecf20Sopenharmony_ci break; 1538c2ecf20Sopenharmony_ci default: 1548c2ecf20Sopenharmony_ci return -EINVAL; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci ppc_generate_decrypt_key(ctx->key_dec, ctx->key_enc, key_len); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci return 0; 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic void ppc_aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci struct ppc_aes_ctx *ctx = crypto_tfm_ctx(tfm); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci spe_begin(); 1678c2ecf20Sopenharmony_ci ppc_encrypt_aes(out, in, ctx->key_enc, ctx->rounds); 1688c2ecf20Sopenharmony_ci spe_end(); 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic void ppc_aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct ppc_aes_ctx *ctx = crypto_tfm_ctx(tfm); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci spe_begin(); 1768c2ecf20Sopenharmony_ci ppc_decrypt_aes(out, in, ctx->key_dec, ctx->rounds); 1778c2ecf20Sopenharmony_ci spe_end(); 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic int ppc_ecb_crypt(struct skcipher_request *req, bool enc) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 1838c2ecf20Sopenharmony_ci struct ppc_aes_ctx *ctx = crypto_skcipher_ctx(tfm); 1848c2ecf20Sopenharmony_ci struct skcipher_walk walk; 1858c2ecf20Sopenharmony_ci unsigned int nbytes; 1868c2ecf20Sopenharmony_ci int err; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci err = skcipher_walk_virt(&walk, req, false); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 1918c2ecf20Sopenharmony_ci nbytes = min_t(unsigned int, nbytes, MAX_BYTES); 1928c2ecf20Sopenharmony_ci nbytes = round_down(nbytes, AES_BLOCK_SIZE); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci spe_begin(); 1958c2ecf20Sopenharmony_ci if (enc) 1968c2ecf20Sopenharmony_ci ppc_encrypt_ecb(walk.dst.virt.addr, walk.src.virt.addr, 1978c2ecf20Sopenharmony_ci ctx->key_enc, ctx->rounds, nbytes); 1988c2ecf20Sopenharmony_ci else 1998c2ecf20Sopenharmony_ci ppc_decrypt_ecb(walk.dst.virt.addr, walk.src.virt.addr, 2008c2ecf20Sopenharmony_ci ctx->key_dec, ctx->rounds, nbytes); 2018c2ecf20Sopenharmony_ci spe_end(); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci err = skcipher_walk_done(&walk, walk.nbytes - nbytes); 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci return err; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic int ppc_ecb_encrypt(struct skcipher_request *req) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci return ppc_ecb_crypt(req, true); 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic int ppc_ecb_decrypt(struct skcipher_request *req) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci return ppc_ecb_crypt(req, false); 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic int ppc_cbc_crypt(struct skcipher_request *req, bool enc) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 2228c2ecf20Sopenharmony_ci struct ppc_aes_ctx *ctx = crypto_skcipher_ctx(tfm); 2238c2ecf20Sopenharmony_ci struct skcipher_walk walk; 2248c2ecf20Sopenharmony_ci unsigned int nbytes; 2258c2ecf20Sopenharmony_ci int err; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci err = skcipher_walk_virt(&walk, req, false); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 2308c2ecf20Sopenharmony_ci nbytes = min_t(unsigned int, nbytes, MAX_BYTES); 2318c2ecf20Sopenharmony_ci nbytes = round_down(nbytes, AES_BLOCK_SIZE); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci spe_begin(); 2348c2ecf20Sopenharmony_ci if (enc) 2358c2ecf20Sopenharmony_ci ppc_encrypt_cbc(walk.dst.virt.addr, walk.src.virt.addr, 2368c2ecf20Sopenharmony_ci ctx->key_enc, ctx->rounds, nbytes, 2378c2ecf20Sopenharmony_ci walk.iv); 2388c2ecf20Sopenharmony_ci else 2398c2ecf20Sopenharmony_ci ppc_decrypt_cbc(walk.dst.virt.addr, walk.src.virt.addr, 2408c2ecf20Sopenharmony_ci ctx->key_dec, ctx->rounds, nbytes, 2418c2ecf20Sopenharmony_ci walk.iv); 2428c2ecf20Sopenharmony_ci spe_end(); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci err = skcipher_walk_done(&walk, walk.nbytes - nbytes); 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci return err; 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic int ppc_cbc_encrypt(struct skcipher_request *req) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci return ppc_cbc_crypt(req, true); 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic int ppc_cbc_decrypt(struct skcipher_request *req) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci return ppc_cbc_crypt(req, false); 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic int ppc_ctr_crypt(struct skcipher_request *req) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 2638c2ecf20Sopenharmony_ci struct ppc_aes_ctx *ctx = crypto_skcipher_ctx(tfm); 2648c2ecf20Sopenharmony_ci struct skcipher_walk walk; 2658c2ecf20Sopenharmony_ci unsigned int nbytes; 2668c2ecf20Sopenharmony_ci int err; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci err = skcipher_walk_virt(&walk, req, false); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 2718c2ecf20Sopenharmony_ci nbytes = min_t(unsigned int, nbytes, MAX_BYTES); 2728c2ecf20Sopenharmony_ci if (nbytes < walk.total) 2738c2ecf20Sopenharmony_ci nbytes = round_down(nbytes, AES_BLOCK_SIZE); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci spe_begin(); 2768c2ecf20Sopenharmony_ci ppc_crypt_ctr(walk.dst.virt.addr, walk.src.virt.addr, 2778c2ecf20Sopenharmony_ci ctx->key_enc, ctx->rounds, nbytes, walk.iv); 2788c2ecf20Sopenharmony_ci spe_end(); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci err = skcipher_walk_done(&walk, walk.nbytes - nbytes); 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci return err; 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic int ppc_xts_crypt(struct skcipher_request *req, bool enc) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 2898c2ecf20Sopenharmony_ci struct ppc_xts_ctx *ctx = crypto_skcipher_ctx(tfm); 2908c2ecf20Sopenharmony_ci struct skcipher_walk walk; 2918c2ecf20Sopenharmony_ci unsigned int nbytes; 2928c2ecf20Sopenharmony_ci int err; 2938c2ecf20Sopenharmony_ci u32 *twk; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci err = skcipher_walk_virt(&walk, req, false); 2968c2ecf20Sopenharmony_ci twk = ctx->key_twk; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 2998c2ecf20Sopenharmony_ci nbytes = min_t(unsigned int, nbytes, MAX_BYTES); 3008c2ecf20Sopenharmony_ci nbytes = round_down(nbytes, AES_BLOCK_SIZE); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci spe_begin(); 3038c2ecf20Sopenharmony_ci if (enc) 3048c2ecf20Sopenharmony_ci ppc_encrypt_xts(walk.dst.virt.addr, walk.src.virt.addr, 3058c2ecf20Sopenharmony_ci ctx->key_enc, ctx->rounds, nbytes, 3068c2ecf20Sopenharmony_ci walk.iv, twk); 3078c2ecf20Sopenharmony_ci else 3088c2ecf20Sopenharmony_ci ppc_decrypt_xts(walk.dst.virt.addr, walk.src.virt.addr, 3098c2ecf20Sopenharmony_ci ctx->key_dec, ctx->rounds, nbytes, 3108c2ecf20Sopenharmony_ci walk.iv, twk); 3118c2ecf20Sopenharmony_ci spe_end(); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci twk = NULL; 3148c2ecf20Sopenharmony_ci err = skcipher_walk_done(&walk, walk.nbytes - nbytes); 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci return err; 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic int ppc_xts_encrypt(struct skcipher_request *req) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 3238c2ecf20Sopenharmony_ci struct ppc_xts_ctx *ctx = crypto_skcipher_ctx(tfm); 3248c2ecf20Sopenharmony_ci int tail = req->cryptlen % AES_BLOCK_SIZE; 3258c2ecf20Sopenharmony_ci int offset = req->cryptlen - tail - AES_BLOCK_SIZE; 3268c2ecf20Sopenharmony_ci struct skcipher_request subreq; 3278c2ecf20Sopenharmony_ci u8 b[2][AES_BLOCK_SIZE]; 3288c2ecf20Sopenharmony_ci int err; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci if (req->cryptlen < AES_BLOCK_SIZE) 3318c2ecf20Sopenharmony_ci return -EINVAL; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci if (tail) { 3348c2ecf20Sopenharmony_ci subreq = *req; 3358c2ecf20Sopenharmony_ci skcipher_request_set_crypt(&subreq, req->src, req->dst, 3368c2ecf20Sopenharmony_ci req->cryptlen - tail, req->iv); 3378c2ecf20Sopenharmony_ci req = &subreq; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci err = ppc_xts_crypt(req, true); 3418c2ecf20Sopenharmony_ci if (err || !tail) 3428c2ecf20Sopenharmony_ci return err; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(b[0], req->dst, offset, AES_BLOCK_SIZE, 0); 3458c2ecf20Sopenharmony_ci memcpy(b[1], b[0], tail); 3468c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(b[0], req->src, offset + AES_BLOCK_SIZE, tail, 0); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci spe_begin(); 3498c2ecf20Sopenharmony_ci ppc_encrypt_xts(b[0], b[0], ctx->key_enc, ctx->rounds, AES_BLOCK_SIZE, 3508c2ecf20Sopenharmony_ci req->iv, NULL); 3518c2ecf20Sopenharmony_ci spe_end(); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(b[0], req->dst, offset, AES_BLOCK_SIZE + tail, 1); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci return 0; 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic int ppc_xts_decrypt(struct skcipher_request *req) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 3618c2ecf20Sopenharmony_ci struct ppc_xts_ctx *ctx = crypto_skcipher_ctx(tfm); 3628c2ecf20Sopenharmony_ci int tail = req->cryptlen % AES_BLOCK_SIZE; 3638c2ecf20Sopenharmony_ci int offset = req->cryptlen - tail - AES_BLOCK_SIZE; 3648c2ecf20Sopenharmony_ci struct skcipher_request subreq; 3658c2ecf20Sopenharmony_ci u8 b[3][AES_BLOCK_SIZE]; 3668c2ecf20Sopenharmony_ci le128 twk; 3678c2ecf20Sopenharmony_ci int err; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci if (req->cryptlen < AES_BLOCK_SIZE) 3708c2ecf20Sopenharmony_ci return -EINVAL; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (tail) { 3738c2ecf20Sopenharmony_ci subreq = *req; 3748c2ecf20Sopenharmony_ci skcipher_request_set_crypt(&subreq, req->src, req->dst, 3758c2ecf20Sopenharmony_ci offset, req->iv); 3768c2ecf20Sopenharmony_ci req = &subreq; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci err = ppc_xts_crypt(req, false); 3808c2ecf20Sopenharmony_ci if (err || !tail) 3818c2ecf20Sopenharmony_ci return err; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(b[1], req->src, offset, AES_BLOCK_SIZE + tail, 0); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci spe_begin(); 3868c2ecf20Sopenharmony_ci if (!offset) 3878c2ecf20Sopenharmony_ci ppc_encrypt_ecb(req->iv, req->iv, ctx->key_twk, ctx->rounds, 3888c2ecf20Sopenharmony_ci AES_BLOCK_SIZE); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci gf128mul_x_ble(&twk, (le128 *)req->iv); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci ppc_decrypt_xts(b[1], b[1], ctx->key_dec, ctx->rounds, AES_BLOCK_SIZE, 3938c2ecf20Sopenharmony_ci (u8 *)&twk, NULL); 3948c2ecf20Sopenharmony_ci memcpy(b[0], b[2], tail); 3958c2ecf20Sopenharmony_ci memcpy(b[0] + tail, b[1] + tail, AES_BLOCK_SIZE - tail); 3968c2ecf20Sopenharmony_ci ppc_decrypt_xts(b[0], b[0], ctx->key_dec, ctx->rounds, AES_BLOCK_SIZE, 3978c2ecf20Sopenharmony_ci req->iv, NULL); 3988c2ecf20Sopenharmony_ci spe_end(); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(b[0], req->dst, offset, AES_BLOCK_SIZE + tail, 1); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci return 0; 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci/* 4068c2ecf20Sopenharmony_ci * Algorithm definitions. Disabling alignment (cra_alignmask=0) was chosen 4078c2ecf20Sopenharmony_ci * because the e500 platform can handle unaligned reads/writes very efficently. 4088c2ecf20Sopenharmony_ci * This improves IPsec thoughput by another few percent. Additionally we assume 4098c2ecf20Sopenharmony_ci * that AES context is always aligned to at least 8 bytes because it is created 4108c2ecf20Sopenharmony_ci * with kmalloc() in the crypto infrastructure 4118c2ecf20Sopenharmony_ci */ 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cistatic struct crypto_alg aes_cipher_alg = { 4148c2ecf20Sopenharmony_ci .cra_name = "aes", 4158c2ecf20Sopenharmony_ci .cra_driver_name = "aes-ppc-spe", 4168c2ecf20Sopenharmony_ci .cra_priority = 300, 4178c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_TYPE_CIPHER, 4188c2ecf20Sopenharmony_ci .cra_blocksize = AES_BLOCK_SIZE, 4198c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct ppc_aes_ctx), 4208c2ecf20Sopenharmony_ci .cra_alignmask = 0, 4218c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 4228c2ecf20Sopenharmony_ci .cra_u = { 4238c2ecf20Sopenharmony_ci .cipher = { 4248c2ecf20Sopenharmony_ci .cia_min_keysize = AES_MIN_KEY_SIZE, 4258c2ecf20Sopenharmony_ci .cia_max_keysize = AES_MAX_KEY_SIZE, 4268c2ecf20Sopenharmony_ci .cia_setkey = ppc_aes_setkey, 4278c2ecf20Sopenharmony_ci .cia_encrypt = ppc_aes_encrypt, 4288c2ecf20Sopenharmony_ci .cia_decrypt = ppc_aes_decrypt 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci}; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic struct skcipher_alg aes_skcipher_algs[] = { 4348c2ecf20Sopenharmony_ci { 4358c2ecf20Sopenharmony_ci .base.cra_name = "ecb(aes)", 4368c2ecf20Sopenharmony_ci .base.cra_driver_name = "ecb-ppc-spe", 4378c2ecf20Sopenharmony_ci .base.cra_priority = 300, 4388c2ecf20Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 4398c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct ppc_aes_ctx), 4408c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 4418c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 4428c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 4438c2ecf20Sopenharmony_ci .setkey = ppc_aes_setkey_skcipher, 4448c2ecf20Sopenharmony_ci .encrypt = ppc_ecb_encrypt, 4458c2ecf20Sopenharmony_ci .decrypt = ppc_ecb_decrypt, 4468c2ecf20Sopenharmony_ci }, { 4478c2ecf20Sopenharmony_ci .base.cra_name = "cbc(aes)", 4488c2ecf20Sopenharmony_ci .base.cra_driver_name = "cbc-ppc-spe", 4498c2ecf20Sopenharmony_ci .base.cra_priority = 300, 4508c2ecf20Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 4518c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct ppc_aes_ctx), 4528c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 4538c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 4548c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 4558c2ecf20Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 4568c2ecf20Sopenharmony_ci .setkey = ppc_aes_setkey_skcipher, 4578c2ecf20Sopenharmony_ci .encrypt = ppc_cbc_encrypt, 4588c2ecf20Sopenharmony_ci .decrypt = ppc_cbc_decrypt, 4598c2ecf20Sopenharmony_ci }, { 4608c2ecf20Sopenharmony_ci .base.cra_name = "ctr(aes)", 4618c2ecf20Sopenharmony_ci .base.cra_driver_name = "ctr-ppc-spe", 4628c2ecf20Sopenharmony_ci .base.cra_priority = 300, 4638c2ecf20Sopenharmony_ci .base.cra_blocksize = 1, 4648c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct ppc_aes_ctx), 4658c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 4668c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 4678c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 4688c2ecf20Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 4698c2ecf20Sopenharmony_ci .setkey = ppc_aes_setkey_skcipher, 4708c2ecf20Sopenharmony_ci .encrypt = ppc_ctr_crypt, 4718c2ecf20Sopenharmony_ci .decrypt = ppc_ctr_crypt, 4728c2ecf20Sopenharmony_ci .chunksize = AES_BLOCK_SIZE, 4738c2ecf20Sopenharmony_ci }, { 4748c2ecf20Sopenharmony_ci .base.cra_name = "xts(aes)", 4758c2ecf20Sopenharmony_ci .base.cra_driver_name = "xts-ppc-spe", 4768c2ecf20Sopenharmony_ci .base.cra_priority = 300, 4778c2ecf20Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 4788c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct ppc_xts_ctx), 4798c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 4808c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE * 2, 4818c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE * 2, 4828c2ecf20Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 4838c2ecf20Sopenharmony_ci .setkey = ppc_xts_setkey, 4848c2ecf20Sopenharmony_ci .encrypt = ppc_xts_encrypt, 4858c2ecf20Sopenharmony_ci .decrypt = ppc_xts_decrypt, 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci}; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic int __init ppc_aes_mod_init(void) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci int err; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci err = crypto_register_alg(&aes_cipher_alg); 4948c2ecf20Sopenharmony_ci if (err) 4958c2ecf20Sopenharmony_ci return err; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci err = crypto_register_skciphers(aes_skcipher_algs, 4988c2ecf20Sopenharmony_ci ARRAY_SIZE(aes_skcipher_algs)); 4998c2ecf20Sopenharmony_ci if (err) 5008c2ecf20Sopenharmony_ci crypto_unregister_alg(&aes_cipher_alg); 5018c2ecf20Sopenharmony_ci return err; 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic void __exit ppc_aes_mod_fini(void) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci crypto_unregister_alg(&aes_cipher_alg); 5078c2ecf20Sopenharmony_ci crypto_unregister_skciphers(aes_skcipher_algs, 5088c2ecf20Sopenharmony_ci ARRAY_SIZE(aes_skcipher_algs)); 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_cimodule_init(ppc_aes_mod_init); 5128c2ecf20Sopenharmony_cimodule_exit(ppc_aes_mod_fini); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 5158c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS, SPE optimized"); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("aes"); 5188c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("ecb(aes)"); 5198c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("cbc(aes)"); 5208c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("ctr(aes)"); 5218c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("xts(aes)"); 5228c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("aes-ppc-spe"); 523