162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Cryptographic API.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Support for VIA PadLock hardware crypto engine.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (c) 2004  Michal Ludvig <michal@logix.cz>
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <crypto/algapi.h>
1262306a36Sopenharmony_ci#include <crypto/aes.h>
1362306a36Sopenharmony_ci#include <crypto/internal/skcipher.h>
1462306a36Sopenharmony_ci#include <crypto/padlock.h>
1562306a36Sopenharmony_ci#include <linux/module.h>
1662306a36Sopenharmony_ci#include <linux/init.h>
1762306a36Sopenharmony_ci#include <linux/types.h>
1862306a36Sopenharmony_ci#include <linux/errno.h>
1962306a36Sopenharmony_ci#include <linux/interrupt.h>
2062306a36Sopenharmony_ci#include <linux/kernel.h>
2162306a36Sopenharmony_ci#include <linux/mm.h>
2262306a36Sopenharmony_ci#include <linux/percpu.h>
2362306a36Sopenharmony_ci#include <linux/smp.h>
2462306a36Sopenharmony_ci#include <linux/slab.h>
2562306a36Sopenharmony_ci#include <asm/cpu_device_id.h>
2662306a36Sopenharmony_ci#include <asm/byteorder.h>
2762306a36Sopenharmony_ci#include <asm/processor.h>
2862306a36Sopenharmony_ci#include <asm/fpu/api.h>
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/*
3162306a36Sopenharmony_ci * Number of data blocks actually fetched for each xcrypt insn.
3262306a36Sopenharmony_ci * Processors with prefetch errata will fetch extra blocks.
3362306a36Sopenharmony_ci */
3462306a36Sopenharmony_cistatic unsigned int ecb_fetch_blocks = 2;
3562306a36Sopenharmony_ci#define MAX_ECB_FETCH_BLOCKS (8)
3662306a36Sopenharmony_ci#define ecb_fetch_bytes (ecb_fetch_blocks * AES_BLOCK_SIZE)
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic unsigned int cbc_fetch_blocks = 1;
3962306a36Sopenharmony_ci#define MAX_CBC_FETCH_BLOCKS (4)
4062306a36Sopenharmony_ci#define cbc_fetch_bytes (cbc_fetch_blocks * AES_BLOCK_SIZE)
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/* Control word. */
4362306a36Sopenharmony_cistruct cword {
4462306a36Sopenharmony_ci	unsigned int __attribute__ ((__packed__))
4562306a36Sopenharmony_ci		rounds:4,
4662306a36Sopenharmony_ci		algo:3,
4762306a36Sopenharmony_ci		keygen:1,
4862306a36Sopenharmony_ci		interm:1,
4962306a36Sopenharmony_ci		encdec:1,
5062306a36Sopenharmony_ci		ksize:2;
5162306a36Sopenharmony_ci} __attribute__ ((__aligned__(PADLOCK_ALIGNMENT)));
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/* Whenever making any changes to the following
5462306a36Sopenharmony_ci * structure *make sure* you keep E, d_data
5562306a36Sopenharmony_ci * and cword aligned on 16 Bytes boundaries and
5662306a36Sopenharmony_ci * the Hardware can access 16 * 16 bytes of E and d_data
5762306a36Sopenharmony_ci * (only the first 15 * 16 bytes matter but the HW reads
5862306a36Sopenharmony_ci * more).
5962306a36Sopenharmony_ci */
6062306a36Sopenharmony_cistruct aes_ctx {
6162306a36Sopenharmony_ci	u32 E[AES_MAX_KEYLENGTH_U32]
6262306a36Sopenharmony_ci		__attribute__ ((__aligned__(PADLOCK_ALIGNMENT)));
6362306a36Sopenharmony_ci	u32 d_data[AES_MAX_KEYLENGTH_U32]
6462306a36Sopenharmony_ci		__attribute__ ((__aligned__(PADLOCK_ALIGNMENT)));
6562306a36Sopenharmony_ci	struct {
6662306a36Sopenharmony_ci		struct cword encrypt;
6762306a36Sopenharmony_ci		struct cword decrypt;
6862306a36Sopenharmony_ci	} cword;
6962306a36Sopenharmony_ci	u32 *D;
7062306a36Sopenharmony_ci};
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic DEFINE_PER_CPU(struct cword *, paes_last_cword);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci/* Tells whether the ACE is capable to generate
7562306a36Sopenharmony_ci   the extended key for a given key_len. */
7662306a36Sopenharmony_cistatic inline int
7762306a36Sopenharmony_ciaes_hw_extkey_available(uint8_t key_len)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	/* TODO: We should check the actual CPU model/stepping
8062306a36Sopenharmony_ci	         as it's possible that the capability will be
8162306a36Sopenharmony_ci	         added in the next CPU revisions. */
8262306a36Sopenharmony_ci	if (key_len == 16)
8362306a36Sopenharmony_ci		return 1;
8462306a36Sopenharmony_ci	return 0;
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic inline struct aes_ctx *aes_ctx_common(void *ctx)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	unsigned long addr = (unsigned long)ctx;
9062306a36Sopenharmony_ci	unsigned long align = PADLOCK_ALIGNMENT;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	if (align <= crypto_tfm_ctx_alignment())
9362306a36Sopenharmony_ci		align = 1;
9462306a36Sopenharmony_ci	return (struct aes_ctx *)ALIGN(addr, align);
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic inline struct aes_ctx *aes_ctx(struct crypto_tfm *tfm)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	return aes_ctx_common(crypto_tfm_ctx(tfm));
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic inline struct aes_ctx *skcipher_aes_ctx(struct crypto_skcipher *tfm)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	return aes_ctx_common(crypto_skcipher_ctx(tfm));
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
10862306a36Sopenharmony_ci		       unsigned int key_len)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	struct aes_ctx *ctx = aes_ctx(tfm);
11162306a36Sopenharmony_ci	const __le32 *key = (const __le32 *)in_key;
11262306a36Sopenharmony_ci	struct crypto_aes_ctx gen_aes;
11362306a36Sopenharmony_ci	int cpu;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	if (key_len % 8)
11662306a36Sopenharmony_ci		return -EINVAL;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	/*
11962306a36Sopenharmony_ci	 * If the hardware is capable of generating the extended key
12062306a36Sopenharmony_ci	 * itself we must supply the plain key for both encryption
12162306a36Sopenharmony_ci	 * and decryption.
12262306a36Sopenharmony_ci	 */
12362306a36Sopenharmony_ci	ctx->D = ctx->E;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	ctx->E[0] = le32_to_cpu(key[0]);
12662306a36Sopenharmony_ci	ctx->E[1] = le32_to_cpu(key[1]);
12762306a36Sopenharmony_ci	ctx->E[2] = le32_to_cpu(key[2]);
12862306a36Sopenharmony_ci	ctx->E[3] = le32_to_cpu(key[3]);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	/* Prepare control words. */
13162306a36Sopenharmony_ci	memset(&ctx->cword, 0, sizeof(ctx->cword));
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	ctx->cword.decrypt.encdec = 1;
13462306a36Sopenharmony_ci	ctx->cword.encrypt.rounds = 10 + (key_len - 16) / 4;
13562306a36Sopenharmony_ci	ctx->cword.decrypt.rounds = ctx->cword.encrypt.rounds;
13662306a36Sopenharmony_ci	ctx->cword.encrypt.ksize = (key_len - 16) / 8;
13762306a36Sopenharmony_ci	ctx->cword.decrypt.ksize = ctx->cword.encrypt.ksize;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	/* Don't generate extended keys if the hardware can do it. */
14062306a36Sopenharmony_ci	if (aes_hw_extkey_available(key_len))
14162306a36Sopenharmony_ci		goto ok;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	ctx->D = ctx->d_data;
14462306a36Sopenharmony_ci	ctx->cword.encrypt.keygen = 1;
14562306a36Sopenharmony_ci	ctx->cword.decrypt.keygen = 1;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	if (aes_expandkey(&gen_aes, in_key, key_len))
14862306a36Sopenharmony_ci		return -EINVAL;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	memcpy(ctx->E, gen_aes.key_enc, AES_MAX_KEYLENGTH);
15162306a36Sopenharmony_ci	memcpy(ctx->D, gen_aes.key_dec, AES_MAX_KEYLENGTH);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ciok:
15462306a36Sopenharmony_ci	for_each_online_cpu(cpu)
15562306a36Sopenharmony_ci		if (&ctx->cword.encrypt == per_cpu(paes_last_cword, cpu) ||
15662306a36Sopenharmony_ci		    &ctx->cword.decrypt == per_cpu(paes_last_cword, cpu))
15762306a36Sopenharmony_ci			per_cpu(paes_last_cword, cpu) = NULL;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	return 0;
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic int aes_set_key_skcipher(struct crypto_skcipher *tfm, const u8 *in_key,
16362306a36Sopenharmony_ci				unsigned int key_len)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	return aes_set_key(crypto_skcipher_tfm(tfm), in_key, key_len);
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci/* ====== Encryption/decryption routines ====== */
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci/* These are the real call to PadLock. */
17162306a36Sopenharmony_cistatic inline void padlock_reset_key(struct cword *cword)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	int cpu = raw_smp_processor_id();
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	if (cword != per_cpu(paes_last_cword, cpu))
17662306a36Sopenharmony_ci#ifndef CONFIG_X86_64
17762306a36Sopenharmony_ci		asm volatile ("pushfl; popfl");
17862306a36Sopenharmony_ci#else
17962306a36Sopenharmony_ci		asm volatile ("pushfq; popfq");
18062306a36Sopenharmony_ci#endif
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic inline void padlock_store_cword(struct cword *cword)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	per_cpu(paes_last_cword, raw_smp_processor_id()) = cword;
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci/*
18962306a36Sopenharmony_ci * While the padlock instructions don't use FP/SSE registers, they
19062306a36Sopenharmony_ci * generate a spurious DNA fault when CR0.TS is '1'.  Fortunately,
19162306a36Sopenharmony_ci * the kernel doesn't use CR0.TS.
19262306a36Sopenharmony_ci */
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_cistatic inline void rep_xcrypt_ecb(const u8 *input, u8 *output, void *key,
19562306a36Sopenharmony_ci				  struct cword *control_word, int count)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	asm volatile (".byte 0xf3,0x0f,0xa7,0xc8"	/* rep xcryptecb */
19862306a36Sopenharmony_ci		      : "+S"(input), "+D"(output)
19962306a36Sopenharmony_ci		      : "d"(control_word), "b"(key), "c"(count));
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic inline u8 *rep_xcrypt_cbc(const u8 *input, u8 *output, void *key,
20362306a36Sopenharmony_ci				 u8 *iv, struct cword *control_word, int count)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	asm volatile (".byte 0xf3,0x0f,0xa7,0xd0"	/* rep xcryptcbc */
20662306a36Sopenharmony_ci		      : "+S" (input), "+D" (output), "+a" (iv)
20762306a36Sopenharmony_ci		      : "d" (control_word), "b" (key), "c" (count));
20862306a36Sopenharmony_ci	return iv;
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cistatic void ecb_crypt_copy(const u8 *in, u8 *out, u32 *key,
21262306a36Sopenharmony_ci			   struct cword *cword, int count)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	/*
21562306a36Sopenharmony_ci	 * Padlock prefetches extra data so we must provide mapped input buffers.
21662306a36Sopenharmony_ci	 * Assume there are at least 16 bytes of stack already in use.
21762306a36Sopenharmony_ci	 */
21862306a36Sopenharmony_ci	u8 buf[AES_BLOCK_SIZE * (MAX_ECB_FETCH_BLOCKS - 1) + PADLOCK_ALIGNMENT - 1];
21962306a36Sopenharmony_ci	u8 *tmp = PTR_ALIGN(&buf[0], PADLOCK_ALIGNMENT);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	memcpy(tmp, in, count * AES_BLOCK_SIZE);
22262306a36Sopenharmony_ci	rep_xcrypt_ecb(tmp, out, key, cword, count);
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic u8 *cbc_crypt_copy(const u8 *in, u8 *out, u32 *key,
22662306a36Sopenharmony_ci			   u8 *iv, struct cword *cword, int count)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	/*
22962306a36Sopenharmony_ci	 * Padlock prefetches extra data so we must provide mapped input buffers.
23062306a36Sopenharmony_ci	 * Assume there are at least 16 bytes of stack already in use.
23162306a36Sopenharmony_ci	 */
23262306a36Sopenharmony_ci	u8 buf[AES_BLOCK_SIZE * (MAX_CBC_FETCH_BLOCKS - 1) + PADLOCK_ALIGNMENT - 1];
23362306a36Sopenharmony_ci	u8 *tmp = PTR_ALIGN(&buf[0], PADLOCK_ALIGNMENT);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	memcpy(tmp, in, count * AES_BLOCK_SIZE);
23662306a36Sopenharmony_ci	return rep_xcrypt_cbc(tmp, out, key, iv, cword, count);
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic inline void ecb_crypt(const u8 *in, u8 *out, u32 *key,
24062306a36Sopenharmony_ci			     struct cword *cword, int count)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	/* Padlock in ECB mode fetches at least ecb_fetch_bytes of data.
24362306a36Sopenharmony_ci	 * We could avoid some copying here but it's probably not worth it.
24462306a36Sopenharmony_ci	 */
24562306a36Sopenharmony_ci	if (unlikely(offset_in_page(in) + ecb_fetch_bytes > PAGE_SIZE)) {
24662306a36Sopenharmony_ci		ecb_crypt_copy(in, out, key, cword, count);
24762306a36Sopenharmony_ci		return;
24862306a36Sopenharmony_ci	}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	rep_xcrypt_ecb(in, out, key, cword, count);
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cistatic inline u8 *cbc_crypt(const u8 *in, u8 *out, u32 *key,
25462306a36Sopenharmony_ci			    u8 *iv, struct cword *cword, int count)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	/* Padlock in CBC mode fetches at least cbc_fetch_bytes of data. */
25762306a36Sopenharmony_ci	if (unlikely(offset_in_page(in) + cbc_fetch_bytes > PAGE_SIZE))
25862306a36Sopenharmony_ci		return cbc_crypt_copy(in, out, key, iv, cword, count);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	return rep_xcrypt_cbc(in, out, key, iv, cword, count);
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cistatic inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key,
26462306a36Sopenharmony_ci				      void *control_word, u32 count)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	u32 initial = count & (ecb_fetch_blocks - 1);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	if (count < ecb_fetch_blocks) {
26962306a36Sopenharmony_ci		ecb_crypt(input, output, key, control_word, count);
27062306a36Sopenharmony_ci		return;
27162306a36Sopenharmony_ci	}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	count -= initial;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	if (initial)
27662306a36Sopenharmony_ci		asm volatile (".byte 0xf3,0x0f,0xa7,0xc8"	/* rep xcryptecb */
27762306a36Sopenharmony_ci			      : "+S"(input), "+D"(output)
27862306a36Sopenharmony_ci			      : "d"(control_word), "b"(key), "c"(initial));
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	asm volatile (".byte 0xf3,0x0f,0xa7,0xc8"	/* rep xcryptecb */
28162306a36Sopenharmony_ci		      : "+S"(input), "+D"(output)
28262306a36Sopenharmony_ci		      : "d"(control_word), "b"(key), "c"(count));
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key,
28662306a36Sopenharmony_ci				     u8 *iv, void *control_word, u32 count)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	u32 initial = count & (cbc_fetch_blocks - 1);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	if (count < cbc_fetch_blocks)
29162306a36Sopenharmony_ci		return cbc_crypt(input, output, key, iv, control_word, count);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	count -= initial;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	if (initial)
29662306a36Sopenharmony_ci		asm volatile (".byte 0xf3,0x0f,0xa7,0xd0"	/* rep xcryptcbc */
29762306a36Sopenharmony_ci			      : "+S" (input), "+D" (output), "+a" (iv)
29862306a36Sopenharmony_ci			      : "d" (control_word), "b" (key), "c" (initial));
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	asm volatile (".byte 0xf3,0x0f,0xa7,0xd0"	/* rep xcryptcbc */
30162306a36Sopenharmony_ci		      : "+S" (input), "+D" (output), "+a" (iv)
30262306a36Sopenharmony_ci		      : "d" (control_word), "b" (key), "c" (count));
30362306a36Sopenharmony_ci	return iv;
30462306a36Sopenharmony_ci}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_cistatic void padlock_aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	struct aes_ctx *ctx = aes_ctx(tfm);
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	padlock_reset_key(&ctx->cword.encrypt);
31162306a36Sopenharmony_ci	ecb_crypt(in, out, ctx->E, &ctx->cword.encrypt, 1);
31262306a36Sopenharmony_ci	padlock_store_cword(&ctx->cword.encrypt);
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_cistatic void padlock_aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	struct aes_ctx *ctx = aes_ctx(tfm);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	padlock_reset_key(&ctx->cword.encrypt);
32062306a36Sopenharmony_ci	ecb_crypt(in, out, ctx->D, &ctx->cword.decrypt, 1);
32162306a36Sopenharmony_ci	padlock_store_cword(&ctx->cword.encrypt);
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cistatic struct crypto_alg aes_alg = {
32562306a36Sopenharmony_ci	.cra_name		=	"aes",
32662306a36Sopenharmony_ci	.cra_driver_name	=	"aes-padlock",
32762306a36Sopenharmony_ci	.cra_priority		=	PADLOCK_CRA_PRIORITY,
32862306a36Sopenharmony_ci	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
32962306a36Sopenharmony_ci	.cra_blocksize		=	AES_BLOCK_SIZE,
33062306a36Sopenharmony_ci	.cra_ctxsize		=	sizeof(struct aes_ctx),
33162306a36Sopenharmony_ci	.cra_alignmask		=	PADLOCK_ALIGNMENT - 1,
33262306a36Sopenharmony_ci	.cra_module		=	THIS_MODULE,
33362306a36Sopenharmony_ci	.cra_u			=	{
33462306a36Sopenharmony_ci		.cipher = {
33562306a36Sopenharmony_ci			.cia_min_keysize	=	AES_MIN_KEY_SIZE,
33662306a36Sopenharmony_ci			.cia_max_keysize	=	AES_MAX_KEY_SIZE,
33762306a36Sopenharmony_ci			.cia_setkey	   	= 	aes_set_key,
33862306a36Sopenharmony_ci			.cia_encrypt	 	=	padlock_aes_encrypt,
33962306a36Sopenharmony_ci			.cia_decrypt	  	=	padlock_aes_decrypt,
34062306a36Sopenharmony_ci		}
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_ci};
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cistatic int ecb_aes_encrypt(struct skcipher_request *req)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
34762306a36Sopenharmony_ci	struct aes_ctx *ctx = skcipher_aes_ctx(tfm);
34862306a36Sopenharmony_ci	struct skcipher_walk walk;
34962306a36Sopenharmony_ci	unsigned int nbytes;
35062306a36Sopenharmony_ci	int err;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	padlock_reset_key(&ctx->cword.encrypt);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, false);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	while ((nbytes = walk.nbytes) != 0) {
35762306a36Sopenharmony_ci		padlock_xcrypt_ecb(walk.src.virt.addr, walk.dst.virt.addr,
35862306a36Sopenharmony_ci				   ctx->E, &ctx->cword.encrypt,
35962306a36Sopenharmony_ci				   nbytes / AES_BLOCK_SIZE);
36062306a36Sopenharmony_ci		nbytes &= AES_BLOCK_SIZE - 1;
36162306a36Sopenharmony_ci		err = skcipher_walk_done(&walk, nbytes);
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	padlock_store_cword(&ctx->cword.encrypt);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	return err;
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_cistatic int ecb_aes_decrypt(struct skcipher_request *req)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
37262306a36Sopenharmony_ci	struct aes_ctx *ctx = skcipher_aes_ctx(tfm);
37362306a36Sopenharmony_ci	struct skcipher_walk walk;
37462306a36Sopenharmony_ci	unsigned int nbytes;
37562306a36Sopenharmony_ci	int err;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	padlock_reset_key(&ctx->cword.decrypt);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, false);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	while ((nbytes = walk.nbytes) != 0) {
38262306a36Sopenharmony_ci		padlock_xcrypt_ecb(walk.src.virt.addr, walk.dst.virt.addr,
38362306a36Sopenharmony_ci				   ctx->D, &ctx->cword.decrypt,
38462306a36Sopenharmony_ci				   nbytes / AES_BLOCK_SIZE);
38562306a36Sopenharmony_ci		nbytes &= AES_BLOCK_SIZE - 1;
38662306a36Sopenharmony_ci		err = skcipher_walk_done(&walk, nbytes);
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	padlock_store_cword(&ctx->cword.encrypt);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	return err;
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cistatic struct skcipher_alg ecb_aes_alg = {
39562306a36Sopenharmony_ci	.base.cra_name		=	"ecb(aes)",
39662306a36Sopenharmony_ci	.base.cra_driver_name	=	"ecb-aes-padlock",
39762306a36Sopenharmony_ci	.base.cra_priority	=	PADLOCK_COMPOSITE_PRIORITY,
39862306a36Sopenharmony_ci	.base.cra_blocksize	=	AES_BLOCK_SIZE,
39962306a36Sopenharmony_ci	.base.cra_ctxsize	=	sizeof(struct aes_ctx),
40062306a36Sopenharmony_ci	.base.cra_alignmask	=	PADLOCK_ALIGNMENT - 1,
40162306a36Sopenharmony_ci	.base.cra_module	=	THIS_MODULE,
40262306a36Sopenharmony_ci	.min_keysize		=	AES_MIN_KEY_SIZE,
40362306a36Sopenharmony_ci	.max_keysize		=	AES_MAX_KEY_SIZE,
40462306a36Sopenharmony_ci	.setkey			=	aes_set_key_skcipher,
40562306a36Sopenharmony_ci	.encrypt		=	ecb_aes_encrypt,
40662306a36Sopenharmony_ci	.decrypt		=	ecb_aes_decrypt,
40762306a36Sopenharmony_ci};
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_cistatic int cbc_aes_encrypt(struct skcipher_request *req)
41062306a36Sopenharmony_ci{
41162306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
41262306a36Sopenharmony_ci	struct aes_ctx *ctx = skcipher_aes_ctx(tfm);
41362306a36Sopenharmony_ci	struct skcipher_walk walk;
41462306a36Sopenharmony_ci	unsigned int nbytes;
41562306a36Sopenharmony_ci	int err;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	padlock_reset_key(&ctx->cword.encrypt);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, false);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	while ((nbytes = walk.nbytes) != 0) {
42262306a36Sopenharmony_ci		u8 *iv = padlock_xcrypt_cbc(walk.src.virt.addr,
42362306a36Sopenharmony_ci					    walk.dst.virt.addr, ctx->E,
42462306a36Sopenharmony_ci					    walk.iv, &ctx->cword.encrypt,
42562306a36Sopenharmony_ci					    nbytes / AES_BLOCK_SIZE);
42662306a36Sopenharmony_ci		memcpy(walk.iv, iv, AES_BLOCK_SIZE);
42762306a36Sopenharmony_ci		nbytes &= AES_BLOCK_SIZE - 1;
42862306a36Sopenharmony_ci		err = skcipher_walk_done(&walk, nbytes);
42962306a36Sopenharmony_ci	}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	padlock_store_cword(&ctx->cword.decrypt);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	return err;
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_cistatic int cbc_aes_decrypt(struct skcipher_request *req)
43762306a36Sopenharmony_ci{
43862306a36Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
43962306a36Sopenharmony_ci	struct aes_ctx *ctx = skcipher_aes_ctx(tfm);
44062306a36Sopenharmony_ci	struct skcipher_walk walk;
44162306a36Sopenharmony_ci	unsigned int nbytes;
44262306a36Sopenharmony_ci	int err;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	padlock_reset_key(&ctx->cword.encrypt);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, false);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	while ((nbytes = walk.nbytes) != 0) {
44962306a36Sopenharmony_ci		padlock_xcrypt_cbc(walk.src.virt.addr, walk.dst.virt.addr,
45062306a36Sopenharmony_ci				   ctx->D, walk.iv, &ctx->cword.decrypt,
45162306a36Sopenharmony_ci				   nbytes / AES_BLOCK_SIZE);
45262306a36Sopenharmony_ci		nbytes &= AES_BLOCK_SIZE - 1;
45362306a36Sopenharmony_ci		err = skcipher_walk_done(&walk, nbytes);
45462306a36Sopenharmony_ci	}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	padlock_store_cword(&ctx->cword.encrypt);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	return err;
45962306a36Sopenharmony_ci}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_cistatic struct skcipher_alg cbc_aes_alg = {
46262306a36Sopenharmony_ci	.base.cra_name		=	"cbc(aes)",
46362306a36Sopenharmony_ci	.base.cra_driver_name	=	"cbc-aes-padlock",
46462306a36Sopenharmony_ci	.base.cra_priority	=	PADLOCK_COMPOSITE_PRIORITY,
46562306a36Sopenharmony_ci	.base.cra_blocksize	=	AES_BLOCK_SIZE,
46662306a36Sopenharmony_ci	.base.cra_ctxsize	=	sizeof(struct aes_ctx),
46762306a36Sopenharmony_ci	.base.cra_alignmask	=	PADLOCK_ALIGNMENT - 1,
46862306a36Sopenharmony_ci	.base.cra_module	=	THIS_MODULE,
46962306a36Sopenharmony_ci	.min_keysize		=	AES_MIN_KEY_SIZE,
47062306a36Sopenharmony_ci	.max_keysize		=	AES_MAX_KEY_SIZE,
47162306a36Sopenharmony_ci	.ivsize			=	AES_BLOCK_SIZE,
47262306a36Sopenharmony_ci	.setkey			=	aes_set_key_skcipher,
47362306a36Sopenharmony_ci	.encrypt		=	cbc_aes_encrypt,
47462306a36Sopenharmony_ci	.decrypt		=	cbc_aes_decrypt,
47562306a36Sopenharmony_ci};
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_cistatic const struct x86_cpu_id padlock_cpu_id[] = {
47862306a36Sopenharmony_ci	X86_MATCH_FEATURE(X86_FEATURE_XCRYPT, NULL),
47962306a36Sopenharmony_ci	{}
48062306a36Sopenharmony_ci};
48162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(x86cpu, padlock_cpu_id);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_cistatic int __init padlock_init(void)
48462306a36Sopenharmony_ci{
48562306a36Sopenharmony_ci	int ret;
48662306a36Sopenharmony_ci	struct cpuinfo_x86 *c = &cpu_data(0);
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	if (!x86_match_cpu(padlock_cpu_id))
48962306a36Sopenharmony_ci		return -ENODEV;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	if (!boot_cpu_has(X86_FEATURE_XCRYPT_EN)) {
49262306a36Sopenharmony_ci		printk(KERN_NOTICE PFX "VIA PadLock detected, but not enabled. Hmm, strange...\n");
49362306a36Sopenharmony_ci		return -ENODEV;
49462306a36Sopenharmony_ci	}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	if ((ret = crypto_register_alg(&aes_alg)) != 0)
49762306a36Sopenharmony_ci		goto aes_err;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	if ((ret = crypto_register_skcipher(&ecb_aes_alg)) != 0)
50062306a36Sopenharmony_ci		goto ecb_aes_err;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	if ((ret = crypto_register_skcipher(&cbc_aes_alg)) != 0)
50362306a36Sopenharmony_ci		goto cbc_aes_err;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	printk(KERN_NOTICE PFX "Using VIA PadLock ACE for AES algorithm.\n");
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	if (c->x86 == 6 && c->x86_model == 15 && c->x86_stepping == 2) {
50862306a36Sopenharmony_ci		ecb_fetch_blocks = MAX_ECB_FETCH_BLOCKS;
50962306a36Sopenharmony_ci		cbc_fetch_blocks = MAX_CBC_FETCH_BLOCKS;
51062306a36Sopenharmony_ci		printk(KERN_NOTICE PFX "VIA Nano stepping 2 detected: enabling workaround.\n");
51162306a36Sopenharmony_ci	}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ciout:
51462306a36Sopenharmony_ci	return ret;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_cicbc_aes_err:
51762306a36Sopenharmony_ci	crypto_unregister_skcipher(&ecb_aes_alg);
51862306a36Sopenharmony_ciecb_aes_err:
51962306a36Sopenharmony_ci	crypto_unregister_alg(&aes_alg);
52062306a36Sopenharmony_ciaes_err:
52162306a36Sopenharmony_ci	printk(KERN_ERR PFX "VIA PadLock AES initialization failed.\n");
52262306a36Sopenharmony_ci	goto out;
52362306a36Sopenharmony_ci}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_cistatic void __exit padlock_fini(void)
52662306a36Sopenharmony_ci{
52762306a36Sopenharmony_ci	crypto_unregister_skcipher(&cbc_aes_alg);
52862306a36Sopenharmony_ci	crypto_unregister_skcipher(&ecb_aes_alg);
52962306a36Sopenharmony_ci	crypto_unregister_alg(&aes_alg);
53062306a36Sopenharmony_ci}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_cimodule_init(padlock_init);
53362306a36Sopenharmony_cimodule_exit(padlock_fini);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ciMODULE_DESCRIPTION("VIA PadLock AES algorithm support");
53662306a36Sopenharmony_ciMODULE_LICENSE("GPL");
53762306a36Sopenharmony_ciMODULE_AUTHOR("Michal Ludvig");
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("aes");
540