fbedceb100
Move a long comment from lib/crc32.c to Documentation/crc32.txt where it will more likely get read. Edited the resulting document to add an explanation of the slicing-by-n algorithm. [djwong@us.ibm.com: minor changelog tweaks] [akpm@linux-foundation.org: fix typo, per George] Signed-off-by: George Spelvin <linux@horizon.com> Signed-off-by: Bob Pearson <rpearson@systemfabricworks.com> Signed-off-by: Darrick J. Wong <djwong@us.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
348 lines
8.6 KiB
C
348 lines
8.6 KiB
C
/*
|
|
* Oct 15, 2000 Matt Domsch <Matt_Domsch@dell.com>
|
|
* Nicer crc32 functions/docs submitted by linux@horizon.com. Thanks!
|
|
* Code was from the public domain, copyright abandoned. Code was
|
|
* subsequently included in the kernel, thus was re-licensed under the
|
|
* GNU GPL v2.
|
|
*
|
|
* Oct 12, 2000 Matt Domsch <Matt_Domsch@dell.com>
|
|
* Same crc32 function was used in 5 other places in the kernel.
|
|
* I made one version, and deleted the others.
|
|
* There are various incantations of crc32(). Some use a seed of 0 or ~0.
|
|
* Some xor at the end with ~0. The generic crc32() function takes
|
|
* seed as an argument, and doesn't xor at the end. Then individual
|
|
* users can do whatever they need.
|
|
* drivers/net/smc9194.c uses seed ~0, doesn't xor with ~0.
|
|
* fs/jffs2 uses seed 0, doesn't xor with ~0.
|
|
* fs/partitions/efi.c uses seed ~0, xor's with ~0.
|
|
*
|
|
* This source code is licensed under the GNU General Public License,
|
|
* Version 2. See the file COPYING for more details.
|
|
*/
|
|
|
|
/* see: Documentation/crc32.txt for a description of algorithms */
|
|
|
|
#include <linux/crc32.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/compiler.h>
|
|
#include <linux/types.h>
|
|
#include <linux/init.h>
|
|
#include <linux/atomic.h>
|
|
#include "crc32defs.h"
|
|
#if CRC_LE_BITS == 8
|
|
# define tole(x) __constant_cpu_to_le32(x)
|
|
#else
|
|
# define tole(x) (x)
|
|
#endif
|
|
|
|
#if CRC_BE_BITS == 8
|
|
# define tobe(x) __constant_cpu_to_be32(x)
|
|
#else
|
|
# define tobe(x) (x)
|
|
#endif
|
|
#include "crc32table.h"
|
|
|
|
MODULE_AUTHOR("Matt Domsch <Matt_Domsch@dell.com>");
|
|
MODULE_DESCRIPTION("Ethernet CRC32 calculations");
|
|
MODULE_LICENSE("GPL");
|
|
|
|
#if CRC_LE_BITS == 8 || CRC_BE_BITS == 8
|
|
|
|
static inline u32
|
|
crc32_body(u32 crc, unsigned char const *buf, size_t len, const u32 (*tab)[256])
|
|
{
|
|
# ifdef __LITTLE_ENDIAN
|
|
# define DO_CRC(x) crc = t0[(crc ^ (x)) & 255] ^ (crc >> 8)
|
|
# define DO_CRC4 crc = t3[(crc) & 255] ^ \
|
|
t2[(crc >> 8) & 255] ^ \
|
|
t1[(crc >> 16) & 255] ^ \
|
|
t0[(crc >> 24) & 255]
|
|
# else
|
|
# define DO_CRC(x) crc = t0[((crc >> 24) ^ (x)) & 255] ^ (crc << 8)
|
|
# define DO_CRC4 crc = t0[(crc) & 255] ^ \
|
|
t1[(crc >> 8) & 255] ^ \
|
|
t2[(crc >> 16) & 255] ^ \
|
|
t3[(crc >> 24) & 255]
|
|
# endif
|
|
const u32 *b;
|
|
size_t rem_len;
|
|
const u32 *t0=tab[0], *t1=tab[1], *t2=tab[2], *t3=tab[3];
|
|
|
|
/* Align it */
|
|
if (unlikely((long)buf & 3 && len)) {
|
|
do {
|
|
DO_CRC(*buf++);
|
|
} while ((--len) && ((long)buf)&3);
|
|
}
|
|
rem_len = len & 3;
|
|
/* load data 32 bits wide, xor data 32 bits wide. */
|
|
len = len >> 2;
|
|
b = (const u32 *)buf;
|
|
for (--b; len; --len) {
|
|
crc ^= *++b; /* use pre increment for speed */
|
|
DO_CRC4;
|
|
}
|
|
len = rem_len;
|
|
/* And the last few bytes */
|
|
if (len) {
|
|
u8 *p = (u8 *)(b + 1) - 1;
|
|
do {
|
|
DO_CRC(*++p); /* use pre increment for speed */
|
|
} while (--len);
|
|
}
|
|
return crc;
|
|
#undef DO_CRC
|
|
#undef DO_CRC4
|
|
}
|
|
#endif
|
|
/**
|
|
* crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
|
|
* @crc: seed value for computation. ~0 for Ethernet, sometimes 0 for
|
|
* other uses, or the previous crc32 value if computing incrementally.
|
|
* @p: pointer to buffer over which CRC is run
|
|
* @len: length of buffer @p
|
|
*/
|
|
u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len);
|
|
|
|
#if CRC_LE_BITS == 1
|
|
/*
|
|
* In fact, the table-based code will work in this case, but it can be
|
|
* simplified by inlining the table in ?: form.
|
|
*/
|
|
|
|
u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len)
|
|
{
|
|
int i;
|
|
while (len--) {
|
|
crc ^= *p++;
|
|
for (i = 0; i < 8; i++)
|
|
crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
|
|
}
|
|
return crc;
|
|
}
|
|
#else /* Table-based approach */
|
|
|
|
u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len)
|
|
{
|
|
# if CRC_LE_BITS == 8
|
|
const u32 (*tab)[] = crc32table_le;
|
|
|
|
crc = __cpu_to_le32(crc);
|
|
crc = crc32_body(crc, p, len, tab);
|
|
return __le32_to_cpu(crc);
|
|
# elif CRC_LE_BITS == 4
|
|
while (len--) {
|
|
crc ^= *p++;
|
|
crc = (crc >> 4) ^ crc32table_le[crc & 15];
|
|
crc = (crc >> 4) ^ crc32table_le[crc & 15];
|
|
}
|
|
return crc;
|
|
# elif CRC_LE_BITS == 2
|
|
while (len--) {
|
|
crc ^= *p++;
|
|
crc = (crc >> 2) ^ crc32table_le[crc & 3];
|
|
crc = (crc >> 2) ^ crc32table_le[crc & 3];
|
|
crc = (crc >> 2) ^ crc32table_le[crc & 3];
|
|
crc = (crc >> 2) ^ crc32table_le[crc & 3];
|
|
}
|
|
return crc;
|
|
# endif
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
|
|
* @crc: seed value for computation. ~0 for Ethernet, sometimes 0 for
|
|
* other uses, or the previous crc32 value if computing incrementally.
|
|
* @p: pointer to buffer over which CRC is run
|
|
* @len: length of buffer @p
|
|
*/
|
|
u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len);
|
|
|
|
#if CRC_BE_BITS == 1
|
|
/*
|
|
* In fact, the table-based code will work in this case, but it can be
|
|
* simplified by inlining the table in ?: form.
|
|
*/
|
|
|
|
u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len)
|
|
{
|
|
int i;
|
|
while (len--) {
|
|
crc ^= *p++ << 24;
|
|
for (i = 0; i < 8; i++)
|
|
crc =
|
|
(crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE :
|
|
0);
|
|
}
|
|
return crc;
|
|
}
|
|
|
|
#else /* Table-based approach */
|
|
u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len)
|
|
{
|
|
# if CRC_BE_BITS == 8
|
|
const u32 (*tab)[] = crc32table_be;
|
|
|
|
crc = __cpu_to_be32(crc);
|
|
crc = crc32_body(crc, p, len, tab);
|
|
return __be32_to_cpu(crc);
|
|
# elif CRC_BE_BITS == 4
|
|
while (len--) {
|
|
crc ^= *p++ << 24;
|
|
crc = (crc << 4) ^ crc32table_be[crc >> 28];
|
|
crc = (crc << 4) ^ crc32table_be[crc >> 28];
|
|
}
|
|
return crc;
|
|
# elif CRC_BE_BITS == 2
|
|
while (len--) {
|
|
crc ^= *p++ << 24;
|
|
crc = (crc << 2) ^ crc32table_be[crc >> 30];
|
|
crc = (crc << 2) ^ crc32table_be[crc >> 30];
|
|
crc = (crc << 2) ^ crc32table_be[crc >> 30];
|
|
crc = (crc << 2) ^ crc32table_be[crc >> 30];
|
|
}
|
|
return crc;
|
|
# endif
|
|
}
|
|
#endif
|
|
|
|
EXPORT_SYMBOL(crc32_le);
|
|
EXPORT_SYMBOL(crc32_be);
|
|
|
|
#ifdef UNITTEST
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
|
|
#if 0 /*Not used at present */
|
|
static void
|
|
buf_dump(char const *prefix, unsigned char const *buf, size_t len)
|
|
{
|
|
fputs(prefix, stdout);
|
|
while (len--)
|
|
printf(" %02x", *buf++);
|
|
putchar('\n');
|
|
|
|
}
|
|
#endif
|
|
|
|
static void bytereverse(unsigned char *buf, size_t len)
|
|
{
|
|
while (len--) {
|
|
unsigned char x = bitrev8(*buf);
|
|
*buf++ = x;
|
|
}
|
|
}
|
|
|
|
static void random_garbage(unsigned char *buf, size_t len)
|
|
{
|
|
while (len--)
|
|
*buf++ = (unsigned char) random();
|
|
}
|
|
|
|
#if 0 /* Not used at present */
|
|
static void store_le(u32 x, unsigned char *buf)
|
|
{
|
|
buf[0] = (unsigned char) x;
|
|
buf[1] = (unsigned char) (x >> 8);
|
|
buf[2] = (unsigned char) (x >> 16);
|
|
buf[3] = (unsigned char) (x >> 24);
|
|
}
|
|
#endif
|
|
|
|
static void store_be(u32 x, unsigned char *buf)
|
|
{
|
|
buf[0] = (unsigned char) (x >> 24);
|
|
buf[1] = (unsigned char) (x >> 16);
|
|
buf[2] = (unsigned char) (x >> 8);
|
|
buf[3] = (unsigned char) x;
|
|
}
|
|
|
|
/*
|
|
* This checks that CRC(buf + CRC(buf)) = 0, and that
|
|
* CRC commutes with bit-reversal. This has the side effect
|
|
* of bytewise bit-reversing the input buffer, and returns
|
|
* the CRC of the reversed buffer.
|
|
*/
|
|
static u32 test_step(u32 init, unsigned char *buf, size_t len)
|
|
{
|
|
u32 crc1, crc2;
|
|
size_t i;
|
|
|
|
crc1 = crc32_be(init, buf, len);
|
|
store_be(crc1, buf + len);
|
|
crc2 = crc32_be(init, buf, len + 4);
|
|
if (crc2)
|
|
printf("\nCRC cancellation fail: 0x%08x should be 0\n",
|
|
crc2);
|
|
|
|
for (i = 0; i <= len + 4; i++) {
|
|
crc2 = crc32_be(init, buf, i);
|
|
crc2 = crc32_be(crc2, buf + i, len + 4 - i);
|
|
if (crc2)
|
|
printf("\nCRC split fail: 0x%08x\n", crc2);
|
|
}
|
|
|
|
/* Now swap it around for the other test */
|
|
|
|
bytereverse(buf, len + 4);
|
|
init = bitrev32(init);
|
|
crc2 = bitrev32(crc1);
|
|
if (crc1 != bitrev32(crc2))
|
|
printf("\nBit reversal fail: 0x%08x -> 0x%08x -> 0x%08x\n",
|
|
crc1, crc2, bitrev32(crc2));
|
|
crc1 = crc32_le(init, buf, len);
|
|
if (crc1 != crc2)
|
|
printf("\nCRC endianness fail: 0x%08x != 0x%08x\n", crc1,
|
|
crc2);
|
|
crc2 = crc32_le(init, buf, len + 4);
|
|
if (crc2)
|
|
printf("\nCRC cancellation fail: 0x%08x should be 0\n",
|
|
crc2);
|
|
|
|
for (i = 0; i <= len + 4; i++) {
|
|
crc2 = crc32_le(init, buf, i);
|
|
crc2 = crc32_le(crc2, buf + i, len + 4 - i);
|
|
if (crc2)
|
|
printf("\nCRC split fail: 0x%08x\n", crc2);
|
|
}
|
|
|
|
return crc1;
|
|
}
|
|
|
|
#define SIZE 64
|
|
#define INIT1 0
|
|
#define INIT2 0
|
|
|
|
int main(void)
|
|
{
|
|
unsigned char buf1[SIZE + 4];
|
|
unsigned char buf2[SIZE + 4];
|
|
unsigned char buf3[SIZE + 4];
|
|
int i, j;
|
|
u32 crc1, crc2, crc3;
|
|
|
|
for (i = 0; i <= SIZE; i++) {
|
|
printf("\rTesting length %d...", i);
|
|
fflush(stdout);
|
|
random_garbage(buf1, i);
|
|
random_garbage(buf2, i);
|
|
for (j = 0; j < i; j++)
|
|
buf3[j] = buf1[j] ^ buf2[j];
|
|
|
|
crc1 = test_step(INIT1, buf1, i);
|
|
crc2 = test_step(INIT2, buf2, i);
|
|
/* Now check that CRC(buf1 ^ buf2) = CRC(buf1) ^ CRC(buf2) */
|
|
crc3 = test_step(INIT1 ^ INIT2, buf3, i);
|
|
if (crc3 != (crc1 ^ crc2))
|
|
printf("CRC XOR fail: 0x%08x != 0x%08x ^ 0x%08x\n",
|
|
crc3, crc1, crc2);
|
|
}
|
|
printf("\nAll test complete. No failures expected.\n");
|
|
return 0;
|
|
}
|
|
|
|
#endif /* UNITTEST */
|