162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * AES CTR routines supporting VMX instructions on the Power 8 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2015 International Business Machines Inc. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Marcelo Henrique Cerri <mhcerri@br.ibm.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <asm/simd.h> 1162306a36Sopenharmony_ci#include <asm/switch_to.h> 1262306a36Sopenharmony_ci#include <crypto/aes.h> 1362306a36Sopenharmony_ci#include <crypto/internal/simd.h> 1462306a36Sopenharmony_ci#include <crypto/internal/skcipher.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "aesp8-ppc.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistruct p8_aes_ctr_ctx { 1962306a36Sopenharmony_ci struct crypto_skcipher *fallback; 2062306a36Sopenharmony_ci struct aes_key enc_key; 2162306a36Sopenharmony_ci}; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic int p8_aes_ctr_init(struct crypto_skcipher *tfm) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci struct p8_aes_ctr_ctx *ctx = crypto_skcipher_ctx(tfm); 2662306a36Sopenharmony_ci struct crypto_skcipher *fallback; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci fallback = crypto_alloc_skcipher("ctr(aes)", 0, 2962306a36Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK | 3062306a36Sopenharmony_ci CRYPTO_ALG_ASYNC); 3162306a36Sopenharmony_ci if (IS_ERR(fallback)) { 3262306a36Sopenharmony_ci pr_err("Failed to allocate ctr(aes) fallback: %ld\n", 3362306a36Sopenharmony_ci PTR_ERR(fallback)); 3462306a36Sopenharmony_ci return PTR_ERR(fallback); 3562306a36Sopenharmony_ci } 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci crypto_skcipher_set_reqsize(tfm, sizeof(struct skcipher_request) + 3862306a36Sopenharmony_ci crypto_skcipher_reqsize(fallback)); 3962306a36Sopenharmony_ci ctx->fallback = fallback; 4062306a36Sopenharmony_ci return 0; 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic void p8_aes_ctr_exit(struct crypto_skcipher *tfm) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci struct p8_aes_ctr_ctx *ctx = crypto_skcipher_ctx(tfm); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci crypto_free_skcipher(ctx->fallback); 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic int p8_aes_ctr_setkey(struct crypto_skcipher *tfm, const u8 *key, 5162306a36Sopenharmony_ci unsigned int keylen) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci struct p8_aes_ctr_ctx *ctx = crypto_skcipher_ctx(tfm); 5462306a36Sopenharmony_ci int ret; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci preempt_disable(); 5762306a36Sopenharmony_ci pagefault_disable(); 5862306a36Sopenharmony_ci enable_kernel_vsx(); 5962306a36Sopenharmony_ci ret = aes_p8_set_encrypt_key(key, keylen * 8, &ctx->enc_key); 6062306a36Sopenharmony_ci disable_kernel_vsx(); 6162306a36Sopenharmony_ci pagefault_enable(); 6262306a36Sopenharmony_ci preempt_enable(); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci ret |= crypto_skcipher_setkey(ctx->fallback, key, keylen); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci return ret ? -EINVAL : 0; 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic void p8_aes_ctr_final(const struct p8_aes_ctr_ctx *ctx, 7062306a36Sopenharmony_ci struct skcipher_walk *walk) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci u8 *ctrblk = walk->iv; 7362306a36Sopenharmony_ci u8 keystream[AES_BLOCK_SIZE]; 7462306a36Sopenharmony_ci u8 *src = walk->src.virt.addr; 7562306a36Sopenharmony_ci u8 *dst = walk->dst.virt.addr; 7662306a36Sopenharmony_ci unsigned int nbytes = walk->nbytes; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci preempt_disable(); 7962306a36Sopenharmony_ci pagefault_disable(); 8062306a36Sopenharmony_ci enable_kernel_vsx(); 8162306a36Sopenharmony_ci aes_p8_encrypt(ctrblk, keystream, &ctx->enc_key); 8262306a36Sopenharmony_ci disable_kernel_vsx(); 8362306a36Sopenharmony_ci pagefault_enable(); 8462306a36Sopenharmony_ci preempt_enable(); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci crypto_xor_cpy(dst, keystream, src, nbytes); 8762306a36Sopenharmony_ci crypto_inc(ctrblk, AES_BLOCK_SIZE); 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic int p8_aes_ctr_crypt(struct skcipher_request *req) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 9362306a36Sopenharmony_ci const struct p8_aes_ctr_ctx *ctx = crypto_skcipher_ctx(tfm); 9462306a36Sopenharmony_ci struct skcipher_walk walk; 9562306a36Sopenharmony_ci unsigned int nbytes; 9662306a36Sopenharmony_ci int ret; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (!crypto_simd_usable()) { 9962306a36Sopenharmony_ci struct skcipher_request *subreq = skcipher_request_ctx(req); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci *subreq = *req; 10262306a36Sopenharmony_ci skcipher_request_set_tfm(subreq, ctx->fallback); 10362306a36Sopenharmony_ci return crypto_skcipher_encrypt(subreq); 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci ret = skcipher_walk_virt(&walk, req, false); 10762306a36Sopenharmony_ci while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) { 10862306a36Sopenharmony_ci preempt_disable(); 10962306a36Sopenharmony_ci pagefault_disable(); 11062306a36Sopenharmony_ci enable_kernel_vsx(); 11162306a36Sopenharmony_ci aes_p8_ctr32_encrypt_blocks(walk.src.virt.addr, 11262306a36Sopenharmony_ci walk.dst.virt.addr, 11362306a36Sopenharmony_ci nbytes / AES_BLOCK_SIZE, 11462306a36Sopenharmony_ci &ctx->enc_key, walk.iv); 11562306a36Sopenharmony_ci disable_kernel_vsx(); 11662306a36Sopenharmony_ci pagefault_enable(); 11762306a36Sopenharmony_ci preempt_enable(); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci do { 12062306a36Sopenharmony_ci crypto_inc(walk.iv, AES_BLOCK_SIZE); 12162306a36Sopenharmony_ci } while ((nbytes -= AES_BLOCK_SIZE) >= AES_BLOCK_SIZE); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci ret = skcipher_walk_done(&walk, nbytes); 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci if (nbytes) { 12662306a36Sopenharmony_ci p8_aes_ctr_final(ctx, &walk); 12762306a36Sopenharmony_ci ret = skcipher_walk_done(&walk, 0); 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci return ret; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistruct skcipher_alg p8_aes_ctr_alg = { 13362306a36Sopenharmony_ci .base.cra_name = "ctr(aes)", 13462306a36Sopenharmony_ci .base.cra_driver_name = "p8_aes_ctr", 13562306a36Sopenharmony_ci .base.cra_module = THIS_MODULE, 13662306a36Sopenharmony_ci .base.cra_priority = 2000, 13762306a36Sopenharmony_ci .base.cra_flags = CRYPTO_ALG_NEED_FALLBACK, 13862306a36Sopenharmony_ci .base.cra_blocksize = 1, 13962306a36Sopenharmony_ci .base.cra_ctxsize = sizeof(struct p8_aes_ctr_ctx), 14062306a36Sopenharmony_ci .setkey = p8_aes_ctr_setkey, 14162306a36Sopenharmony_ci .encrypt = p8_aes_ctr_crypt, 14262306a36Sopenharmony_ci .decrypt = p8_aes_ctr_crypt, 14362306a36Sopenharmony_ci .init = p8_aes_ctr_init, 14462306a36Sopenharmony_ci .exit = p8_aes_ctr_exit, 14562306a36Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 14662306a36Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 14762306a36Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 14862306a36Sopenharmony_ci .chunksize = AES_BLOCK_SIZE, 14962306a36Sopenharmony_ci}; 150