18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Cryptographic API.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * s390 implementation of the AES Cipher Algorithm with protected keys.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * s390 Version:
88c2ecf20Sopenharmony_ci *   Copyright IBM Corp. 2017,2020
98c2ecf20Sopenharmony_ci *   Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
108c2ecf20Sopenharmony_ci *		Harald Freudenberger <freude@de.ibm.com>
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#define KMSG_COMPONENT "paes_s390"
148c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <crypto/aes.h>
178c2ecf20Sopenharmony_ci#include <crypto/algapi.h>
188c2ecf20Sopenharmony_ci#include <linux/bug.h>
198c2ecf20Sopenharmony_ci#include <linux/err.h>
208c2ecf20Sopenharmony_ci#include <linux/module.h>
218c2ecf20Sopenharmony_ci#include <linux/cpufeature.h>
228c2ecf20Sopenharmony_ci#include <linux/init.h>
238c2ecf20Sopenharmony_ci#include <linux/mutex.h>
248c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
258c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h>
268c2ecf20Sopenharmony_ci#include <crypto/xts.h>
278c2ecf20Sopenharmony_ci#include <asm/cpacf.h>
288c2ecf20Sopenharmony_ci#include <asm/pkey.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci/*
318c2ecf20Sopenharmony_ci * Key blobs smaller/bigger than these defines are rejected
328c2ecf20Sopenharmony_ci * by the common code even before the individual setkey function
338c2ecf20Sopenharmony_ci * is called. As paes can handle different kinds of key blobs
348c2ecf20Sopenharmony_ci * and padding is also possible, the limits need to be generous.
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_ci#define PAES_MIN_KEYSIZE 16
378c2ecf20Sopenharmony_ci#define PAES_MAX_KEYSIZE MAXEP11AESKEYBLOBSIZE
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic u8 *ctrblk;
408c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(ctrblk_lock);
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic cpacf_mask_t km_functions, kmc_functions, kmctr_functions;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistruct key_blob {
458c2ecf20Sopenharmony_ci	/*
468c2ecf20Sopenharmony_ci	 * Small keys will be stored in the keybuf. Larger keys are
478c2ecf20Sopenharmony_ci	 * stored in extra allocated memory. In both cases does
488c2ecf20Sopenharmony_ci	 * key point to the memory where the key is stored.
498c2ecf20Sopenharmony_ci	 * The code distinguishes by checking keylen against
508c2ecf20Sopenharmony_ci	 * sizeof(keybuf). See the two following helper functions.
518c2ecf20Sopenharmony_ci	 */
528c2ecf20Sopenharmony_ci	u8 *key;
538c2ecf20Sopenharmony_ci	u8 keybuf[128];
548c2ecf20Sopenharmony_ci	unsigned int keylen;
558c2ecf20Sopenharmony_ci};
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic inline int _key_to_kb(struct key_blob *kb,
588c2ecf20Sopenharmony_ci			     const u8 *key,
598c2ecf20Sopenharmony_ci			     unsigned int keylen)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	struct clearkey_header {
628c2ecf20Sopenharmony_ci		u8  type;
638c2ecf20Sopenharmony_ci		u8  res0[3];
648c2ecf20Sopenharmony_ci		u8  version;
658c2ecf20Sopenharmony_ci		u8  res1[3];
668c2ecf20Sopenharmony_ci		u32 keytype;
678c2ecf20Sopenharmony_ci		u32 len;
688c2ecf20Sopenharmony_ci	} __packed * h;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	switch (keylen) {
718c2ecf20Sopenharmony_ci	case 16:
728c2ecf20Sopenharmony_ci	case 24:
738c2ecf20Sopenharmony_ci	case 32:
748c2ecf20Sopenharmony_ci		/* clear key value, prepare pkey clear key token in keybuf */
758c2ecf20Sopenharmony_ci		memset(kb->keybuf, 0, sizeof(kb->keybuf));
768c2ecf20Sopenharmony_ci		h = (struct clearkey_header *) kb->keybuf;
778c2ecf20Sopenharmony_ci		h->version = 0x02; /* TOKVER_CLEAR_KEY */
788c2ecf20Sopenharmony_ci		h->keytype = (keylen - 8) >> 3;
798c2ecf20Sopenharmony_ci		h->len = keylen;
808c2ecf20Sopenharmony_ci		memcpy(kb->keybuf + sizeof(*h), key, keylen);
818c2ecf20Sopenharmony_ci		kb->keylen = sizeof(*h) + keylen;
828c2ecf20Sopenharmony_ci		kb->key = kb->keybuf;
838c2ecf20Sopenharmony_ci		break;
848c2ecf20Sopenharmony_ci	default:
858c2ecf20Sopenharmony_ci		/* other key material, let pkey handle this */
868c2ecf20Sopenharmony_ci		if (keylen <= sizeof(kb->keybuf))
878c2ecf20Sopenharmony_ci			kb->key = kb->keybuf;
888c2ecf20Sopenharmony_ci		else {
898c2ecf20Sopenharmony_ci			kb->key = kmalloc(keylen, GFP_KERNEL);
908c2ecf20Sopenharmony_ci			if (!kb->key)
918c2ecf20Sopenharmony_ci				return -ENOMEM;
928c2ecf20Sopenharmony_ci		}
938c2ecf20Sopenharmony_ci		memcpy(kb->key, key, keylen);
948c2ecf20Sopenharmony_ci		kb->keylen = keylen;
958c2ecf20Sopenharmony_ci		break;
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	return 0;
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic inline void _free_kb_keybuf(struct key_blob *kb)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	if (kb->key && kb->key != kb->keybuf
1048c2ecf20Sopenharmony_ci	    && kb->keylen > sizeof(kb->keybuf)) {
1058c2ecf20Sopenharmony_ci		kfree(kb->key);
1068c2ecf20Sopenharmony_ci		kb->key = NULL;
1078c2ecf20Sopenharmony_ci	}
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistruct s390_paes_ctx {
1118c2ecf20Sopenharmony_ci	struct key_blob kb;
1128c2ecf20Sopenharmony_ci	struct pkey_protkey pk;
1138c2ecf20Sopenharmony_ci	spinlock_t pk_lock;
1148c2ecf20Sopenharmony_ci	unsigned long fc;
1158c2ecf20Sopenharmony_ci};
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistruct s390_pxts_ctx {
1188c2ecf20Sopenharmony_ci	struct key_blob kb[2];
1198c2ecf20Sopenharmony_ci	struct pkey_protkey pk[2];
1208c2ecf20Sopenharmony_ci	spinlock_t pk_lock;
1218c2ecf20Sopenharmony_ci	unsigned long fc;
1228c2ecf20Sopenharmony_ci};
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistatic inline int __paes_keyblob2pkey(struct key_blob *kb,
1258c2ecf20Sopenharmony_ci				     struct pkey_protkey *pk)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	int i, ret;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	/* try three times in case of failure */
1308c2ecf20Sopenharmony_ci	for (i = 0; i < 3; i++) {
1318c2ecf20Sopenharmony_ci		ret = pkey_keyblob2pkey(kb->key, kb->keylen, pk);
1328c2ecf20Sopenharmony_ci		if (ret == 0)
1338c2ecf20Sopenharmony_ci			break;
1348c2ecf20Sopenharmony_ci	}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	return ret;
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic inline int __paes_convert_key(struct s390_paes_ctx *ctx)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	struct pkey_protkey pkey;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	if (__paes_keyblob2pkey(&ctx->kb, &pkey))
1448c2ecf20Sopenharmony_ci		return -EINVAL;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	spin_lock_bh(&ctx->pk_lock);
1478c2ecf20Sopenharmony_ci	memcpy(&ctx->pk, &pkey, sizeof(pkey));
1488c2ecf20Sopenharmony_ci	spin_unlock_bh(&ctx->pk_lock);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	return 0;
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistatic int ecb_paes_init(struct crypto_skcipher *tfm)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	ctx->kb.key = NULL;
1588c2ecf20Sopenharmony_ci	spin_lock_init(&ctx->pk_lock);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	return 0;
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic void ecb_paes_exit(struct crypto_skcipher *tfm)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	_free_kb_keybuf(&ctx->kb);
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic inline int __ecb_paes_set_key(struct s390_paes_ctx *ctx)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	unsigned long fc;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	if (__paes_convert_key(ctx))
1758c2ecf20Sopenharmony_ci		return -EINVAL;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	/* Pick the correct function code based on the protected key type */
1788c2ecf20Sopenharmony_ci	fc = (ctx->pk.type == PKEY_KEYTYPE_AES_128) ? CPACF_KM_PAES_128 :
1798c2ecf20Sopenharmony_ci		(ctx->pk.type == PKEY_KEYTYPE_AES_192) ? CPACF_KM_PAES_192 :
1808c2ecf20Sopenharmony_ci		(ctx->pk.type == PKEY_KEYTYPE_AES_256) ? CPACF_KM_PAES_256 : 0;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	/* Check if the function code is available */
1838c2ecf20Sopenharmony_ci	ctx->fc = (fc && cpacf_test_func(&km_functions, fc)) ? fc : 0;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	return ctx->fc ? 0 : -EINVAL;
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistatic int ecb_paes_set_key(struct crypto_skcipher *tfm, const u8 *in_key,
1898c2ecf20Sopenharmony_ci			    unsigned int key_len)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	int rc;
1928c2ecf20Sopenharmony_ci	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	_free_kb_keybuf(&ctx->kb);
1958c2ecf20Sopenharmony_ci	rc = _key_to_kb(&ctx->kb, in_key, key_len);
1968c2ecf20Sopenharmony_ci	if (rc)
1978c2ecf20Sopenharmony_ci		return rc;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	return __ecb_paes_set_key(ctx);
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistatic int ecb_paes_crypt(struct skcipher_request *req, unsigned long modifier)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
2058c2ecf20Sopenharmony_ci	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
2068c2ecf20Sopenharmony_ci	struct skcipher_walk walk;
2078c2ecf20Sopenharmony_ci	unsigned int nbytes, n, k;
2088c2ecf20Sopenharmony_ci	int ret;
2098c2ecf20Sopenharmony_ci	struct {
2108c2ecf20Sopenharmony_ci		u8 key[MAXPROTKEYSIZE];
2118c2ecf20Sopenharmony_ci	} param;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	ret = skcipher_walk_virt(&walk, req, false);
2148c2ecf20Sopenharmony_ci	if (ret)
2158c2ecf20Sopenharmony_ci		return ret;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	spin_lock_bh(&ctx->pk_lock);
2188c2ecf20Sopenharmony_ci	memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
2198c2ecf20Sopenharmony_ci	spin_unlock_bh(&ctx->pk_lock);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	while ((nbytes = walk.nbytes) != 0) {
2228c2ecf20Sopenharmony_ci		/* only use complete blocks */
2238c2ecf20Sopenharmony_ci		n = nbytes & ~(AES_BLOCK_SIZE - 1);
2248c2ecf20Sopenharmony_ci		k = cpacf_km(ctx->fc | modifier, &param,
2258c2ecf20Sopenharmony_ci			     walk.dst.virt.addr, walk.src.virt.addr, n);
2268c2ecf20Sopenharmony_ci		if (k)
2278c2ecf20Sopenharmony_ci			ret = skcipher_walk_done(&walk, nbytes - k);
2288c2ecf20Sopenharmony_ci		if (k < n) {
2298c2ecf20Sopenharmony_ci			if (__paes_convert_key(ctx))
2308c2ecf20Sopenharmony_ci				return skcipher_walk_done(&walk, -EIO);
2318c2ecf20Sopenharmony_ci			spin_lock_bh(&ctx->pk_lock);
2328c2ecf20Sopenharmony_ci			memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
2338c2ecf20Sopenharmony_ci			spin_unlock_bh(&ctx->pk_lock);
2348c2ecf20Sopenharmony_ci		}
2358c2ecf20Sopenharmony_ci	}
2368c2ecf20Sopenharmony_ci	return ret;
2378c2ecf20Sopenharmony_ci}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_cistatic int ecb_paes_encrypt(struct skcipher_request *req)
2408c2ecf20Sopenharmony_ci{
2418c2ecf20Sopenharmony_ci	return ecb_paes_crypt(req, 0);
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic int ecb_paes_decrypt(struct skcipher_request *req)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	return ecb_paes_crypt(req, CPACF_DECRYPT);
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_cistatic struct skcipher_alg ecb_paes_alg = {
2508c2ecf20Sopenharmony_ci	.base.cra_name		=	"ecb(paes)",
2518c2ecf20Sopenharmony_ci	.base.cra_driver_name	=	"ecb-paes-s390",
2528c2ecf20Sopenharmony_ci	.base.cra_priority	=	401,	/* combo: aes + ecb + 1 */
2538c2ecf20Sopenharmony_ci	.base.cra_blocksize	=	AES_BLOCK_SIZE,
2548c2ecf20Sopenharmony_ci	.base.cra_ctxsize	=	sizeof(struct s390_paes_ctx),
2558c2ecf20Sopenharmony_ci	.base.cra_module	=	THIS_MODULE,
2568c2ecf20Sopenharmony_ci	.base.cra_list		=	LIST_HEAD_INIT(ecb_paes_alg.base.cra_list),
2578c2ecf20Sopenharmony_ci	.init			=	ecb_paes_init,
2588c2ecf20Sopenharmony_ci	.exit			=	ecb_paes_exit,
2598c2ecf20Sopenharmony_ci	.min_keysize		=	PAES_MIN_KEYSIZE,
2608c2ecf20Sopenharmony_ci	.max_keysize		=	PAES_MAX_KEYSIZE,
2618c2ecf20Sopenharmony_ci	.setkey			=	ecb_paes_set_key,
2628c2ecf20Sopenharmony_ci	.encrypt		=	ecb_paes_encrypt,
2638c2ecf20Sopenharmony_ci	.decrypt		=	ecb_paes_decrypt,
2648c2ecf20Sopenharmony_ci};
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_cistatic int cbc_paes_init(struct crypto_skcipher *tfm)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	ctx->kb.key = NULL;
2718c2ecf20Sopenharmony_ci	spin_lock_init(&ctx->pk_lock);
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	return 0;
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_cistatic void cbc_paes_exit(struct crypto_skcipher *tfm)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	_free_kb_keybuf(&ctx->kb);
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_cistatic inline int __cbc_paes_set_key(struct s390_paes_ctx *ctx)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	unsigned long fc;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	if (__paes_convert_key(ctx))
2888c2ecf20Sopenharmony_ci		return -EINVAL;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	/* Pick the correct function code based on the protected key type */
2918c2ecf20Sopenharmony_ci	fc = (ctx->pk.type == PKEY_KEYTYPE_AES_128) ? CPACF_KMC_PAES_128 :
2928c2ecf20Sopenharmony_ci		(ctx->pk.type == PKEY_KEYTYPE_AES_192) ? CPACF_KMC_PAES_192 :
2938c2ecf20Sopenharmony_ci		(ctx->pk.type == PKEY_KEYTYPE_AES_256) ? CPACF_KMC_PAES_256 : 0;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	/* Check if the function code is available */
2968c2ecf20Sopenharmony_ci	ctx->fc = (fc && cpacf_test_func(&kmc_functions, fc)) ? fc : 0;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	return ctx->fc ? 0 : -EINVAL;
2998c2ecf20Sopenharmony_ci}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_cistatic int cbc_paes_set_key(struct crypto_skcipher *tfm, const u8 *in_key,
3028c2ecf20Sopenharmony_ci			    unsigned int key_len)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	int rc;
3058c2ecf20Sopenharmony_ci	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	_free_kb_keybuf(&ctx->kb);
3088c2ecf20Sopenharmony_ci	rc = _key_to_kb(&ctx->kb, in_key, key_len);
3098c2ecf20Sopenharmony_ci	if (rc)
3108c2ecf20Sopenharmony_ci		return rc;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	return __cbc_paes_set_key(ctx);
3138c2ecf20Sopenharmony_ci}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_cistatic int cbc_paes_crypt(struct skcipher_request *req, unsigned long modifier)
3168c2ecf20Sopenharmony_ci{
3178c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
3188c2ecf20Sopenharmony_ci	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
3198c2ecf20Sopenharmony_ci	struct skcipher_walk walk;
3208c2ecf20Sopenharmony_ci	unsigned int nbytes, n, k;
3218c2ecf20Sopenharmony_ci	int ret;
3228c2ecf20Sopenharmony_ci	struct {
3238c2ecf20Sopenharmony_ci		u8 iv[AES_BLOCK_SIZE];
3248c2ecf20Sopenharmony_ci		u8 key[MAXPROTKEYSIZE];
3258c2ecf20Sopenharmony_ci	} param;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	ret = skcipher_walk_virt(&walk, req, false);
3288c2ecf20Sopenharmony_ci	if (ret)
3298c2ecf20Sopenharmony_ci		return ret;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	memcpy(param.iv, walk.iv, AES_BLOCK_SIZE);
3328c2ecf20Sopenharmony_ci	spin_lock_bh(&ctx->pk_lock);
3338c2ecf20Sopenharmony_ci	memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
3348c2ecf20Sopenharmony_ci	spin_unlock_bh(&ctx->pk_lock);
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	while ((nbytes = walk.nbytes) != 0) {
3378c2ecf20Sopenharmony_ci		/* only use complete blocks */
3388c2ecf20Sopenharmony_ci		n = nbytes & ~(AES_BLOCK_SIZE - 1);
3398c2ecf20Sopenharmony_ci		k = cpacf_kmc(ctx->fc | modifier, &param,
3408c2ecf20Sopenharmony_ci			      walk.dst.virt.addr, walk.src.virt.addr, n);
3418c2ecf20Sopenharmony_ci		if (k) {
3428c2ecf20Sopenharmony_ci			memcpy(walk.iv, param.iv, AES_BLOCK_SIZE);
3438c2ecf20Sopenharmony_ci			ret = skcipher_walk_done(&walk, nbytes - k);
3448c2ecf20Sopenharmony_ci		}
3458c2ecf20Sopenharmony_ci		if (k < n) {
3468c2ecf20Sopenharmony_ci			if (__paes_convert_key(ctx))
3478c2ecf20Sopenharmony_ci				return skcipher_walk_done(&walk, -EIO);
3488c2ecf20Sopenharmony_ci			spin_lock_bh(&ctx->pk_lock);
3498c2ecf20Sopenharmony_ci			memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
3508c2ecf20Sopenharmony_ci			spin_unlock_bh(&ctx->pk_lock);
3518c2ecf20Sopenharmony_ci		}
3528c2ecf20Sopenharmony_ci	}
3538c2ecf20Sopenharmony_ci	return ret;
3548c2ecf20Sopenharmony_ci}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_cistatic int cbc_paes_encrypt(struct skcipher_request *req)
3578c2ecf20Sopenharmony_ci{
3588c2ecf20Sopenharmony_ci	return cbc_paes_crypt(req, 0);
3598c2ecf20Sopenharmony_ci}
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_cistatic int cbc_paes_decrypt(struct skcipher_request *req)
3628c2ecf20Sopenharmony_ci{
3638c2ecf20Sopenharmony_ci	return cbc_paes_crypt(req, CPACF_DECRYPT);
3648c2ecf20Sopenharmony_ci}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_cistatic struct skcipher_alg cbc_paes_alg = {
3678c2ecf20Sopenharmony_ci	.base.cra_name		=	"cbc(paes)",
3688c2ecf20Sopenharmony_ci	.base.cra_driver_name	=	"cbc-paes-s390",
3698c2ecf20Sopenharmony_ci	.base.cra_priority	=	402,	/* ecb-paes-s390 + 1 */
3708c2ecf20Sopenharmony_ci	.base.cra_blocksize	=	AES_BLOCK_SIZE,
3718c2ecf20Sopenharmony_ci	.base.cra_ctxsize	=	sizeof(struct s390_paes_ctx),
3728c2ecf20Sopenharmony_ci	.base.cra_module	=	THIS_MODULE,
3738c2ecf20Sopenharmony_ci	.base.cra_list		=	LIST_HEAD_INIT(cbc_paes_alg.base.cra_list),
3748c2ecf20Sopenharmony_ci	.init			=	cbc_paes_init,
3758c2ecf20Sopenharmony_ci	.exit			=	cbc_paes_exit,
3768c2ecf20Sopenharmony_ci	.min_keysize		=	PAES_MIN_KEYSIZE,
3778c2ecf20Sopenharmony_ci	.max_keysize		=	PAES_MAX_KEYSIZE,
3788c2ecf20Sopenharmony_ci	.ivsize			=	AES_BLOCK_SIZE,
3798c2ecf20Sopenharmony_ci	.setkey			=	cbc_paes_set_key,
3808c2ecf20Sopenharmony_ci	.encrypt		=	cbc_paes_encrypt,
3818c2ecf20Sopenharmony_ci	.decrypt		=	cbc_paes_decrypt,
3828c2ecf20Sopenharmony_ci};
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_cistatic int xts_paes_init(struct crypto_skcipher *tfm)
3858c2ecf20Sopenharmony_ci{
3868c2ecf20Sopenharmony_ci	struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm);
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	ctx->kb[0].key = NULL;
3898c2ecf20Sopenharmony_ci	ctx->kb[1].key = NULL;
3908c2ecf20Sopenharmony_ci	spin_lock_init(&ctx->pk_lock);
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	return 0;
3938c2ecf20Sopenharmony_ci}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_cistatic void xts_paes_exit(struct crypto_skcipher *tfm)
3968c2ecf20Sopenharmony_ci{
3978c2ecf20Sopenharmony_ci	struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm);
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	_free_kb_keybuf(&ctx->kb[0]);
4008c2ecf20Sopenharmony_ci	_free_kb_keybuf(&ctx->kb[1]);
4018c2ecf20Sopenharmony_ci}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_cistatic inline int __xts_paes_convert_key(struct s390_pxts_ctx *ctx)
4048c2ecf20Sopenharmony_ci{
4058c2ecf20Sopenharmony_ci	struct pkey_protkey pkey0, pkey1;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	if (__paes_keyblob2pkey(&ctx->kb[0], &pkey0) ||
4088c2ecf20Sopenharmony_ci	    __paes_keyblob2pkey(&ctx->kb[1], &pkey1))
4098c2ecf20Sopenharmony_ci		return -EINVAL;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	spin_lock_bh(&ctx->pk_lock);
4128c2ecf20Sopenharmony_ci	memcpy(&ctx->pk[0], &pkey0, sizeof(pkey0));
4138c2ecf20Sopenharmony_ci	memcpy(&ctx->pk[1], &pkey1, sizeof(pkey1));
4148c2ecf20Sopenharmony_ci	spin_unlock_bh(&ctx->pk_lock);
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	return 0;
4178c2ecf20Sopenharmony_ci}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_cistatic inline int __xts_paes_set_key(struct s390_pxts_ctx *ctx)
4208c2ecf20Sopenharmony_ci{
4218c2ecf20Sopenharmony_ci	unsigned long fc;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	if (__xts_paes_convert_key(ctx))
4248c2ecf20Sopenharmony_ci		return -EINVAL;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	if (ctx->pk[0].type != ctx->pk[1].type)
4278c2ecf20Sopenharmony_ci		return -EINVAL;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	/* Pick the correct function code based on the protected key type */
4308c2ecf20Sopenharmony_ci	fc = (ctx->pk[0].type == PKEY_KEYTYPE_AES_128) ? CPACF_KM_PXTS_128 :
4318c2ecf20Sopenharmony_ci		(ctx->pk[0].type == PKEY_KEYTYPE_AES_256) ?
4328c2ecf20Sopenharmony_ci		CPACF_KM_PXTS_256 : 0;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	/* Check if the function code is available */
4358c2ecf20Sopenharmony_ci	ctx->fc = (fc && cpacf_test_func(&km_functions, fc)) ? fc : 0;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	return ctx->fc ? 0 : -EINVAL;
4388c2ecf20Sopenharmony_ci}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_cistatic int xts_paes_set_key(struct crypto_skcipher *tfm, const u8 *in_key,
4418c2ecf20Sopenharmony_ci			    unsigned int xts_key_len)
4428c2ecf20Sopenharmony_ci{
4438c2ecf20Sopenharmony_ci	int rc;
4448c2ecf20Sopenharmony_ci	struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm);
4458c2ecf20Sopenharmony_ci	u8 ckey[2 * AES_MAX_KEY_SIZE];
4468c2ecf20Sopenharmony_ci	unsigned int ckey_len, key_len;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	if (xts_key_len % 2)
4498c2ecf20Sopenharmony_ci		return -EINVAL;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	key_len = xts_key_len / 2;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	_free_kb_keybuf(&ctx->kb[0]);
4548c2ecf20Sopenharmony_ci	_free_kb_keybuf(&ctx->kb[1]);
4558c2ecf20Sopenharmony_ci	rc = _key_to_kb(&ctx->kb[0], in_key, key_len);
4568c2ecf20Sopenharmony_ci	if (rc)
4578c2ecf20Sopenharmony_ci		return rc;
4588c2ecf20Sopenharmony_ci	rc = _key_to_kb(&ctx->kb[1], in_key + key_len, key_len);
4598c2ecf20Sopenharmony_ci	if (rc)
4608c2ecf20Sopenharmony_ci		return rc;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	rc = __xts_paes_set_key(ctx);
4638c2ecf20Sopenharmony_ci	if (rc)
4648c2ecf20Sopenharmony_ci		return rc;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	/*
4678c2ecf20Sopenharmony_ci	 * xts_check_key verifies the key length is not odd and makes
4688c2ecf20Sopenharmony_ci	 * sure that the two keys are not the same. This can be done
4698c2ecf20Sopenharmony_ci	 * on the two protected keys as well
4708c2ecf20Sopenharmony_ci	 */
4718c2ecf20Sopenharmony_ci	ckey_len = (ctx->pk[0].type == PKEY_KEYTYPE_AES_128) ?
4728c2ecf20Sopenharmony_ci		AES_KEYSIZE_128 : AES_KEYSIZE_256;
4738c2ecf20Sopenharmony_ci	memcpy(ckey, ctx->pk[0].protkey, ckey_len);
4748c2ecf20Sopenharmony_ci	memcpy(ckey + ckey_len, ctx->pk[1].protkey, ckey_len);
4758c2ecf20Sopenharmony_ci	return xts_verify_key(tfm, ckey, 2*ckey_len);
4768c2ecf20Sopenharmony_ci}
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_cistatic int xts_paes_crypt(struct skcipher_request *req, unsigned long modifier)
4798c2ecf20Sopenharmony_ci{
4808c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
4818c2ecf20Sopenharmony_ci	struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm);
4828c2ecf20Sopenharmony_ci	struct skcipher_walk walk;
4838c2ecf20Sopenharmony_ci	unsigned int keylen, offset, nbytes, n, k;
4848c2ecf20Sopenharmony_ci	int ret;
4858c2ecf20Sopenharmony_ci	struct {
4868c2ecf20Sopenharmony_ci		u8 key[MAXPROTKEYSIZE];	/* key + verification pattern */
4878c2ecf20Sopenharmony_ci		u8 tweak[16];
4888c2ecf20Sopenharmony_ci		u8 block[16];
4898c2ecf20Sopenharmony_ci		u8 bit[16];
4908c2ecf20Sopenharmony_ci		u8 xts[16];
4918c2ecf20Sopenharmony_ci	} pcc_param;
4928c2ecf20Sopenharmony_ci	struct {
4938c2ecf20Sopenharmony_ci		u8 key[MAXPROTKEYSIZE];	/* key + verification pattern */
4948c2ecf20Sopenharmony_ci		u8 init[16];
4958c2ecf20Sopenharmony_ci	} xts_param;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	ret = skcipher_walk_virt(&walk, req, false);
4988c2ecf20Sopenharmony_ci	if (ret)
4998c2ecf20Sopenharmony_ci		return ret;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	keylen = (ctx->pk[0].type == PKEY_KEYTYPE_AES_128) ? 48 : 64;
5028c2ecf20Sopenharmony_ci	offset = (ctx->pk[0].type == PKEY_KEYTYPE_AES_128) ? 16 : 0;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	memset(&pcc_param, 0, sizeof(pcc_param));
5058c2ecf20Sopenharmony_ci	memcpy(pcc_param.tweak, walk.iv, sizeof(pcc_param.tweak));
5068c2ecf20Sopenharmony_ci	spin_lock_bh(&ctx->pk_lock);
5078c2ecf20Sopenharmony_ci	memcpy(pcc_param.key + offset, ctx->pk[1].protkey, keylen);
5088c2ecf20Sopenharmony_ci	memcpy(xts_param.key + offset, ctx->pk[0].protkey, keylen);
5098c2ecf20Sopenharmony_ci	spin_unlock_bh(&ctx->pk_lock);
5108c2ecf20Sopenharmony_ci	cpacf_pcc(ctx->fc, pcc_param.key + offset);
5118c2ecf20Sopenharmony_ci	memcpy(xts_param.init, pcc_param.xts, 16);
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	while ((nbytes = walk.nbytes) != 0) {
5148c2ecf20Sopenharmony_ci		/* only use complete blocks */
5158c2ecf20Sopenharmony_ci		n = nbytes & ~(AES_BLOCK_SIZE - 1);
5168c2ecf20Sopenharmony_ci		k = cpacf_km(ctx->fc | modifier, xts_param.key + offset,
5178c2ecf20Sopenharmony_ci			     walk.dst.virt.addr, walk.src.virt.addr, n);
5188c2ecf20Sopenharmony_ci		if (k)
5198c2ecf20Sopenharmony_ci			ret = skcipher_walk_done(&walk, nbytes - k);
5208c2ecf20Sopenharmony_ci		if (k < n) {
5218c2ecf20Sopenharmony_ci			if (__xts_paes_convert_key(ctx))
5228c2ecf20Sopenharmony_ci				return skcipher_walk_done(&walk, -EIO);
5238c2ecf20Sopenharmony_ci			spin_lock_bh(&ctx->pk_lock);
5248c2ecf20Sopenharmony_ci			memcpy(xts_param.key + offset,
5258c2ecf20Sopenharmony_ci			       ctx->pk[0].protkey, keylen);
5268c2ecf20Sopenharmony_ci			spin_unlock_bh(&ctx->pk_lock);
5278c2ecf20Sopenharmony_ci		}
5288c2ecf20Sopenharmony_ci	}
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	return ret;
5318c2ecf20Sopenharmony_ci}
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_cistatic int xts_paes_encrypt(struct skcipher_request *req)
5348c2ecf20Sopenharmony_ci{
5358c2ecf20Sopenharmony_ci	return xts_paes_crypt(req, 0);
5368c2ecf20Sopenharmony_ci}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_cistatic int xts_paes_decrypt(struct skcipher_request *req)
5398c2ecf20Sopenharmony_ci{
5408c2ecf20Sopenharmony_ci	return xts_paes_crypt(req, CPACF_DECRYPT);
5418c2ecf20Sopenharmony_ci}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_cistatic struct skcipher_alg xts_paes_alg = {
5448c2ecf20Sopenharmony_ci	.base.cra_name		=	"xts(paes)",
5458c2ecf20Sopenharmony_ci	.base.cra_driver_name	=	"xts-paes-s390",
5468c2ecf20Sopenharmony_ci	.base.cra_priority	=	402,	/* ecb-paes-s390 + 1 */
5478c2ecf20Sopenharmony_ci	.base.cra_blocksize	=	AES_BLOCK_SIZE,
5488c2ecf20Sopenharmony_ci	.base.cra_ctxsize	=	sizeof(struct s390_pxts_ctx),
5498c2ecf20Sopenharmony_ci	.base.cra_module	=	THIS_MODULE,
5508c2ecf20Sopenharmony_ci	.base.cra_list		=	LIST_HEAD_INIT(xts_paes_alg.base.cra_list),
5518c2ecf20Sopenharmony_ci	.init			=	xts_paes_init,
5528c2ecf20Sopenharmony_ci	.exit			=	xts_paes_exit,
5538c2ecf20Sopenharmony_ci	.min_keysize		=	2 * PAES_MIN_KEYSIZE,
5548c2ecf20Sopenharmony_ci	.max_keysize		=	2 * PAES_MAX_KEYSIZE,
5558c2ecf20Sopenharmony_ci	.ivsize			=	AES_BLOCK_SIZE,
5568c2ecf20Sopenharmony_ci	.setkey			=	xts_paes_set_key,
5578c2ecf20Sopenharmony_ci	.encrypt		=	xts_paes_encrypt,
5588c2ecf20Sopenharmony_ci	.decrypt		=	xts_paes_decrypt,
5598c2ecf20Sopenharmony_ci};
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_cistatic int ctr_paes_init(struct crypto_skcipher *tfm)
5628c2ecf20Sopenharmony_ci{
5638c2ecf20Sopenharmony_ci	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	ctx->kb.key = NULL;
5668c2ecf20Sopenharmony_ci	spin_lock_init(&ctx->pk_lock);
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	return 0;
5698c2ecf20Sopenharmony_ci}
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_cistatic void ctr_paes_exit(struct crypto_skcipher *tfm)
5728c2ecf20Sopenharmony_ci{
5738c2ecf20Sopenharmony_ci	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	_free_kb_keybuf(&ctx->kb);
5768c2ecf20Sopenharmony_ci}
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_cistatic inline int __ctr_paes_set_key(struct s390_paes_ctx *ctx)
5798c2ecf20Sopenharmony_ci{
5808c2ecf20Sopenharmony_ci	unsigned long fc;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	if (__paes_convert_key(ctx))
5838c2ecf20Sopenharmony_ci		return -EINVAL;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	/* Pick the correct function code based on the protected key type */
5868c2ecf20Sopenharmony_ci	fc = (ctx->pk.type == PKEY_KEYTYPE_AES_128) ? CPACF_KMCTR_PAES_128 :
5878c2ecf20Sopenharmony_ci		(ctx->pk.type == PKEY_KEYTYPE_AES_192) ? CPACF_KMCTR_PAES_192 :
5888c2ecf20Sopenharmony_ci		(ctx->pk.type == PKEY_KEYTYPE_AES_256) ?
5898c2ecf20Sopenharmony_ci		CPACF_KMCTR_PAES_256 : 0;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	/* Check if the function code is available */
5928c2ecf20Sopenharmony_ci	ctx->fc = (fc && cpacf_test_func(&kmctr_functions, fc)) ? fc : 0;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	return ctx->fc ? 0 : -EINVAL;
5958c2ecf20Sopenharmony_ci}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_cistatic int ctr_paes_set_key(struct crypto_skcipher *tfm, const u8 *in_key,
5988c2ecf20Sopenharmony_ci			    unsigned int key_len)
5998c2ecf20Sopenharmony_ci{
6008c2ecf20Sopenharmony_ci	int rc;
6018c2ecf20Sopenharmony_ci	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	_free_kb_keybuf(&ctx->kb);
6048c2ecf20Sopenharmony_ci	rc = _key_to_kb(&ctx->kb, in_key, key_len);
6058c2ecf20Sopenharmony_ci	if (rc)
6068c2ecf20Sopenharmony_ci		return rc;
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	return __ctr_paes_set_key(ctx);
6098c2ecf20Sopenharmony_ci}
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_cistatic unsigned int __ctrblk_init(u8 *ctrptr, u8 *iv, unsigned int nbytes)
6128c2ecf20Sopenharmony_ci{
6138c2ecf20Sopenharmony_ci	unsigned int i, n;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	/* only use complete blocks, max. PAGE_SIZE */
6168c2ecf20Sopenharmony_ci	memcpy(ctrptr, iv, AES_BLOCK_SIZE);
6178c2ecf20Sopenharmony_ci	n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : nbytes & ~(AES_BLOCK_SIZE - 1);
6188c2ecf20Sopenharmony_ci	for (i = (n / AES_BLOCK_SIZE) - 1; i > 0; i--) {
6198c2ecf20Sopenharmony_ci		memcpy(ctrptr + AES_BLOCK_SIZE, ctrptr, AES_BLOCK_SIZE);
6208c2ecf20Sopenharmony_ci		crypto_inc(ctrptr + AES_BLOCK_SIZE, AES_BLOCK_SIZE);
6218c2ecf20Sopenharmony_ci		ctrptr += AES_BLOCK_SIZE;
6228c2ecf20Sopenharmony_ci	}
6238c2ecf20Sopenharmony_ci	return n;
6248c2ecf20Sopenharmony_ci}
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_cistatic int ctr_paes_crypt(struct skcipher_request *req)
6278c2ecf20Sopenharmony_ci{
6288c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
6298c2ecf20Sopenharmony_ci	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
6308c2ecf20Sopenharmony_ci	u8 buf[AES_BLOCK_SIZE], *ctrptr;
6318c2ecf20Sopenharmony_ci	struct skcipher_walk walk;
6328c2ecf20Sopenharmony_ci	unsigned int nbytes, n, k;
6338c2ecf20Sopenharmony_ci	int ret, locked;
6348c2ecf20Sopenharmony_ci	struct {
6358c2ecf20Sopenharmony_ci		u8 key[MAXPROTKEYSIZE];
6368c2ecf20Sopenharmony_ci	} param;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	ret = skcipher_walk_virt(&walk, req, false);
6398c2ecf20Sopenharmony_ci	if (ret)
6408c2ecf20Sopenharmony_ci		return ret;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	spin_lock_bh(&ctx->pk_lock);
6438c2ecf20Sopenharmony_ci	memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
6448c2ecf20Sopenharmony_ci	spin_unlock_bh(&ctx->pk_lock);
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	locked = mutex_trylock(&ctrblk_lock);
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) {
6498c2ecf20Sopenharmony_ci		n = AES_BLOCK_SIZE;
6508c2ecf20Sopenharmony_ci		if (nbytes >= 2*AES_BLOCK_SIZE && locked)
6518c2ecf20Sopenharmony_ci			n = __ctrblk_init(ctrblk, walk.iv, nbytes);
6528c2ecf20Sopenharmony_ci		ctrptr = (n > AES_BLOCK_SIZE) ? ctrblk : walk.iv;
6538c2ecf20Sopenharmony_ci		k = cpacf_kmctr(ctx->fc, &param, walk.dst.virt.addr,
6548c2ecf20Sopenharmony_ci				walk.src.virt.addr, n, ctrptr);
6558c2ecf20Sopenharmony_ci		if (k) {
6568c2ecf20Sopenharmony_ci			if (ctrptr == ctrblk)
6578c2ecf20Sopenharmony_ci				memcpy(walk.iv, ctrptr + k - AES_BLOCK_SIZE,
6588c2ecf20Sopenharmony_ci				       AES_BLOCK_SIZE);
6598c2ecf20Sopenharmony_ci			crypto_inc(walk.iv, AES_BLOCK_SIZE);
6608c2ecf20Sopenharmony_ci			ret = skcipher_walk_done(&walk, nbytes - k);
6618c2ecf20Sopenharmony_ci		}
6628c2ecf20Sopenharmony_ci		if (k < n) {
6638c2ecf20Sopenharmony_ci			if (__paes_convert_key(ctx)) {
6648c2ecf20Sopenharmony_ci				if (locked)
6658c2ecf20Sopenharmony_ci					mutex_unlock(&ctrblk_lock);
6668c2ecf20Sopenharmony_ci				return skcipher_walk_done(&walk, -EIO);
6678c2ecf20Sopenharmony_ci			}
6688c2ecf20Sopenharmony_ci			spin_lock_bh(&ctx->pk_lock);
6698c2ecf20Sopenharmony_ci			memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
6708c2ecf20Sopenharmony_ci			spin_unlock_bh(&ctx->pk_lock);
6718c2ecf20Sopenharmony_ci		}
6728c2ecf20Sopenharmony_ci	}
6738c2ecf20Sopenharmony_ci	if (locked)
6748c2ecf20Sopenharmony_ci		mutex_unlock(&ctrblk_lock);
6758c2ecf20Sopenharmony_ci	/*
6768c2ecf20Sopenharmony_ci	 * final block may be < AES_BLOCK_SIZE, copy only nbytes
6778c2ecf20Sopenharmony_ci	 */
6788c2ecf20Sopenharmony_ci	if (nbytes) {
6798c2ecf20Sopenharmony_ci		memset(buf, 0, AES_BLOCK_SIZE);
6808c2ecf20Sopenharmony_ci		memcpy(buf, walk.src.virt.addr, nbytes);
6818c2ecf20Sopenharmony_ci		while (1) {
6828c2ecf20Sopenharmony_ci			if (cpacf_kmctr(ctx->fc, &param, buf,
6838c2ecf20Sopenharmony_ci					buf, AES_BLOCK_SIZE,
6848c2ecf20Sopenharmony_ci					walk.iv) == AES_BLOCK_SIZE)
6858c2ecf20Sopenharmony_ci				break;
6868c2ecf20Sopenharmony_ci			if (__paes_convert_key(ctx))
6878c2ecf20Sopenharmony_ci				return skcipher_walk_done(&walk, -EIO);
6888c2ecf20Sopenharmony_ci			spin_lock_bh(&ctx->pk_lock);
6898c2ecf20Sopenharmony_ci			memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE);
6908c2ecf20Sopenharmony_ci			spin_unlock_bh(&ctx->pk_lock);
6918c2ecf20Sopenharmony_ci		}
6928c2ecf20Sopenharmony_ci		memcpy(walk.dst.virt.addr, buf, nbytes);
6938c2ecf20Sopenharmony_ci		crypto_inc(walk.iv, AES_BLOCK_SIZE);
6948c2ecf20Sopenharmony_ci		ret = skcipher_walk_done(&walk, nbytes);
6958c2ecf20Sopenharmony_ci	}
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	return ret;
6988c2ecf20Sopenharmony_ci}
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_cistatic struct skcipher_alg ctr_paes_alg = {
7018c2ecf20Sopenharmony_ci	.base.cra_name		=	"ctr(paes)",
7028c2ecf20Sopenharmony_ci	.base.cra_driver_name	=	"ctr-paes-s390",
7038c2ecf20Sopenharmony_ci	.base.cra_priority	=	402,	/* ecb-paes-s390 + 1 */
7048c2ecf20Sopenharmony_ci	.base.cra_blocksize	=	1,
7058c2ecf20Sopenharmony_ci	.base.cra_ctxsize	=	sizeof(struct s390_paes_ctx),
7068c2ecf20Sopenharmony_ci	.base.cra_module	=	THIS_MODULE,
7078c2ecf20Sopenharmony_ci	.base.cra_list		=	LIST_HEAD_INIT(ctr_paes_alg.base.cra_list),
7088c2ecf20Sopenharmony_ci	.init			=	ctr_paes_init,
7098c2ecf20Sopenharmony_ci	.exit			=	ctr_paes_exit,
7108c2ecf20Sopenharmony_ci	.min_keysize		=	PAES_MIN_KEYSIZE,
7118c2ecf20Sopenharmony_ci	.max_keysize		=	PAES_MAX_KEYSIZE,
7128c2ecf20Sopenharmony_ci	.ivsize			=	AES_BLOCK_SIZE,
7138c2ecf20Sopenharmony_ci	.setkey			=	ctr_paes_set_key,
7148c2ecf20Sopenharmony_ci	.encrypt		=	ctr_paes_crypt,
7158c2ecf20Sopenharmony_ci	.decrypt		=	ctr_paes_crypt,
7168c2ecf20Sopenharmony_ci	.chunksize		=	AES_BLOCK_SIZE,
7178c2ecf20Sopenharmony_ci};
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_cistatic inline void __crypto_unregister_skcipher(struct skcipher_alg *alg)
7208c2ecf20Sopenharmony_ci{
7218c2ecf20Sopenharmony_ci	if (!list_empty(&alg->base.cra_list))
7228c2ecf20Sopenharmony_ci		crypto_unregister_skcipher(alg);
7238c2ecf20Sopenharmony_ci}
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_cistatic void paes_s390_fini(void)
7268c2ecf20Sopenharmony_ci{
7278c2ecf20Sopenharmony_ci	__crypto_unregister_skcipher(&ctr_paes_alg);
7288c2ecf20Sopenharmony_ci	__crypto_unregister_skcipher(&xts_paes_alg);
7298c2ecf20Sopenharmony_ci	__crypto_unregister_skcipher(&cbc_paes_alg);
7308c2ecf20Sopenharmony_ci	__crypto_unregister_skcipher(&ecb_paes_alg);
7318c2ecf20Sopenharmony_ci	if (ctrblk)
7328c2ecf20Sopenharmony_ci		free_page((unsigned long) ctrblk);
7338c2ecf20Sopenharmony_ci}
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_cistatic int __init paes_s390_init(void)
7368c2ecf20Sopenharmony_ci{
7378c2ecf20Sopenharmony_ci	int ret;
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	/* Query available functions for KM, KMC and KMCTR */
7408c2ecf20Sopenharmony_ci	cpacf_query(CPACF_KM, &km_functions);
7418c2ecf20Sopenharmony_ci	cpacf_query(CPACF_KMC, &kmc_functions);
7428c2ecf20Sopenharmony_ci	cpacf_query(CPACF_KMCTR, &kmctr_functions);
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	if (cpacf_test_func(&km_functions, CPACF_KM_PAES_128) ||
7458c2ecf20Sopenharmony_ci	    cpacf_test_func(&km_functions, CPACF_KM_PAES_192) ||
7468c2ecf20Sopenharmony_ci	    cpacf_test_func(&km_functions, CPACF_KM_PAES_256)) {
7478c2ecf20Sopenharmony_ci		ret = crypto_register_skcipher(&ecb_paes_alg);
7488c2ecf20Sopenharmony_ci		if (ret)
7498c2ecf20Sopenharmony_ci			goto out_err;
7508c2ecf20Sopenharmony_ci	}
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	if (cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_128) ||
7538c2ecf20Sopenharmony_ci	    cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_192) ||
7548c2ecf20Sopenharmony_ci	    cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_256)) {
7558c2ecf20Sopenharmony_ci		ret = crypto_register_skcipher(&cbc_paes_alg);
7568c2ecf20Sopenharmony_ci		if (ret)
7578c2ecf20Sopenharmony_ci			goto out_err;
7588c2ecf20Sopenharmony_ci	}
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	if (cpacf_test_func(&km_functions, CPACF_KM_PXTS_128) ||
7618c2ecf20Sopenharmony_ci	    cpacf_test_func(&km_functions, CPACF_KM_PXTS_256)) {
7628c2ecf20Sopenharmony_ci		ret = crypto_register_skcipher(&xts_paes_alg);
7638c2ecf20Sopenharmony_ci		if (ret)
7648c2ecf20Sopenharmony_ci			goto out_err;
7658c2ecf20Sopenharmony_ci	}
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	if (cpacf_test_func(&kmctr_functions, CPACF_KMCTR_PAES_128) ||
7688c2ecf20Sopenharmony_ci	    cpacf_test_func(&kmctr_functions, CPACF_KMCTR_PAES_192) ||
7698c2ecf20Sopenharmony_ci	    cpacf_test_func(&kmctr_functions, CPACF_KMCTR_PAES_256)) {
7708c2ecf20Sopenharmony_ci		ctrblk = (u8 *) __get_free_page(GFP_KERNEL);
7718c2ecf20Sopenharmony_ci		if (!ctrblk) {
7728c2ecf20Sopenharmony_ci			ret = -ENOMEM;
7738c2ecf20Sopenharmony_ci			goto out_err;
7748c2ecf20Sopenharmony_ci		}
7758c2ecf20Sopenharmony_ci		ret = crypto_register_skcipher(&ctr_paes_alg);
7768c2ecf20Sopenharmony_ci		if (ret)
7778c2ecf20Sopenharmony_ci			goto out_err;
7788c2ecf20Sopenharmony_ci	}
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	return 0;
7818c2ecf20Sopenharmony_ciout_err:
7828c2ecf20Sopenharmony_ci	paes_s390_fini();
7838c2ecf20Sopenharmony_ci	return ret;
7848c2ecf20Sopenharmony_ci}
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_cimodule_init(paes_s390_init);
7878c2ecf20Sopenharmony_cimodule_exit(paes_s390_fini);
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("paes");
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm with protected keys");
7928c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
793