Advertisement
Guest User

Csum

a guest
Aug 4th, 2015
247
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 4.40 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdint.h>
  3.  
  4. static inline unsigned short csum_fold(unsigned int sum)
  5. {
  6.     asm("  addl %1,%0\n"
  7.         "  adcl $0xffff,%0"
  8.         : "=r" (sum)
  9.         : "r" ((unsigned int)sum << 16),
  10.           "0" ((unsigned int)sum & 0xffff0000));
  11.     return (unsigned short)(~(unsigned int)sum >> 16);
  12. }
  13.  
  14. static inline unsigned add32_with_carry(unsigned a, unsigned b)
  15. {
  16.     asm("addl %2,%0\n\t"
  17.         "adcl $0,%0"
  18.         : "=r" (a)
  19.         : "0" (a), "rm" (b));
  20.     return a;
  21. }
  22.  
  23. static inline unsigned short from32to16(unsigned a)
  24. {
  25.     unsigned short b = a >> 16;
  26.     asm("addw %w2,%w0\n\t"
  27.         "adcw $0,%w0\n"
  28.         : "=r" (b)
  29.         : "0" (b), "r" (a));
  30.     return b;
  31. }
  32.  
  33. /*
  34.  * Do a 64-bit checksum on an arbitrary memory area.
  35.  * Returns a 32bit checksum.
  36.  *
  37.  * This isn't as time critical as it used to be because many NICs
  38.  * do hardware checksumming these days.
  39.  *
  40.  * Things tried and found to not make it faster:
  41.  * Manual Prefetching
  42.  * Unrolling to an 128 bytes inner loop.
  43.  * Using interleaving with more registers to break the carry chains.
  44.  */
  45. static unsigned do_csum(const unsigned char *buff, unsigned len)
  46. {
  47.     unsigned odd, count;
  48.     unsigned long result = 0;
  49.  
  50.     if ((len == 0))
  51.         return result;
  52.     odd = 1 & (unsigned long) buff;
  53.     if ((odd)) {
  54.         result = *buff << 8;
  55.         len--;
  56.         buff++;
  57.     }
  58.     count = len >> 1;       /* nr of 16-bit words.. */
  59.     if (count) {
  60.         if (2 & (unsigned long) buff) {
  61.             result += *(unsigned short *)buff;
  62.             count--;
  63.             len -= 2;
  64.             buff += 2;
  65.         }
  66.         count >>= 1;        /* nr of 32-bit words.. */
  67.         if (count) {
  68.             unsigned long zero;
  69.             unsigned count64;
  70.             if (4 & (unsigned long) buff) {
  71.                 result += *(unsigned int *) buff;
  72.                 count--;
  73.                 len -= 4;
  74.                 buff += 4;
  75.             }
  76.             count >>= 1;    /* nr of 64-bit words.. */
  77.  
  78.             /* main loop using 64byte blocks */
  79.             zero = 0;
  80.             count64 = count >> 3;
  81.             while (count64) {
  82.                 asm("addq 0*8(%[src]),%[res]\n\t"
  83.                     "adcq 1*8(%[src]),%[res]\n\t"
  84.                     "adcq 2*8(%[src]),%[res]\n\t"
  85.                     "adcq 3*8(%[src]),%[res]\n\t"
  86.                     "adcq 4*8(%[src]),%[res]\n\t"
  87.                     "adcq 5*8(%[src]),%[res]\n\t"
  88.                     "adcq 6*8(%[src]),%[res]\n\t"
  89.                     "adcq 7*8(%[src]),%[res]\n\t"
  90.                     "adcq %[zero],%[res]"
  91.                     : [res] "=r" (result)
  92.                     : [src] "r" (buff), [zero] "r" (zero),
  93.                     "[res]" (result));
  94.                 buff += 64;
  95.                 count64--;
  96.             }
  97.  
  98.             /* last up to 7 8byte blocks */
  99.             count %= 8;
  100.             while (count) {
  101.                 asm("addq %1,%0\n\t"
  102.                     "adcq %2,%0\n"
  103.                         : "=r" (result)
  104.                     : "m" (*(unsigned long *)buff),
  105.                     "r" (zero),  "0" (result));
  106.                 --count;
  107.                     buff += 8;
  108.             }
  109.             result = add32_with_carry(result>>32,
  110.                           result&0xffffffff);
  111.  
  112.             if (len & 4) {
  113.                 result += *(unsigned int *) buff;
  114.                 buff += 4;
  115.             }
  116.         }
  117.         if (len & 2) {
  118.             result += *(unsigned short *) buff;
  119.             buff += 2;
  120.         }
  121.     }
  122.     if (len & 1)
  123.         result += *buff;
  124.     result = add32_with_carry(result>>32, result & 0xffffffff);
  125.     if ((odd)) {
  126.         result = from32to16(result);
  127.         result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
  128.     }
  129.     return result;
  130. }
  131.  
  132. /*
  133.  * computes the checksum of a memory block at buff, length len,
  134.  * and adds in "sum" (32-bit)
  135.  *
  136.  * returns a 32-bit number suitable for feeding into itself
  137.  * or csum_tcpudp_magic
  138.  *
  139.  * this function must be called with even lengths, except
  140.  * for the last fragment, which may be odd
  141.  *
  142.  * it's best to have buff aligned on a 64-bit boundary
  143.  */
  144. unsigned int csum_partial(const void *buff, int len, unsigned int sum)
  145. {
  146.     return (unsigned int)add32_with_carry(do_csum(buff, len), sum);
  147. }
  148.  
  149. uint16_t
  150. hev_checksum_compute (uint16_t *data, size_t size)
  151. {
  152.     register uint32_t sum = 0;
  153.     unsigned short oddbyte;
  154.  
  155.     while (1 < size) {
  156.         sum += *data++;
  157.         size -= 2;
  158.     }
  159.     if(1 == size) {
  160.         oddbyte = 0;
  161.         *((uint8_t *) &oddbyte) = *(uint8_t *) data;
  162.         sum += oddbyte;
  163.     }
  164.  
  165.     sum = (sum >> 16) + (sum & 0xffff);
  166.     sum += (sum >> 16);
  167.  
  168.     return (uint16_t) ~sum;
  169. }
  170.  
  171. int
  172. main (int argc, char *argv[])
  173. {
  174.     unsigned char buff[1400];
  175.  
  176.     unsigned int sum = 0;
  177.  
  178.     printf ("%x\n", hev_checksum_compute ((uint16_t *) buff, 1400));
  179.  
  180.     sum = csum_partial (buff, 4, sum);
  181.     sum = csum_partial (buff + 4 , 1400 - 4, sum);
  182.     printf ("%x\n", csum_fold (sum));
  183.  
  184.     sum = csum_partial (buff, 3, sum);
  185.     sum = csum_partial (buff + 3 , 1400 - 3, sum);
  186.     printf ("%x\n", csum_fold (sum));
  187.  
  188.     return 0;
  189. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement