Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <stdint.h>
- static inline unsigned short csum_fold(unsigned int sum)
- {
- asm(" addl %1,%0\n"
- " adcl $0xffff,%0"
- : "=r" (sum)
- : "r" ((unsigned int)sum << 16),
- "0" ((unsigned int)sum & 0xffff0000));
- return (unsigned short)(~(unsigned int)sum >> 16);
- }
- static inline unsigned add32_with_carry(unsigned a, unsigned b)
- {
- asm("addl %2,%0\n\t"
- "adcl $0,%0"
- : "=r" (a)
- : "0" (a), "rm" (b));
- return a;
- }
- static inline unsigned short from32to16(unsigned a)
- {
- unsigned short b = a >> 16;
- asm("addw %w2,%w0\n\t"
- "adcw $0,%w0\n"
- : "=r" (b)
- : "0" (b), "r" (a));
- return b;
- }
- /*
- * Do a 64-bit checksum on an arbitrary memory area.
- * Returns a 32bit checksum.
- *
- * This isn't as time critical as it used to be because many NICs
- * do hardware checksumming these days.
- *
- * Things tried and found to not make it faster:
- * Manual Prefetching
- * Unrolling to an 128 bytes inner loop.
- * Using interleaving with more registers to break the carry chains.
- */
- static unsigned do_csum(const unsigned char *buff, unsigned len)
- {
- unsigned odd, count;
- unsigned long result = 0;
- if ((len == 0))
- return result;
- odd = 1 & (unsigned long) buff;
- if ((odd)) {
- result = *buff << 8;
- len--;
- buff++;
- }
- count = len >> 1; /* nr of 16-bit words.. */
- if (count) {
- if (2 & (unsigned long) buff) {
- result += *(unsigned short *)buff;
- count--;
- len -= 2;
- buff += 2;
- }
- count >>= 1; /* nr of 32-bit words.. */
- if (count) {
- unsigned long zero;
- unsigned count64;
- if (4 & (unsigned long) buff) {
- result += *(unsigned int *) buff;
- count--;
- len -= 4;
- buff += 4;
- }
- count >>= 1; /* nr of 64-bit words.. */
- /* main loop using 64byte blocks */
- zero = 0;
- count64 = count >> 3;
- while (count64) {
- asm("addq 0*8(%[src]),%[res]\n\t"
- "adcq 1*8(%[src]),%[res]\n\t"
- "adcq 2*8(%[src]),%[res]\n\t"
- "adcq 3*8(%[src]),%[res]\n\t"
- "adcq 4*8(%[src]),%[res]\n\t"
- "adcq 5*8(%[src]),%[res]\n\t"
- "adcq 6*8(%[src]),%[res]\n\t"
- "adcq 7*8(%[src]),%[res]\n\t"
- "adcq %[zero],%[res]"
- : [res] "=r" (result)
- : [src] "r" (buff), [zero] "r" (zero),
- "[res]" (result));
- buff += 64;
- count64--;
- }
- /* last up to 7 8byte blocks */
- count %= 8;
- while (count) {
- asm("addq %1,%0\n\t"
- "adcq %2,%0\n"
- : "=r" (result)
- : "m" (*(unsigned long *)buff),
- "r" (zero), "0" (result));
- --count;
- buff += 8;
- }
- result = add32_with_carry(result>>32,
- result&0xffffffff);
- if (len & 4) {
- result += *(unsigned int *) buff;
- buff += 4;
- }
- }
- if (len & 2) {
- result += *(unsigned short *) buff;
- buff += 2;
- }
- }
- if (len & 1)
- result += *buff;
- result = add32_with_carry(result>>32, result & 0xffffffff);
- if ((odd)) {
- result = from32to16(result);
- result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
- }
- return result;
- }
- /*
- * computes the checksum of a memory block at buff, length len,
- * and adds in "sum" (32-bit)
- *
- * returns a 32-bit number suitable for feeding into itself
- * or csum_tcpudp_magic
- *
- * this function must be called with even lengths, except
- * for the last fragment, which may be odd
- *
- * it's best to have buff aligned on a 64-bit boundary
- */
- unsigned int csum_partial(const void *buff, int len, unsigned int sum)
- {
- return (unsigned int)add32_with_carry(do_csum(buff, len), sum);
- }
- uint16_t
- hev_checksum_compute (uint16_t *data, size_t size)
- {
- register uint32_t sum = 0;
- unsigned short oddbyte;
- while (1 < size) {
- sum += *data++;
- size -= 2;
- }
- if(1 == size) {
- oddbyte = 0;
- *((uint8_t *) &oddbyte) = *(uint8_t *) data;
- sum += oddbyte;
- }
- sum = (sum >> 16) + (sum & 0xffff);
- sum += (sum >> 16);
- return (uint16_t) ~sum;
- }
- int
- main (int argc, char *argv[])
- {
- unsigned char buff[1400];
- unsigned int sum = 0;
- printf ("%x\n", hev_checksum_compute ((uint16_t *) buff, 1400));
- sum = csum_partial (buff, 4, sum);
- sum = csum_partial (buff + 4 , 1400 - 4, sum);
- printf ("%x\n", csum_fold (sum));
- sum = csum_partial (buff, 3, sum);
- sum = csum_partial (buff + 3 , 1400 - 3, sum);
- printf ("%x\n", csum_fold (sum));
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement