2 * crc32-arm64.c - CRC32 and CRC32C using optional ARMv8 instructions
4 * Module based on crypto/crc32c_generic.c
6 * CRC32 loop taken from Ed Nevill's Hadoop CRC patch
7 * http://mail-archives.apache.org/mod_mbox/hadoop-common-dev/201406.mbox/%3C1403687030.3355.19.camel%40localhost.localdomain%3E
9 * Using inline assembly instead of intrinsics in order to be backwards
10 * compatible with older compilers.
12 * Copyright (C) 2014 Linaro Ltd <yazen.ghannam@linaro.org>
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License version 2 as
16 * published by the Free Software Foundation.
19 #include <linux/unaligned/access_ok.h>
20 #include <linux/cpufeature.h>
21 #include <linux/init.h>
22 #include <linux/kernel.h>
23 #include <linux/module.h>
24 #include <linux/string.h>
26 #include <crypto/internal/hash.h>
28 MODULE_AUTHOR("Yazen Ghannam <yazen.ghannam@linaro.org>");
29 MODULE_DESCRIPTION("CRC32 and CRC32C using optional ARMv8 instructions");
30 MODULE_LICENSE("GPL v2");
32 #define CRC32X(crc, value) __asm__("crc32x %w[c], %w[c], %x[v]":[c]"+r"(crc):[v]"r"(value))
33 #define CRC32W(crc, value) __asm__("crc32w %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value))
34 #define CRC32H(crc, value) __asm__("crc32h %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value))
35 #define CRC32B(crc, value) __asm__("crc32b %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value))
36 #define CRC32CX(crc, value) __asm__("crc32cx %w[c], %w[c], %x[v]":[c]"+r"(crc):[v]"r"(value))
37 #define CRC32CW(crc, value) __asm__("crc32cw %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value))
38 #define CRC32CH(crc, value) __asm__("crc32ch %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value))
39 #define CRC32CB(crc, value) __asm__("crc32cb %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value))
41 static u32
crc32_arm64_le_hw(u32 crc
, const u8
*p
, unsigned int len
)
45 while ((length
-= sizeof(u64
)) >= 0) {
46 CRC32X(crc
, get_unaligned_le64(p
));
50 /* The following is more efficient than the straight loop */
51 if (length
& sizeof(u32
)) {
52 CRC32W(crc
, get_unaligned_le32(p
));
55 if (length
& sizeof(u16
)) {
56 CRC32H(crc
, get_unaligned_le16(p
));
59 if (length
& sizeof(u8
))
65 static u32
crc32c_arm64_le_hw(u32 crc
, const u8
*p
, unsigned int len
)
69 while ((length
-= sizeof(u64
)) >= 0) {
70 CRC32CX(crc
, get_unaligned_le64(p
));
74 /* The following is more efficient than the straight loop */
75 if (length
& sizeof(u32
)) {
76 CRC32CW(crc
, get_unaligned_le32(p
));
79 if (length
& sizeof(u16
)) {
80 CRC32CH(crc
, get_unaligned_le16(p
));
83 if (length
& sizeof(u8
))
89 #define CHKSUM_BLOCK_SIZE 1
90 #define CHKSUM_DIGEST_SIZE 4
96 struct chksum_desc_ctx
{
100 static int chksum_init(struct shash_desc
*desc
)
102 struct chksum_ctx
*mctx
= crypto_shash_ctx(desc
->tfm
);
103 struct chksum_desc_ctx
*ctx
= shash_desc_ctx(desc
);
105 ctx
->crc
= mctx
->key
;
111 * Setting the seed allows arbitrary accumulators and flexible XOR policy
112 * If your algorithm starts with ~0, then XOR with ~0 before you set
115 static int chksum_setkey(struct crypto_shash
*tfm
, const u8
*key
,
118 struct chksum_ctx
*mctx
= crypto_shash_ctx(tfm
);
120 if (keylen
!= sizeof(mctx
->key
)) {
121 crypto_shash_set_flags(tfm
, CRYPTO_TFM_RES_BAD_KEY_LEN
);
124 mctx
->key
= get_unaligned_le32(key
);
128 static int chksum_update(struct shash_desc
*desc
, const u8
*data
,
131 struct chksum_desc_ctx
*ctx
= shash_desc_ctx(desc
);
133 ctx
->crc
= crc32_arm64_le_hw(ctx
->crc
, data
, length
);
137 static int chksumc_update(struct shash_desc
*desc
, const u8
*data
,
140 struct chksum_desc_ctx
*ctx
= shash_desc_ctx(desc
);
142 ctx
->crc
= crc32c_arm64_le_hw(ctx
->crc
, data
, length
);
146 static int chksum_final(struct shash_desc
*desc
, u8
*out
)
148 struct chksum_desc_ctx
*ctx
= shash_desc_ctx(desc
);
150 put_unaligned_le32(ctx
->crc
, out
);
154 static int chksumc_final(struct shash_desc
*desc
, u8
*out
)
156 struct chksum_desc_ctx
*ctx
= shash_desc_ctx(desc
);
158 put_unaligned_le32(~ctx
->crc
, out
);
162 static int __chksum_finup(u32 crc
, const u8
*data
, unsigned int len
, u8
*out
)
164 put_unaligned_le32(crc32_arm64_le_hw(crc
, data
, len
), out
);
168 static int __chksumc_finup(u32 crc
, const u8
*data
, unsigned int len
, u8
*out
)
170 put_unaligned_le32(~crc32c_arm64_le_hw(crc
, data
, len
), out
);
174 static int chksum_finup(struct shash_desc
*desc
, const u8
*data
,
175 unsigned int len
, u8
*out
)
177 struct chksum_desc_ctx
*ctx
= shash_desc_ctx(desc
);
179 return __chksum_finup(ctx
->crc
, data
, len
, out
);
182 static int chksumc_finup(struct shash_desc
*desc
, const u8
*data
,
183 unsigned int len
, u8
*out
)
185 struct chksum_desc_ctx
*ctx
= shash_desc_ctx(desc
);
187 return __chksumc_finup(ctx
->crc
, data
, len
, out
);
190 static int chksum_digest(struct shash_desc
*desc
, const u8
*data
,
191 unsigned int length
, u8
*out
)
193 struct chksum_ctx
*mctx
= crypto_shash_ctx(desc
->tfm
);
195 return __chksum_finup(mctx
->key
, data
, length
, out
);
198 static int chksumc_digest(struct shash_desc
*desc
, const u8
*data
,
199 unsigned int length
, u8
*out
)
201 struct chksum_ctx
*mctx
= crypto_shash_ctx(desc
->tfm
);
203 return __chksumc_finup(mctx
->key
, data
, length
, out
);
206 static int crc32_cra_init(struct crypto_tfm
*tfm
)
208 struct chksum_ctx
*mctx
= crypto_tfm_ctx(tfm
);
214 static int crc32c_cra_init(struct crypto_tfm
*tfm
)
216 struct chksum_ctx
*mctx
= crypto_tfm_ctx(tfm
);
222 static struct shash_alg crc32_alg
= {
223 .digestsize
= CHKSUM_DIGEST_SIZE
,
224 .setkey
= chksum_setkey
,
226 .update
= chksum_update
,
227 .final
= chksum_final
,
228 .finup
= chksum_finup
,
229 .digest
= chksum_digest
,
230 .descsize
= sizeof(struct chksum_desc_ctx
),
233 .cra_driver_name
= "crc32-arm64-hw",
235 .cra_blocksize
= CHKSUM_BLOCK_SIZE
,
237 .cra_ctxsize
= sizeof(struct chksum_ctx
),
238 .cra_module
= THIS_MODULE
,
239 .cra_init
= crc32_cra_init
,
243 static struct shash_alg crc32c_alg
= {
244 .digestsize
= CHKSUM_DIGEST_SIZE
,
245 .setkey
= chksum_setkey
,
247 .update
= chksumc_update
,
248 .final
= chksumc_final
,
249 .finup
= chksumc_finup
,
250 .digest
= chksumc_digest
,
251 .descsize
= sizeof(struct chksum_desc_ctx
),
253 .cra_name
= "crc32c",
254 .cra_driver_name
= "crc32c-arm64-hw",
256 .cra_blocksize
= CHKSUM_BLOCK_SIZE
,
258 .cra_ctxsize
= sizeof(struct chksum_ctx
),
259 .cra_module
= THIS_MODULE
,
260 .cra_init
= crc32c_cra_init
,
264 static int __init
crc32_mod_init(void)
268 err
= crypto_register_shash(&crc32_alg
);
273 err
= crypto_register_shash(&crc32c_alg
);
276 crypto_unregister_shash(&crc32_alg
);
283 static void __exit
crc32_mod_exit(void)
285 crypto_unregister_shash(&crc32_alg
);
286 crypto_unregister_shash(&crc32c_alg
);
289 module_cpu_feature_match(CRC32
, crc32_mod_init
);
290 module_exit(crc32_mod_exit
);