162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/* Glue code for CAMELLIA encryption optimized for sparc64 crypto opcodes.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 2012 David S. Miller <davem@davemloft.net>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/crypto.h>
1062306a36Sopenharmony_ci#include <linux/init.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/mm.h>
1362306a36Sopenharmony_ci#include <linux/types.h>
1462306a36Sopenharmony_ci#include <crypto/algapi.h>
1562306a36Sopenharmony_ci#include <crypto/internal/skcipher.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <asm/fpumacro.h>
1862306a36Sopenharmony_ci#include <asm/pstate.h>
1962306a36Sopenharmony_ci#include <asm/elf.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include "opcodes.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define CAMELLIA_MIN_KEY_SIZE        16
2462306a36Sopenharmony_ci#define CAMELLIA_MAX_KEY_SIZE        32
2562306a36Sopenharmony_ci#define CAMELLIA_BLOCK_SIZE          16
2662306a36Sopenharmony_ci#define CAMELLIA_TABLE_BYTE_LEN     272
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistruct camellia_sparc64_ctx {
2962306a36Sopenharmony_ci	u64 encrypt_key[CAMELLIA_TABLE_BYTE_LEN / sizeof(u64)];
3062306a36Sopenharmony_ci	u64 decrypt_key[CAMELLIA_TABLE_BYTE_LEN / sizeof(u64)];
3162306a36Sopenharmony_ci	int key_len;
3262306a36Sopenharmony_ci};
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ciextern void camellia_sparc64_key_expand(const u32 *in_key, u64 *encrypt_key,
3562306a36Sopenharmony_ci					unsigned int key_len, u64 *decrypt_key);
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic int camellia_set_key(struct crypto_tfm *tfm, const u8 *_in_key,
3862306a36Sopenharmony_ci			    unsigned int key_len)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	struct camellia_sparc64_ctx *ctx = crypto_tfm_ctx(tfm);
4162306a36Sopenharmony_ci	const u32 *in_key = (const u32 *) _in_key;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	if (key_len != 16 && key_len != 24 && key_len != 32)
4462306a36Sopenharmony_ci		return -EINVAL;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	ctx->key_len = key_len;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	camellia_sparc64_key_expand(in_key, &ctx->encrypt_key[0],
4962306a36Sopenharmony_ci				    key_len, &ctx->decrypt_key[0]);
5062306a36Sopenharmony_ci	return 0;
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic int camellia_set_key_skcipher(struct crypto_skcipher *tfm,
5462306a36Sopenharmony_ci				     const u8 *in_key, unsigned int key_len)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	return camellia_set_key(crypto_skcipher_tfm(tfm), in_key, key_len);
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ciextern void camellia_sparc64_crypt(const u64 *key, const u32 *input,
6062306a36Sopenharmony_ci				   u32 *output, unsigned int key_len);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic void camellia_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	struct camellia_sparc64_ctx *ctx = crypto_tfm_ctx(tfm);
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	camellia_sparc64_crypt(&ctx->encrypt_key[0],
6762306a36Sopenharmony_ci			       (const u32 *) src,
6862306a36Sopenharmony_ci			       (u32 *) dst, ctx->key_len);
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic void camellia_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	struct camellia_sparc64_ctx *ctx = crypto_tfm_ctx(tfm);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	camellia_sparc64_crypt(&ctx->decrypt_key[0],
7662306a36Sopenharmony_ci			       (const u32 *) src,
7762306a36Sopenharmony_ci			       (u32 *) dst, ctx->key_len);
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ciextern void camellia_sparc64_load_keys(const u64 *key, unsigned int key_len);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_citypedef void ecb_crypt_op(const u64 *input, u64 *output, unsigned int len,
8362306a36Sopenharmony_ci			  const u64 *key);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ciextern ecb_crypt_op camellia_sparc64_ecb_crypt_3_grand_rounds;
8662306a36Sopenharmony_ciextern ecb_crypt_op camellia_sparc64_ecb_crypt_4_grand_rounds;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic int __ecb_crypt(struct skcipher_request *req, bool encrypt)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
9162306a36Sopenharmony_ci	const struct camellia_sparc64_ctx *ctx = crypto_skcipher_ctx(tfm);
9262306a36Sopenharmony_ci	struct skcipher_walk walk;
9362306a36Sopenharmony_ci	ecb_crypt_op *op;
9462306a36Sopenharmony_ci	const u64 *key;
9562306a36Sopenharmony_ci	unsigned int nbytes;
9662306a36Sopenharmony_ci	int err;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	op = camellia_sparc64_ecb_crypt_3_grand_rounds;
9962306a36Sopenharmony_ci	if (ctx->key_len != 16)
10062306a36Sopenharmony_ci		op = camellia_sparc64_ecb_crypt_4_grand_rounds;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, true);
10362306a36Sopenharmony_ci	if (err)
10462306a36Sopenharmony_ci		return err;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	if (encrypt)
10762306a36Sopenharmony_ci		key = &ctx->encrypt_key[0];
10862306a36Sopenharmony_ci	else
10962306a36Sopenharmony_ci		key = &ctx->decrypt_key[0];
11062306a36Sopenharmony_ci	camellia_sparc64_load_keys(key, ctx->key_len);
11162306a36Sopenharmony_ci	while ((nbytes = walk.nbytes) != 0) {
11262306a36Sopenharmony_ci		op(walk.src.virt.addr, walk.dst.virt.addr,
11362306a36Sopenharmony_ci		   round_down(nbytes, CAMELLIA_BLOCK_SIZE), key);
11462306a36Sopenharmony_ci		err = skcipher_walk_done(&walk, nbytes % CAMELLIA_BLOCK_SIZE);
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci	fprs_write(0);
11762306a36Sopenharmony_ci	return err;
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic int ecb_encrypt(struct skcipher_request *req)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	return __ecb_crypt(req, true);
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic int ecb_decrypt(struct skcipher_request *req)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	return __ecb_crypt(req, false);
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_citypedef void cbc_crypt_op(const u64 *input, u64 *output, unsigned int len,
13162306a36Sopenharmony_ci			  const u64 *key, u64 *iv);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ciextern cbc_crypt_op camellia_sparc64_cbc_encrypt_3_grand_rounds;
13462306a36Sopenharmony_ciextern cbc_crypt_op camellia_sparc64_cbc_encrypt_4_grand_rounds;
13562306a36Sopenharmony_ciextern cbc_crypt_op camellia_sparc64_cbc_decrypt_3_grand_rounds;
13662306a36Sopenharmony_ciextern cbc_crypt_op camellia_sparc64_cbc_decrypt_4_grand_rounds;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistatic int cbc_encrypt(struct skcipher_request *req)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
14162306a36Sopenharmony_ci	const struct camellia_sparc64_ctx *ctx = crypto_skcipher_ctx(tfm);
14262306a36Sopenharmony_ci	struct skcipher_walk walk;
14362306a36Sopenharmony_ci	cbc_crypt_op *op;
14462306a36Sopenharmony_ci	const u64 *key;
14562306a36Sopenharmony_ci	unsigned int nbytes;
14662306a36Sopenharmony_ci	int err;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	op = camellia_sparc64_cbc_encrypt_3_grand_rounds;
14962306a36Sopenharmony_ci	if (ctx->key_len != 16)
15062306a36Sopenharmony_ci		op = camellia_sparc64_cbc_encrypt_4_grand_rounds;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, true);
15362306a36Sopenharmony_ci	if (err)
15462306a36Sopenharmony_ci		return err;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	key = &ctx->encrypt_key[0];
15762306a36Sopenharmony_ci	camellia_sparc64_load_keys(key, ctx->key_len);
15862306a36Sopenharmony_ci	while ((nbytes = walk.nbytes) != 0) {
15962306a36Sopenharmony_ci		op(walk.src.virt.addr, walk.dst.virt.addr,
16062306a36Sopenharmony_ci		   round_down(nbytes, CAMELLIA_BLOCK_SIZE), key, walk.iv);
16162306a36Sopenharmony_ci		err = skcipher_walk_done(&walk, nbytes % CAMELLIA_BLOCK_SIZE);
16262306a36Sopenharmony_ci	}
16362306a36Sopenharmony_ci	fprs_write(0);
16462306a36Sopenharmony_ci	return err;
16562306a36Sopenharmony_ci}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cistatic int cbc_decrypt(struct skcipher_request *req)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
17062306a36Sopenharmony_ci	const struct camellia_sparc64_ctx *ctx = crypto_skcipher_ctx(tfm);
17162306a36Sopenharmony_ci	struct skcipher_walk walk;
17262306a36Sopenharmony_ci	cbc_crypt_op *op;
17362306a36Sopenharmony_ci	const u64 *key;
17462306a36Sopenharmony_ci	unsigned int nbytes;
17562306a36Sopenharmony_ci	int err;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	op = camellia_sparc64_cbc_decrypt_3_grand_rounds;
17862306a36Sopenharmony_ci	if (ctx->key_len != 16)
17962306a36Sopenharmony_ci		op = camellia_sparc64_cbc_decrypt_4_grand_rounds;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, true);
18262306a36Sopenharmony_ci	if (err)
18362306a36Sopenharmony_ci		return err;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	key = &ctx->decrypt_key[0];
18662306a36Sopenharmony_ci	camellia_sparc64_load_keys(key, ctx->key_len);
18762306a36Sopenharmony_ci	while ((nbytes = walk.nbytes) != 0) {
18862306a36Sopenharmony_ci		op(walk.src.virt.addr, walk.dst.virt.addr,
18962306a36Sopenharmony_ci		   round_down(nbytes, CAMELLIA_BLOCK_SIZE), key, walk.iv);
19062306a36Sopenharmony_ci		err = skcipher_walk_done(&walk, nbytes % CAMELLIA_BLOCK_SIZE);
19162306a36Sopenharmony_ci	}
19262306a36Sopenharmony_ci	fprs_write(0);
19362306a36Sopenharmony_ci	return err;
19462306a36Sopenharmony_ci}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_cistatic struct crypto_alg cipher_alg = {
19762306a36Sopenharmony_ci	.cra_name		= "camellia",
19862306a36Sopenharmony_ci	.cra_driver_name	= "camellia-sparc64",
19962306a36Sopenharmony_ci	.cra_priority		= SPARC_CR_OPCODE_PRIORITY,
20062306a36Sopenharmony_ci	.cra_flags		= CRYPTO_ALG_TYPE_CIPHER,
20162306a36Sopenharmony_ci	.cra_blocksize		= CAMELLIA_BLOCK_SIZE,
20262306a36Sopenharmony_ci	.cra_ctxsize		= sizeof(struct camellia_sparc64_ctx),
20362306a36Sopenharmony_ci	.cra_alignmask		= 3,
20462306a36Sopenharmony_ci	.cra_module		= THIS_MODULE,
20562306a36Sopenharmony_ci	.cra_u	= {
20662306a36Sopenharmony_ci		.cipher	= {
20762306a36Sopenharmony_ci			.cia_min_keysize	= CAMELLIA_MIN_KEY_SIZE,
20862306a36Sopenharmony_ci			.cia_max_keysize	= CAMELLIA_MAX_KEY_SIZE,
20962306a36Sopenharmony_ci			.cia_setkey		= camellia_set_key,
21062306a36Sopenharmony_ci			.cia_encrypt		= camellia_encrypt,
21162306a36Sopenharmony_ci			.cia_decrypt		= camellia_decrypt
21262306a36Sopenharmony_ci		}
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci};
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic struct skcipher_alg skcipher_algs[] = {
21762306a36Sopenharmony_ci	{
21862306a36Sopenharmony_ci		.base.cra_name		= "ecb(camellia)",
21962306a36Sopenharmony_ci		.base.cra_driver_name	= "ecb-camellia-sparc64",
22062306a36Sopenharmony_ci		.base.cra_priority	= SPARC_CR_OPCODE_PRIORITY,
22162306a36Sopenharmony_ci		.base.cra_blocksize	= CAMELLIA_BLOCK_SIZE,
22262306a36Sopenharmony_ci		.base.cra_ctxsize	= sizeof(struct camellia_sparc64_ctx),
22362306a36Sopenharmony_ci		.base.cra_alignmask	= 7,
22462306a36Sopenharmony_ci		.base.cra_module	= THIS_MODULE,
22562306a36Sopenharmony_ci		.min_keysize		= CAMELLIA_MIN_KEY_SIZE,
22662306a36Sopenharmony_ci		.max_keysize		= CAMELLIA_MAX_KEY_SIZE,
22762306a36Sopenharmony_ci		.setkey			= camellia_set_key_skcipher,
22862306a36Sopenharmony_ci		.encrypt		= ecb_encrypt,
22962306a36Sopenharmony_ci		.decrypt		= ecb_decrypt,
23062306a36Sopenharmony_ci	}, {
23162306a36Sopenharmony_ci		.base.cra_name		= "cbc(camellia)",
23262306a36Sopenharmony_ci		.base.cra_driver_name	= "cbc-camellia-sparc64",
23362306a36Sopenharmony_ci		.base.cra_priority	= SPARC_CR_OPCODE_PRIORITY,
23462306a36Sopenharmony_ci		.base.cra_blocksize	= CAMELLIA_BLOCK_SIZE,
23562306a36Sopenharmony_ci		.base.cra_ctxsize	= sizeof(struct camellia_sparc64_ctx),
23662306a36Sopenharmony_ci		.base.cra_alignmask	= 7,
23762306a36Sopenharmony_ci		.base.cra_module	= THIS_MODULE,
23862306a36Sopenharmony_ci		.min_keysize		= CAMELLIA_MIN_KEY_SIZE,
23962306a36Sopenharmony_ci		.max_keysize		= CAMELLIA_MAX_KEY_SIZE,
24062306a36Sopenharmony_ci		.ivsize			= CAMELLIA_BLOCK_SIZE,
24162306a36Sopenharmony_ci		.setkey			= camellia_set_key_skcipher,
24262306a36Sopenharmony_ci		.encrypt		= cbc_encrypt,
24362306a36Sopenharmony_ci		.decrypt		= cbc_decrypt,
24462306a36Sopenharmony_ci	}
24562306a36Sopenharmony_ci};
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistatic bool __init sparc64_has_camellia_opcode(void)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	unsigned long cfr;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	if (!(sparc64_elf_hwcap & HWCAP_SPARC_CRYPTO))
25262306a36Sopenharmony_ci		return false;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	__asm__ __volatile__("rd %%asr26, %0" : "=r" (cfr));
25562306a36Sopenharmony_ci	if (!(cfr & CFR_CAMELLIA))
25662306a36Sopenharmony_ci		return false;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	return true;
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistatic int __init camellia_sparc64_mod_init(void)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	int err;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	if (!sparc64_has_camellia_opcode()) {
26662306a36Sopenharmony_ci		pr_info("sparc64 camellia opcodes not available.\n");
26762306a36Sopenharmony_ci		return -ENODEV;
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci	pr_info("Using sparc64 camellia opcodes optimized CAMELLIA implementation\n");
27062306a36Sopenharmony_ci	err = crypto_register_alg(&cipher_alg);
27162306a36Sopenharmony_ci	if (err)
27262306a36Sopenharmony_ci		return err;
27362306a36Sopenharmony_ci	err = crypto_register_skciphers(skcipher_algs,
27462306a36Sopenharmony_ci					ARRAY_SIZE(skcipher_algs));
27562306a36Sopenharmony_ci	if (err)
27662306a36Sopenharmony_ci		crypto_unregister_alg(&cipher_alg);
27762306a36Sopenharmony_ci	return err;
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_cistatic void __exit camellia_sparc64_mod_fini(void)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	crypto_unregister_alg(&cipher_alg);
28362306a36Sopenharmony_ci	crypto_unregister_skciphers(skcipher_algs, ARRAY_SIZE(skcipher_algs));
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cimodule_init(camellia_sparc64_mod_init);
28762306a36Sopenharmony_cimodule_exit(camellia_sparc64_mod_fini);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
29062306a36Sopenharmony_ciMODULE_DESCRIPTION("Camellia Cipher Algorithm, sparc64 camellia opcode accelerated");
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("camellia");
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci#include "crop_devid.c"
295