cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

crc32c-intel_glue.c (6258B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Using hardware provided CRC32 instruction to accelerate the CRC32 disposal.
      4 * CRC32C polynomial:0x1EDC6F41(BE)/0x82F63B78(LE)
      5 * CRC32 is a new instruction in Intel SSE4.2, the reference can be found at:
      6 * http://www.intel.com/products/processor/manuals/
      7 * Intel(R) 64 and IA-32 Architectures Software Developer's Manual
      8 * Volume 2A: Instruction Set Reference, A-M
      9 *
     10 * Copyright (C) 2008 Intel Corporation
     11 * Authors: Austin Zhang <austin_zhang@linux.intel.com>
     12 *          Kent Liu <kent.liu@intel.com>
     13 */
     14#include <linux/init.h>
     15#include <linux/module.h>
     16#include <linux/string.h>
     17#include <linux/kernel.h>
     18#include <crypto/internal/hash.h>
     19#include <crypto/internal/simd.h>
     20
     21#include <asm/cpufeatures.h>
     22#include <asm/cpu_device_id.h>
     23#include <asm/simd.h>
     24
     25#define CHKSUM_BLOCK_SIZE	1
     26#define CHKSUM_DIGEST_SIZE	4
     27
     28#define SCALE_F	sizeof(unsigned long)
     29
     30#ifdef CONFIG_X86_64
     31#define CRC32_INST "crc32q %1, %q0"
     32#else
     33#define CRC32_INST "crc32l %1, %0"
     34#endif
     35
     36#ifdef CONFIG_X86_64
     37/*
     38 * use carryless multiply version of crc32c when buffer
     39 * size is >= 512 to account
     40 * for fpu state save/restore overhead.
     41 */
     42#define CRC32C_PCL_BREAKEVEN	512
     43
     44asmlinkage unsigned int crc_pcl(const u8 *buffer, int len,
     45				unsigned int crc_init);
     46#endif /* CONFIG_X86_64 */
     47
     48static u32 crc32c_intel_le_hw_byte(u32 crc, unsigned char const *data, size_t length)
     49{
     50	while (length--) {
     51		asm("crc32b %1, %0"
     52		    : "+r" (crc) : "rm" (*data));
     53		data++;
     54	}
     55
     56	return crc;
     57}
     58
     59static u32 __pure crc32c_intel_le_hw(u32 crc, unsigned char const *p, size_t len)
     60{
     61	unsigned int iquotient = len / SCALE_F;
     62	unsigned int iremainder = len % SCALE_F;
     63	unsigned long *ptmp = (unsigned long *)p;
     64
     65	while (iquotient--) {
     66		asm(CRC32_INST
     67		    : "+r" (crc) : "rm" (*ptmp));
     68		ptmp++;
     69	}
     70
     71	if (iremainder)
     72		crc = crc32c_intel_le_hw_byte(crc, (unsigned char *)ptmp,
     73				 iremainder);
     74
     75	return crc;
     76}
     77
     78/*
     79 * Setting the seed allows arbitrary accumulators and flexible XOR policy
     80 * If your algorithm starts with ~0, then XOR with ~0 before you set
     81 * the seed.
     82 */
     83static int crc32c_intel_setkey(struct crypto_shash *hash, const u8 *key,
     84			unsigned int keylen)
     85{
     86	u32 *mctx = crypto_shash_ctx(hash);
     87
     88	if (keylen != sizeof(u32))
     89		return -EINVAL;
     90	*mctx = le32_to_cpup((__le32 *)key);
     91	return 0;
     92}
     93
     94static int crc32c_intel_init(struct shash_desc *desc)
     95{
     96	u32 *mctx = crypto_shash_ctx(desc->tfm);
     97	u32 *crcp = shash_desc_ctx(desc);
     98
     99	*crcp = *mctx;
    100
    101	return 0;
    102}
    103
    104static int crc32c_intel_update(struct shash_desc *desc, const u8 *data,
    105			       unsigned int len)
    106{
    107	u32 *crcp = shash_desc_ctx(desc);
    108
    109	*crcp = crc32c_intel_le_hw(*crcp, data, len);
    110	return 0;
    111}
    112
    113static int __crc32c_intel_finup(u32 *crcp, const u8 *data, unsigned int len,
    114				u8 *out)
    115{
    116	*(__le32 *)out = ~cpu_to_le32(crc32c_intel_le_hw(*crcp, data, len));
    117	return 0;
    118}
    119
    120static int crc32c_intel_finup(struct shash_desc *desc, const u8 *data,
    121			      unsigned int len, u8 *out)
    122{
    123	return __crc32c_intel_finup(shash_desc_ctx(desc), data, len, out);
    124}
    125
    126static int crc32c_intel_final(struct shash_desc *desc, u8 *out)
    127{
    128	u32 *crcp = shash_desc_ctx(desc);
    129
    130	*(__le32 *)out = ~cpu_to_le32p(crcp);
    131	return 0;
    132}
    133
    134static int crc32c_intel_digest(struct shash_desc *desc, const u8 *data,
    135			       unsigned int len, u8 *out)
    136{
    137	return __crc32c_intel_finup(crypto_shash_ctx(desc->tfm), data, len,
    138				    out);
    139}
    140
    141static int crc32c_intel_cra_init(struct crypto_tfm *tfm)
    142{
    143	u32 *key = crypto_tfm_ctx(tfm);
    144
    145	*key = ~0;
    146
    147	return 0;
    148}
    149
    150#ifdef CONFIG_X86_64
    151static int crc32c_pcl_intel_update(struct shash_desc *desc, const u8 *data,
    152			       unsigned int len)
    153{
    154	u32 *crcp = shash_desc_ctx(desc);
    155
    156	/*
    157	 * use faster PCL version if datasize is large enough to
    158	 * overcome kernel fpu state save/restore overhead
    159	 */
    160	if (len >= CRC32C_PCL_BREAKEVEN && crypto_simd_usable()) {
    161		kernel_fpu_begin();
    162		*crcp = crc_pcl(data, len, *crcp);
    163		kernel_fpu_end();
    164	} else
    165		*crcp = crc32c_intel_le_hw(*crcp, data, len);
    166	return 0;
    167}
    168
    169static int __crc32c_pcl_intel_finup(u32 *crcp, const u8 *data, unsigned int len,
    170				u8 *out)
    171{
    172	if (len >= CRC32C_PCL_BREAKEVEN && crypto_simd_usable()) {
    173		kernel_fpu_begin();
    174		*(__le32 *)out = ~cpu_to_le32(crc_pcl(data, len, *crcp));
    175		kernel_fpu_end();
    176	} else
    177		*(__le32 *)out =
    178			~cpu_to_le32(crc32c_intel_le_hw(*crcp, data, len));
    179	return 0;
    180}
    181
    182static int crc32c_pcl_intel_finup(struct shash_desc *desc, const u8 *data,
    183			      unsigned int len, u8 *out)
    184{
    185	return __crc32c_pcl_intel_finup(shash_desc_ctx(desc), data, len, out);
    186}
    187
    188static int crc32c_pcl_intel_digest(struct shash_desc *desc, const u8 *data,
    189			       unsigned int len, u8 *out)
    190{
    191	return __crc32c_pcl_intel_finup(crypto_shash_ctx(desc->tfm), data, len,
    192				    out);
    193}
    194#endif /* CONFIG_X86_64 */
    195
    196static struct shash_alg alg = {
    197	.setkey			=	crc32c_intel_setkey,
    198	.init			=	crc32c_intel_init,
    199	.update			=	crc32c_intel_update,
    200	.final			=	crc32c_intel_final,
    201	.finup			=	crc32c_intel_finup,
    202	.digest			=	crc32c_intel_digest,
    203	.descsize		=	sizeof(u32),
    204	.digestsize		=	CHKSUM_DIGEST_SIZE,
    205	.base			=	{
    206		.cra_name		=	"crc32c",
    207		.cra_driver_name	=	"crc32c-intel",
    208		.cra_priority		=	200,
    209		.cra_flags		=	CRYPTO_ALG_OPTIONAL_KEY,
    210		.cra_blocksize		=	CHKSUM_BLOCK_SIZE,
    211		.cra_ctxsize		=	sizeof(u32),
    212		.cra_module		=	THIS_MODULE,
    213		.cra_init		=	crc32c_intel_cra_init,
    214	}
    215};
    216
    217static const struct x86_cpu_id crc32c_cpu_id[] = {
    218	X86_MATCH_FEATURE(X86_FEATURE_XMM4_2, NULL),
    219	{}
    220};
    221MODULE_DEVICE_TABLE(x86cpu, crc32c_cpu_id);
    222
    223static int __init crc32c_intel_mod_init(void)
    224{
    225	if (!x86_match_cpu(crc32c_cpu_id))
    226		return -ENODEV;
    227#ifdef CONFIG_X86_64
    228	if (boot_cpu_has(X86_FEATURE_PCLMULQDQ)) {
    229		alg.update = crc32c_pcl_intel_update;
    230		alg.finup = crc32c_pcl_intel_finup;
    231		alg.digest = crc32c_pcl_intel_digest;
    232	}
    233#endif
    234	return crypto_register_shash(&alg);
    235}
    236
    237static void __exit crc32c_intel_mod_fini(void)
    238{
    239	crypto_unregister_shash(&alg);
    240}
    241
    242module_init(crc32c_intel_mod_init);
    243module_exit(crc32c_intel_mod_fini);
    244
    245MODULE_AUTHOR("Austin Zhang <austin.zhang@intel.com>, Kent Liu <kent.liu@intel.com>");
    246MODULE_DESCRIPTION("CRC32c (Castagnoli) optimization using Intel Hardware.");
    247MODULE_LICENSE("GPL");
    248
    249MODULE_ALIAS_CRYPTO("crc32c");
    250MODULE_ALIAS_CRYPTO("crc32c-intel");