checksum.h
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:6k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /* $Id: checksum.h,v 1.17 2001/04/24 01:09:12 davem Exp $ */
  2. #ifndef __SPARC64_CHECKSUM_H
  3. #define __SPARC64_CHECKSUM_H
  4. /*  checksum.h:  IP/UDP/TCP checksum routines on the V9.
  5.  *
  6.  *  Copyright(C) 1995 Linus Torvalds
  7.  *  Copyright(C) 1995 Miguel de Icaza
  8.  *  Copyright(C) 1996 David S. Miller
  9.  *  Copyright(C) 1996 Eddie C. Dost
  10.  *  Copyright(C) 1997 Jakub Jelinek
  11.  *
  12.  * derived from:
  13.  * Alpha checksum c-code
  14.  *      ix86 inline assembly
  15.  *      RFC1071 Computing the Internet Checksum
  16.  */
  17. #include <asm/uaccess.h> 
  18. /* computes the checksum of a memory block at buff, length len,
  19.  * and adds in "sum" (32-bit)
  20.  *
  21.  * returns a 32-bit number suitable for feeding into itself
  22.  * or csum_tcpudp_magic
  23.  *
  24.  * this function must be called with even lengths, except
  25.  * for the last fragment, which may be odd
  26.  *
  27.  * it's best to have buff aligned on a 32-bit boundary
  28.  */
  29. extern unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum);
  30. /* the same as csum_partial, but copies from user space while it
  31.  * checksums
  32.  *
  33.  * here even more important to align src and dst on a 32-bit (or even
  34.  * better 64-bit) boundary
  35.  */
  36. extern unsigned int csum_partial_copy_sparc64(const char *src, char *dst, int len, unsigned int sum);
  37. extern __inline__ unsigned int 
  38. csum_partial_copy_nocheck (const char *src, char *dst, int len, 
  39.    unsigned int sum)
  40. {
  41. int ret;
  42. unsigned char cur_ds = current->thread.current_ds.seg;
  43. __asm__ __volatile__ ("wr %%g0, %0, %%asi" : : "i" (ASI_P));
  44. ret = csum_partial_copy_sparc64(src, dst, len, sum);
  45. __asm__ __volatile__ ("wr %%g0, %0, %%asi" : : "r" (cur_ds));
  46. return ret;
  47. }
  48. extern __inline__ unsigned int 
  49. csum_partial_copy_from_user(const char *src, char *dst, int len, 
  50.     unsigned int sum, int *err)
  51. {
  52. __asm__ __volatile__ ("stx %0, [%%sp + 0x7ff + 128]"
  53.       : : "r" (err));
  54. return csum_partial_copy_sparc64(src, dst, len, sum);
  55. }
  56. /* 
  57.  * Copy and checksum to user
  58.  */
  59. #define HAVE_CSUM_COPY_USER
  60. extern unsigned int csum_partial_copy_user_sparc64(const char *src, char *dst, int len, unsigned int sum);
  61. extern __inline__ unsigned int 
  62. csum_and_copy_to_user(const char *src, char *dst, int len, 
  63.       unsigned int sum, int *err)
  64. {
  65. __asm__ __volatile__ ("stx %0, [%%sp + 0x7ff + 128]"
  66.       : : "r" (err));
  67. return csum_partial_copy_user_sparc64(src, dst, len, sum);
  68. }
  69.   
  70. /* ihl is always 5 or greater, almost always is 5, and iph is word aligned
  71.  * the majority of the time.
  72.  */
  73. extern __inline__ unsigned short ip_fast_csum(__const__ unsigned char *iph,
  74.       unsigned int ihl)
  75. {
  76. unsigned short sum;
  77. /* Note: We must read %2 before we touch %0 for the first time,
  78.  *       because GCC can legitimately use the same register for
  79.  *       both operands.
  80.  */
  81. __asm__ __volatile__(
  82. " sub %2, 4, %%g7 ! IEU0n"
  83. " lduw [%1 + 0x00], %0 ! Load Groupn"
  84. " lduw [%1 + 0x04], %%g2 ! Load Groupn"
  85. " lduw [%1 + 0x08], %%g3 ! Load Groupn"
  86. " addcc %%g2, %0, %0 ! IEU1 1 Load Bubble + Groupn"
  87. " lduw [%1 + 0x0c], %%g2 ! Loadn"
  88. " addccc %%g3, %0, %0 ! Sngle Group no Bubblen"
  89. " lduw [%1 + 0x10], %%g3 ! Load Groupn"
  90. " addccc %%g2, %0, %0 ! Sngle Group no Bubblen"
  91. " addc %0, %%g0, %0 ! Sngle Groupn"
  92. "1: addcc %%g3, %0, %0 ! IEU1 Group no Bubblen"
  93. " add %1, 4, %1 ! IEU0n"
  94. " addccc %0, %%g0, %0 ! Sngle Group no Bubblen"
  95. " subcc %%g7, 1, %%g7 ! IEU1 Groupn"
  96. " be,a,pt %%icc, 2f ! CTIn"
  97. "  sll %0, 16, %%g2 ! IEU0n"
  98. " lduw [%1 + 0x10], %%g3 ! Load Groupn"
  99. " ba,pt %%xcc, 1b ! CTIn"
  100. "  nop ! IEU0n"
  101. "2: addcc %0, %%g2, %%g2 ! IEU1 Groupn"
  102. " srl %%g2, 16, %0 ! IEU0 Group regdep XXX Scheisse!n"
  103. " addc %0, %%g0, %0 ! Sngle Groupn"
  104. " xnor %%g0, %0, %0 ! IEU0 Groupn"
  105. " srl %0, 0, %0 ! IEU0 Group XXX Scheisse!n"
  106. : "=r" (sum), "=&r" (iph)
  107. : "r" (ihl), "1" (iph)
  108. : "g2", "g3", "g7", "cc");
  109. return sum;
  110. }
  111. /* Fold a partial checksum without adding pseudo headers. */
  112. extern __inline__ unsigned short csum_fold(unsigned int sum)
  113. {
  114. unsigned int tmp;
  115. __asm__ __volatile__(
  116. " addcc %0, %1, %1n"
  117. " srl %1, 16, %1n"
  118. " addc %1, %%g0, %1n"
  119. " xnor %%g0, %1, %0n"
  120. : "=&r" (sum), "=r" (tmp)
  121. : "0" (sum), "1" (sum<<16)
  122. : "cc");
  123. return (sum & 0xffff);
  124. }
  125. extern __inline__ unsigned long csum_tcpudp_nofold(unsigned long saddr,
  126.    unsigned long daddr,
  127.    unsigned int len,
  128.    unsigned short proto,
  129.    unsigned int sum)
  130. {
  131. __asm__ __volatile__(
  132. " addcc %1, %0, %0n"
  133. " addccc %2, %0, %0n"
  134. " addccc %3, %0, %0n"
  135. " addc %0, %%g0, %0n"
  136. : "=r" (sum), "=r" (saddr)
  137. : "r" (daddr), "r" ((proto<<16)+len), "0" (sum), "1" (saddr)
  138. : "cc");
  139. return sum;
  140. }
  141. /*
  142.  * computes the checksum of the TCP/UDP pseudo-header
  143.  * returns a 16-bit checksum, already complemented
  144.  */
  145. static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
  146.    unsigned long daddr,
  147.    unsigned short len,
  148.    unsigned short proto,
  149.    unsigned int sum) 
  150. {
  151. return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
  152. }
  153. #define _HAVE_ARCH_IPV6_CSUM
  154. static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
  155.      struct in6_addr *daddr,
  156.      __u32 len,
  157.      unsigned short proto,
  158.      unsigned int sum) 
  159. {
  160. __asm__ __volatile__ (
  161. " addcc %3, %4, %%g7n"
  162. " addccc %5, %%g7, %%g7n"
  163. " lduw [%2 + 0x0c], %%g2n"
  164. " lduw [%2 + 0x08], %%g3n"
  165. " addccc %%g2, %%g7, %%g7n"
  166. " lduw [%2 + 0x04], %%g2n"
  167. " addccc %%g3, %%g7, %%g7n"
  168. " lduw [%2 + 0x00], %%g3n"
  169. " addccc %%g2, %%g7, %%g7n"
  170. " lduw [%1 + 0x0c], %%g2n"
  171. " addccc %%g3, %%g7, %%g7n"
  172. " lduw [%1 + 0x08], %%g3n"
  173. " addccc %%g2, %%g7, %%g7n"
  174. " lduw [%1 + 0x04], %%g2n"
  175. " addccc %%g3, %%g7, %%g7n"
  176. " lduw [%1 + 0x00], %%g3n"
  177. " addccc %%g2, %%g7, %%g7n"
  178. " addccc %%g3, %%g7, %0n"
  179. " addc 0, %0, %0n"
  180. : "=&r" (sum)
  181. : "r" (saddr), "r" (daddr), "r"(htonl(len)),
  182.   "r"(htonl(proto)), "r"(sum)
  183. : "g2", "g3", "g7", "cc");
  184. return csum_fold(sum);
  185. }
  186. /* this routine is used for miscellaneous IP-like checksums, mainly in icmp.c */
  187. extern __inline__ unsigned short ip_compute_csum(unsigned char * buff, int len)
  188. {
  189. return csum_fold(csum_partial(buff, len, 0));
  190. }
  191. #endif /* !(__SPARC64_CHECKSUM_H) */