162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Glue code for AES implementation for SPE instructions (PPC) 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Based on generic implementation. The assembler module takes care 662306a36Sopenharmony_ci * about the SPE registers so it can run from interrupt context. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Copyright (c) 2015 Markus Stockhausen <stockhausen@collogia.de> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <crypto/aes.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/init.h> 1462306a36Sopenharmony_ci#include <linux/types.h> 1562306a36Sopenharmony_ci#include <linux/errno.h> 1662306a36Sopenharmony_ci#include <linux/crypto.h> 1762306a36Sopenharmony_ci#include <asm/byteorder.h> 1862306a36Sopenharmony_ci#include <asm/switch_to.h> 1962306a36Sopenharmony_ci#include <crypto/algapi.h> 2062306a36Sopenharmony_ci#include <crypto/internal/skcipher.h> 2162306a36Sopenharmony_ci#include <crypto/xts.h> 2262306a36Sopenharmony_ci#include <crypto/gf128mul.h> 2362306a36Sopenharmony_ci#include <crypto/scatterwalk.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* 2662306a36Sopenharmony_ci * MAX_BYTES defines the number of bytes that are allowed to be processed 2762306a36Sopenharmony_ci * between preempt_disable() and preempt_enable(). e500 cores can issue two 2862306a36Sopenharmony_ci * instructions per clock cycle using one 32/64 bit unit (SU1) and one 32 2962306a36Sopenharmony_ci * bit unit (SU2). One of these can be a memory access that is executed via 3062306a36Sopenharmony_ci * a single load and store unit (LSU). XTS-AES-256 takes ~780 operations per 3162306a36Sopenharmony_ci * 16 byte block or 25 cycles per byte. Thus 768 bytes of input data 3262306a36Sopenharmony_ci * will need an estimated maximum of 20,000 cycles. Headroom for cache misses 3362306a36Sopenharmony_ci * included. Even with the low end model clocked at 667 MHz this equals to a 3462306a36Sopenharmony_ci * critical time window of less than 30us. The value has been chosen to 3562306a36Sopenharmony_ci * process a 512 byte disk block in one or a large 1400 bytes IPsec network 3662306a36Sopenharmony_ci * packet in two runs. 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci */ 3962306a36Sopenharmony_ci#define MAX_BYTES 768 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistruct ppc_aes_ctx { 4262306a36Sopenharmony_ci u32 key_enc[AES_MAX_KEYLENGTH_U32]; 4362306a36Sopenharmony_ci u32 key_dec[AES_MAX_KEYLENGTH_U32]; 4462306a36Sopenharmony_ci u32 rounds; 4562306a36Sopenharmony_ci}; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistruct ppc_xts_ctx { 4862306a36Sopenharmony_ci u32 key_enc[AES_MAX_KEYLENGTH_U32]; 4962306a36Sopenharmony_ci u32 key_dec[AES_MAX_KEYLENGTH_U32]; 5062306a36Sopenharmony_ci u32 key_twk[AES_MAX_KEYLENGTH_U32]; 5162306a36Sopenharmony_ci u32 rounds; 5262306a36Sopenharmony_ci}; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ciextern void ppc_encrypt_aes(u8 *out, const u8 *in, u32 *key_enc, u32 rounds); 5562306a36Sopenharmony_ciextern void ppc_decrypt_aes(u8 *out, const u8 *in, u32 *key_dec, u32 rounds); 5662306a36Sopenharmony_ciextern void ppc_encrypt_ecb(u8 *out, const u8 *in, u32 *key_enc, u32 rounds, 5762306a36Sopenharmony_ci u32 bytes); 5862306a36Sopenharmony_ciextern void ppc_decrypt_ecb(u8 *out, const u8 *in, u32 *key_dec, u32 rounds, 5962306a36Sopenharmony_ci u32 bytes); 6062306a36Sopenharmony_ciextern void ppc_encrypt_cbc(u8 *out, const u8 *in, u32 *key_enc, u32 rounds, 6162306a36Sopenharmony_ci u32 bytes, u8 *iv); 6262306a36Sopenharmony_ciextern void ppc_decrypt_cbc(u8 *out, const u8 *in, u32 *key_dec, u32 rounds, 6362306a36Sopenharmony_ci u32 bytes, u8 *iv); 6462306a36Sopenharmony_ciextern void ppc_crypt_ctr (u8 *out, const u8 *in, u32 *key_enc, u32 rounds, 6562306a36Sopenharmony_ci u32 bytes, u8 *iv); 6662306a36Sopenharmony_ciextern void ppc_encrypt_xts(u8 *out, const u8 *in, u32 *key_enc, u32 rounds, 6762306a36Sopenharmony_ci u32 bytes, u8 *iv, u32 *key_twk); 6862306a36Sopenharmony_ciextern void ppc_decrypt_xts(u8 *out, const u8 *in, u32 *key_dec, u32 rounds, 6962306a36Sopenharmony_ci u32 bytes, u8 *iv, u32 *key_twk); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ciextern void ppc_expand_key_128(u32 *key_enc, const u8 *key); 7262306a36Sopenharmony_ciextern void ppc_expand_key_192(u32 *key_enc, const u8 *key); 7362306a36Sopenharmony_ciextern void ppc_expand_key_256(u32 *key_enc, const u8 *key); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ciextern void ppc_generate_decrypt_key(u32 *key_dec,u32 *key_enc, 7662306a36Sopenharmony_ci unsigned int key_len); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic void spe_begin(void) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci /* disable preemption and save users SPE registers if required */ 8162306a36Sopenharmony_ci preempt_disable(); 8262306a36Sopenharmony_ci enable_kernel_spe(); 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic void spe_end(void) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci disable_kernel_spe(); 8862306a36Sopenharmony_ci /* reenable preemption */ 8962306a36Sopenharmony_ci preempt_enable(); 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic int ppc_aes_setkey(struct crypto_tfm *tfm, const u8 *in_key, 9362306a36Sopenharmony_ci unsigned int key_len) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci struct ppc_aes_ctx *ctx = crypto_tfm_ctx(tfm); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci switch (key_len) { 9862306a36Sopenharmony_ci case AES_KEYSIZE_128: 9962306a36Sopenharmony_ci ctx->rounds = 4; 10062306a36Sopenharmony_ci ppc_expand_key_128(ctx->key_enc, in_key); 10162306a36Sopenharmony_ci break; 10262306a36Sopenharmony_ci case AES_KEYSIZE_192: 10362306a36Sopenharmony_ci ctx->rounds = 5; 10462306a36Sopenharmony_ci ppc_expand_key_192(ctx->key_enc, in_key); 10562306a36Sopenharmony_ci break; 10662306a36Sopenharmony_ci case AES_KEYSIZE_256: 10762306a36Sopenharmony_ci ctx->rounds = 6; 10862306a36Sopenharmony_ci ppc_expand_key_256(ctx->key_enc, in_key); 10962306a36Sopenharmony_ci break; 11062306a36Sopenharmony_ci default: 11162306a36Sopenharmony_ci return -EINVAL; 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci ppc_generate_decrypt_key(ctx->key_dec, ctx->key_enc, key_len); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci return 0; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic int ppc_aes_setkey_skcipher(struct crypto_skcipher *tfm, 12062306a36Sopenharmony_ci const u8 *in_key, unsigned int key_len) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci return ppc_aes_setkey(crypto_skcipher_tfm(tfm), in_key, key_len); 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic int ppc_xts_setkey(struct crypto_skcipher *tfm, const u8 *in_key, 12662306a36Sopenharmony_ci unsigned int key_len) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct ppc_xts_ctx *ctx = crypto_skcipher_ctx(tfm); 12962306a36Sopenharmony_ci int err; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci err = xts_verify_key(tfm, in_key, key_len); 13262306a36Sopenharmony_ci if (err) 13362306a36Sopenharmony_ci return err; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci key_len >>= 1; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci switch (key_len) { 13862306a36Sopenharmony_ci case AES_KEYSIZE_128: 13962306a36Sopenharmony_ci ctx->rounds = 4; 14062306a36Sopenharmony_ci ppc_expand_key_128(ctx->key_enc, in_key); 14162306a36Sopenharmony_ci ppc_expand_key_128(ctx->key_twk, in_key + AES_KEYSIZE_128); 14262306a36Sopenharmony_ci break; 14362306a36Sopenharmony_ci case AES_KEYSIZE_192: 14462306a36Sopenharmony_ci ctx->rounds = 5; 14562306a36Sopenharmony_ci ppc_expand_key_192(ctx->key_enc, in_key); 14662306a36Sopenharmony_ci ppc_expand_key_192(ctx->key_twk, in_key + AES_KEYSIZE_192); 14762306a36Sopenharmony_ci break; 14862306a36Sopenharmony_ci case AES_KEYSIZE_256: 14962306a36Sopenharmony_ci ctx->rounds = 6; 15062306a36Sopenharmony_ci ppc_expand_key_256(ctx->key_enc, in_key); 15162306a36Sopenharmony_ci ppc_expand_key_256(ctx->key_twk, in_key + AES_KEYSIZE_256); 15262306a36Sopenharmony_ci break; 15362306a36Sopenharmony_ci default: 15462306a36Sopenharmony_ci return -EINVAL; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci ppc_generate_decrypt_key(ctx->key_dec, ctx->key_enc, key_len); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci return 0; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic void ppc_aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci struct ppc_aes_ctx *ctx = crypto_tfm_ctx(tfm); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci spe_begin(); 16762306a36Sopenharmony_ci ppc_encrypt_aes(out, in, ctx->key_enc, ctx->rounds); 16862306a36Sopenharmony_ci spe_end(); 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic void ppc_aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci struct ppc_aes_ctx *ctx = crypto_tfm_ctx(tfm); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci spe_begin(); 17662306a36Sopenharmony_ci ppc_decrypt_aes(out, in, ctx->key_dec, ctx->rounds); 17762306a36Sopenharmony_ci spe_end(); 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic int ppc_ecb_crypt(struct skcipher_request *req, bool enc) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 18362306a36Sopenharmony_ci struct ppc_aes_ctx *ctx = crypto_skcipher_ctx(tfm); 18462306a36Sopenharmony_ci struct skcipher_walk walk; 18562306a36Sopenharmony_ci unsigned int nbytes; 18662306a36Sopenharmony_ci int err; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci err = skcipher_walk_virt(&walk, req, false); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 19162306a36Sopenharmony_ci nbytes = min_t(unsigned int, nbytes, MAX_BYTES); 19262306a36Sopenharmony_ci nbytes = round_down(nbytes, AES_BLOCK_SIZE); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci spe_begin(); 19562306a36Sopenharmony_ci if (enc) 19662306a36Sopenharmony_ci ppc_encrypt_ecb(walk.dst.virt.addr, walk.src.virt.addr, 19762306a36Sopenharmony_ci ctx->key_enc, ctx->rounds, nbytes); 19862306a36Sopenharmony_ci else 19962306a36Sopenharmony_ci ppc_decrypt_ecb(walk.dst.virt.addr, walk.src.virt.addr, 20062306a36Sopenharmony_ci ctx->key_dec, ctx->rounds, nbytes); 20162306a36Sopenharmony_ci spe_end(); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci err = skcipher_walk_done(&walk, walk.nbytes - nbytes); 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci return err; 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic int ppc_ecb_encrypt(struct skcipher_request *req) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci return ppc_ecb_crypt(req, true); 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic int ppc_ecb_decrypt(struct skcipher_request *req) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci return ppc_ecb_crypt(req, false); 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic int ppc_cbc_crypt(struct skcipher_request *req, bool enc) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 22262306a36Sopenharmony_ci struct ppc_aes_ctx *ctx = crypto_skcipher_ctx(tfm); 22362306a36Sopenharmony_ci struct skcipher_walk walk; 22462306a36Sopenharmony_ci unsigned int nbytes; 22562306a36Sopenharmony_ci int err; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci err = skcipher_walk_virt(&walk, req, false); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 23062306a36Sopenharmony_ci nbytes = min_t(unsigned int, nbytes, MAX_BYTES); 23162306a36Sopenharmony_ci nbytes = round_down(nbytes, AES_BLOCK_SIZE); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci spe_begin(); 23462306a36Sopenharmony_ci if (enc) 23562306a36Sopenharmony_ci ppc_encrypt_cbc(walk.dst.virt.addr, walk.src.virt.addr, 23662306a36Sopenharmony_ci ctx->key_enc, ctx->rounds, nbytes, 23762306a36Sopenharmony_ci walk.iv); 23862306a36Sopenharmony_ci else 23962306a36Sopenharmony_ci ppc_decrypt_cbc(walk.dst.virt.addr, walk.src.virt.addr, 24062306a36Sopenharmony_ci ctx->key_dec, ctx->rounds, nbytes, 24162306a36Sopenharmony_ci walk.iv); 24262306a36Sopenharmony_ci spe_end(); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci err = skcipher_walk_done(&walk, walk.nbytes - nbytes); 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci return err; 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic int ppc_cbc_encrypt(struct skcipher_request *req) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci return ppc_cbc_crypt(req, true); 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cistatic int ppc_cbc_decrypt(struct skcipher_request *req) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci return ppc_cbc_crypt(req, false); 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic int ppc_ctr_crypt(struct skcipher_request *req) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 26362306a36Sopenharmony_ci struct ppc_aes_ctx *ctx = crypto_skcipher_ctx(tfm); 26462306a36Sopenharmony_ci struct skcipher_walk walk; 26562306a36Sopenharmony_ci unsigned int nbytes; 26662306a36Sopenharmony_ci int err; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci err = skcipher_walk_virt(&walk, req, false); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 27162306a36Sopenharmony_ci nbytes = min_t(unsigned int, nbytes, MAX_BYTES); 27262306a36Sopenharmony_ci if (nbytes < walk.total) 27362306a36Sopenharmony_ci nbytes = round_down(nbytes, AES_BLOCK_SIZE); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci spe_begin(); 27662306a36Sopenharmony_ci ppc_crypt_ctr(walk.dst.virt.addr, walk.src.virt.addr, 27762306a36Sopenharmony_ci ctx->key_enc, ctx->rounds, nbytes, walk.iv); 27862306a36Sopenharmony_ci spe_end(); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci err = skcipher_walk_done(&walk, walk.nbytes - nbytes); 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci return err; 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic int ppc_xts_crypt(struct skcipher_request *req, bool enc) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 28962306a36Sopenharmony_ci struct ppc_xts_ctx *ctx = crypto_skcipher_ctx(tfm); 29062306a36Sopenharmony_ci struct skcipher_walk walk; 29162306a36Sopenharmony_ci unsigned int nbytes; 29262306a36Sopenharmony_ci int err; 29362306a36Sopenharmony_ci u32 *twk; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci err = skcipher_walk_virt(&walk, req, false); 29662306a36Sopenharmony_ci twk = ctx->key_twk; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 29962306a36Sopenharmony_ci nbytes = min_t(unsigned int, nbytes, MAX_BYTES); 30062306a36Sopenharmony_ci nbytes = round_down(nbytes, AES_BLOCK_SIZE); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci spe_begin(); 30362306a36Sopenharmony_ci if (enc) 30462306a36Sopenharmony_ci ppc_encrypt_xts(walk.dst.virt.addr, walk.src.virt.addr, 30562306a36Sopenharmony_ci ctx->key_enc, ctx->rounds, nbytes, 30662306a36Sopenharmony_ci walk.iv, twk); 30762306a36Sopenharmony_ci else 30862306a36Sopenharmony_ci ppc_decrypt_xts(walk.dst.virt.addr, walk.src.virt.addr, 30962306a36Sopenharmony_ci ctx->key_dec, ctx->rounds, nbytes, 31062306a36Sopenharmony_ci walk.iv, twk); 31162306a36Sopenharmony_ci spe_end(); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci twk = NULL; 31462306a36Sopenharmony_ci err = skcipher_walk_done(&walk, walk.nbytes - nbytes); 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci return err; 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic int ppc_xts_encrypt(struct skcipher_request *req) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 32362306a36Sopenharmony_ci struct ppc_xts_ctx *ctx = crypto_skcipher_ctx(tfm); 32462306a36Sopenharmony_ci int tail = req->cryptlen % AES_BLOCK_SIZE; 32562306a36Sopenharmony_ci int offset = req->cryptlen - tail - AES_BLOCK_SIZE; 32662306a36Sopenharmony_ci struct skcipher_request subreq; 32762306a36Sopenharmony_ci u8 b[2][AES_BLOCK_SIZE]; 32862306a36Sopenharmony_ci int err; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (req->cryptlen < AES_BLOCK_SIZE) 33162306a36Sopenharmony_ci return -EINVAL; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci if (tail) { 33462306a36Sopenharmony_ci subreq = *req; 33562306a36Sopenharmony_ci skcipher_request_set_crypt(&subreq, req->src, req->dst, 33662306a36Sopenharmony_ci req->cryptlen - tail, req->iv); 33762306a36Sopenharmony_ci req = &subreq; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci err = ppc_xts_crypt(req, true); 34162306a36Sopenharmony_ci if (err || !tail) 34262306a36Sopenharmony_ci return err; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci scatterwalk_map_and_copy(b[0], req->dst, offset, AES_BLOCK_SIZE, 0); 34562306a36Sopenharmony_ci memcpy(b[1], b[0], tail); 34662306a36Sopenharmony_ci scatterwalk_map_and_copy(b[0], req->src, offset + AES_BLOCK_SIZE, tail, 0); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci spe_begin(); 34962306a36Sopenharmony_ci ppc_encrypt_xts(b[0], b[0], ctx->key_enc, ctx->rounds, AES_BLOCK_SIZE, 35062306a36Sopenharmony_ci req->iv, NULL); 35162306a36Sopenharmony_ci spe_end(); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci scatterwalk_map_and_copy(b[0], req->dst, offset, AES_BLOCK_SIZE + tail, 1); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci return 0; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic int ppc_xts_decrypt(struct skcipher_request *req) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 36162306a36Sopenharmony_ci struct ppc_xts_ctx *ctx = crypto_skcipher_ctx(tfm); 36262306a36Sopenharmony_ci int tail = req->cryptlen % AES_BLOCK_SIZE; 36362306a36Sopenharmony_ci int offset = req->cryptlen - tail - AES_BLOCK_SIZE; 36462306a36Sopenharmony_ci struct skcipher_request subreq; 36562306a36Sopenharmony_ci u8 b[3][AES_BLOCK_SIZE]; 36662306a36Sopenharmony_ci le128 twk; 36762306a36Sopenharmony_ci int err; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (req->cryptlen < AES_BLOCK_SIZE) 37062306a36Sopenharmony_ci return -EINVAL; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if (tail) { 37362306a36Sopenharmony_ci subreq = *req; 37462306a36Sopenharmony_ci skcipher_request_set_crypt(&subreq, req->src, req->dst, 37562306a36Sopenharmony_ci offset, req->iv); 37662306a36Sopenharmony_ci req = &subreq; 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci err = ppc_xts_crypt(req, false); 38062306a36Sopenharmony_ci if (err || !tail) 38162306a36Sopenharmony_ci return err; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci scatterwalk_map_and_copy(b[1], req->src, offset, AES_BLOCK_SIZE + tail, 0); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci spe_begin(); 38662306a36Sopenharmony_ci if (!offset) 38762306a36Sopenharmony_ci ppc_encrypt_ecb(req->iv, req->iv, ctx->key_twk, ctx->rounds, 38862306a36Sopenharmony_ci AES_BLOCK_SIZE); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci gf128mul_x_ble(&twk, (le128 *)req->iv); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci ppc_decrypt_xts(b[1], b[1], ctx->key_dec, ctx->rounds, AES_BLOCK_SIZE, 39362306a36Sopenharmony_ci (u8 *)&twk, NULL); 39462306a36Sopenharmony_ci memcpy(b[0], b[2], tail); 39562306a36Sopenharmony_ci memcpy(b[0] + tail, b[1] + tail, AES_BLOCK_SIZE - tail); 39662306a36Sopenharmony_ci ppc_decrypt_xts(b[0], b[0], ctx->key_dec, ctx->rounds, AES_BLOCK_SIZE, 39762306a36Sopenharmony_ci req->iv, NULL); 39862306a36Sopenharmony_ci spe_end(); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci scatterwalk_map_and_copy(b[0], req->dst, offset, AES_BLOCK_SIZE + tail, 1); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci return 0; 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci/* 40662306a36Sopenharmony_ci * Algorithm definitions. Disabling alignment (cra_alignmask=0) was chosen 40762306a36Sopenharmony_ci * because the e500 platform can handle unaligned reads/writes very efficiently. 40862306a36Sopenharmony_ci * This improves IPsec thoughput by another few percent. Additionally we assume 40962306a36Sopenharmony_ci * that AES context is always aligned to at least 8 bytes because it is created 41062306a36Sopenharmony_ci * with kmalloc() in the crypto infrastructure 41162306a36Sopenharmony_ci */ 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistatic struct crypto_alg aes_cipher_alg = { 41462306a36Sopenharmony_ci .cra_name = "aes", 41562306a36Sopenharmony_ci .cra_driver_name = "aes-ppc-spe", 41662306a36Sopenharmony_ci .cra_priority = 300, 41762306a36Sopenharmony_ci .cra_flags = CRYPTO_ALG_TYPE_CIPHER, 41862306a36Sopenharmony_ci .cra_blocksize = AES_BLOCK_SIZE, 41962306a36Sopenharmony_ci .cra_ctxsize = sizeof(struct ppc_aes_ctx), 42062306a36Sopenharmony_ci .cra_alignmask = 0, 42162306a36Sopenharmony_ci .cra_module = THIS_MODULE, 42262306a36Sopenharmony_ci .cra_u = { 42362306a36Sopenharmony_ci .cipher = { 42462306a36Sopenharmony_ci .cia_min_keysize = AES_MIN_KEY_SIZE, 42562306a36Sopenharmony_ci .cia_max_keysize = AES_MAX_KEY_SIZE, 42662306a36Sopenharmony_ci .cia_setkey = ppc_aes_setkey, 42762306a36Sopenharmony_ci .cia_encrypt = ppc_aes_encrypt, 42862306a36Sopenharmony_ci .cia_decrypt = ppc_aes_decrypt 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci}; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic struct skcipher_alg aes_skcipher_algs[] = { 43462306a36Sopenharmony_ci { 43562306a36Sopenharmony_ci .base.cra_name = "ecb(aes)", 43662306a36Sopenharmony_ci .base.cra_driver_name = "ecb-ppc-spe", 43762306a36Sopenharmony_ci .base.cra_priority = 300, 43862306a36Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 43962306a36Sopenharmony_ci .base.cra_ctxsize = sizeof(struct ppc_aes_ctx), 44062306a36Sopenharmony_ci .base.cra_module = THIS_MODULE, 44162306a36Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 44262306a36Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 44362306a36Sopenharmony_ci .setkey = ppc_aes_setkey_skcipher, 44462306a36Sopenharmony_ci .encrypt = ppc_ecb_encrypt, 44562306a36Sopenharmony_ci .decrypt = ppc_ecb_decrypt, 44662306a36Sopenharmony_ci }, { 44762306a36Sopenharmony_ci .base.cra_name = "cbc(aes)", 44862306a36Sopenharmony_ci .base.cra_driver_name = "cbc-ppc-spe", 44962306a36Sopenharmony_ci .base.cra_priority = 300, 45062306a36Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 45162306a36Sopenharmony_ci .base.cra_ctxsize = sizeof(struct ppc_aes_ctx), 45262306a36Sopenharmony_ci .base.cra_module = THIS_MODULE, 45362306a36Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 45462306a36Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 45562306a36Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 45662306a36Sopenharmony_ci .setkey = ppc_aes_setkey_skcipher, 45762306a36Sopenharmony_ci .encrypt = ppc_cbc_encrypt, 45862306a36Sopenharmony_ci .decrypt = ppc_cbc_decrypt, 45962306a36Sopenharmony_ci }, { 46062306a36Sopenharmony_ci .base.cra_name = "ctr(aes)", 46162306a36Sopenharmony_ci .base.cra_driver_name = "ctr-ppc-spe", 46262306a36Sopenharmony_ci .base.cra_priority = 300, 46362306a36Sopenharmony_ci .base.cra_blocksize = 1, 46462306a36Sopenharmony_ci .base.cra_ctxsize = sizeof(struct ppc_aes_ctx), 46562306a36Sopenharmony_ci .base.cra_module = THIS_MODULE, 46662306a36Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 46762306a36Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 46862306a36Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 46962306a36Sopenharmony_ci .setkey = ppc_aes_setkey_skcipher, 47062306a36Sopenharmony_ci .encrypt = ppc_ctr_crypt, 47162306a36Sopenharmony_ci .decrypt = ppc_ctr_crypt, 47262306a36Sopenharmony_ci .chunksize = AES_BLOCK_SIZE, 47362306a36Sopenharmony_ci }, { 47462306a36Sopenharmony_ci .base.cra_name = "xts(aes)", 47562306a36Sopenharmony_ci .base.cra_driver_name = "xts-ppc-spe", 47662306a36Sopenharmony_ci .base.cra_priority = 300, 47762306a36Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 47862306a36Sopenharmony_ci .base.cra_ctxsize = sizeof(struct ppc_xts_ctx), 47962306a36Sopenharmony_ci .base.cra_module = THIS_MODULE, 48062306a36Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE * 2, 48162306a36Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE * 2, 48262306a36Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 48362306a36Sopenharmony_ci .setkey = ppc_xts_setkey, 48462306a36Sopenharmony_ci .encrypt = ppc_xts_encrypt, 48562306a36Sopenharmony_ci .decrypt = ppc_xts_decrypt, 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci}; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistatic int __init ppc_aes_mod_init(void) 49062306a36Sopenharmony_ci{ 49162306a36Sopenharmony_ci int err; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci err = crypto_register_alg(&aes_cipher_alg); 49462306a36Sopenharmony_ci if (err) 49562306a36Sopenharmony_ci return err; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci err = crypto_register_skciphers(aes_skcipher_algs, 49862306a36Sopenharmony_ci ARRAY_SIZE(aes_skcipher_algs)); 49962306a36Sopenharmony_ci if (err) 50062306a36Sopenharmony_ci crypto_unregister_alg(&aes_cipher_alg); 50162306a36Sopenharmony_ci return err; 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cistatic void __exit ppc_aes_mod_fini(void) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci crypto_unregister_alg(&aes_cipher_alg); 50762306a36Sopenharmony_ci crypto_unregister_skciphers(aes_skcipher_algs, 50862306a36Sopenharmony_ci ARRAY_SIZE(aes_skcipher_algs)); 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_cimodule_init(ppc_aes_mod_init); 51262306a36Sopenharmony_cimodule_exit(ppc_aes_mod_fini); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 51562306a36Sopenharmony_ciMODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS, SPE optimized"); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("aes"); 51862306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("ecb(aes)"); 51962306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("cbc(aes)"); 52062306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("ctr(aes)"); 52162306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("xts(aes)"); 52262306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("aes-ppc-spe"); 523