diff options
Diffstat (limited to 'include/asm-sparc/checksum.h')
-rw-r--r-- | include/asm-sparc/checksum.h | 95 |
1 files changed, 88 insertions, 7 deletions
diff --git a/include/asm-sparc/checksum.h b/include/asm-sparc/checksum.h index a11777025..85311970c 100644 --- a/include/asm-sparc/checksum.h +++ b/include/asm-sparc/checksum.h @@ -1,4 +1,4 @@ -/* $Id: checksum.h,v 1.22 1996/11/10 21:28:25 davem Exp $ */ +/* $Id: checksum.h,v 1.27 1997/04/11 00:42:18 davem Exp $ */ #ifndef __SPARC_CHECKSUM_H #define __SPARC_CHECKSUM_H @@ -8,12 +8,16 @@ * Copyright(C) 1995 Miguel de Icaza * Copyright(C) 1996 David S. Miller * Copyright(C) 1996 Eddie C. Dost + * Copyright(C) 1997 Jakub Jelinek * * derived from: * Alpha checksum c-code * ix86 inline assembly * RFC1071 Computing the Internet Checksum */ + +#include <asm/uaccess.h> +#include <asm/cprefix.h> /* computes the checksum of a memory block at buff, length len, * and adds in "sum" (32-bit) @@ -34,11 +38,86 @@ extern unsigned int csum_partial(unsigned char * buff, int len, unsigned int sum * here even more important to align src and dst on a 32-bit (or even * better 64-bit) boundary */ -extern unsigned int csum_partial_copy(char *src, char *dst, int len, int sum); +/* FIXME: Remove these two macros ASAP */ +#define csum_partial_copy(src, dst, len, sum) \ + csum_partial_copy_nocheck(src,dst,len,sum) #define csum_partial_copy_fromuser(s, d, l, w) \ - csum_partial_copy((char *) (s), (d), (l), (w)) + csum_partial_copy((char *) (s), (d), (l), (w)) + +extern unsigned int __csum_partial_copy_sparc_generic (const char *, char *); +extern __inline__ unsigned int +csum_partial_copy_nocheck (const char *src, char *dst, int len, + unsigned int sum) +{ + register unsigned int ret asm("o0") = (unsigned int)src; + register char *d asm("o1") = dst; + register int l asm("g1") = len; + + __asm__ __volatile__ (" + call " C_LABEL_STR(__csum_partial_copy_sparc_generic) " + mov %4, %%g7 + " : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (sum) : + "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g4", "g5", "g7"); + return ret; +} + +extern __inline__ unsigned int +csum_partial_copy_from_user(const char *src, char *dst, int len, + unsigned int sum, int *err) + { + if (!access_ok (VERIFY_READ, src, len)) { + *err = -EFAULT; + memset (dst, 0, len); + return sum; + } else { + register unsigned int ret asm("o0") = (unsigned int)src; + register char *d asm("o1") = dst; + register int l asm("g1") = len; + register unsigned int s asm("g7") = sum; + + __asm__ __volatile__ (" + .section __ex_table,#alloc + .align 4 + .word 1f,2 + .previous +1: + call " C_LABEL_STR(__csum_partial_copy_sparc_generic) " + st %5, [%%sp + 64] + " : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (s), "r" (err) : + "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g4", "g5", "g7"); + return ret; + } + } + +extern __inline__ unsigned int +csum_partial_copy_to_user(const char *src, char *dst, int len, + unsigned int sum, int *err) +{ + if (!access_ok (VERIFY_WRITE, dst, len)) { + *err = -EFAULT; + return sum; + } else { + register unsigned int ret asm("o0") = (unsigned int)src; + register char *d asm("o1") = dst; + register int l asm("g1") = len; + register unsigned int s asm("g7") = sum; + + __asm__ __volatile__ (" + .section __ex_table,#alloc + .align 4 + .word 1f,1 + .previous +1: + call " C_LABEL_STR(__csum_partial_copy_sparc_generic) " + st %5, [%%sp + 64] + " : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (s), "r" (err) : + "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g4", "g5", "g7"); + return ret; + } +} + /* ihl is always 5 or greater, almost always is 5, and iph is word aligned * the majority of the time. */ @@ -75,7 +154,7 @@ extern __inline__ unsigned short ip_fast_csum(__const__ unsigned char *iph, "xnor\t%%g0, %0, %0" : "=r" (sum), "=&r" (iph) : "r" (ihl), "1" (iph) - : "g2", "g3", "g4"); + : "g2", "g3", "g4", "cc"); return sum; } @@ -99,7 +178,8 @@ extern __inline__ unsigned short csum_tcpudp_magic(unsigned long saddr, "xnor\t%%g0, %0, %0" : "=r" (sum), "=r" (saddr) : "r" (daddr), "r" ((proto<<16)+len), "0" (sum), - "1" (saddr)); + "1" (saddr) + : "cc"); return sum; } @@ -113,7 +193,8 @@ extern __inline__ unsigned int csum_fold(unsigned int sum) "addx\t%1, %%g0, %1\n\t" "xnor\t%%g0, %1, %0" : "=&r" (sum), "=r" (tmp) - : "0" (sum), "1" (sum<<16)); + : "0" (sum), "1" (sum<<16) + : "cc"); return sum; } @@ -149,7 +230,7 @@ static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr, : "=&r" (sum) : "r" (saddr), "r" (daddr), "r"(htonl((__u32) (len))), "r"(htonl(proto)), "r"(sum) - : "g2", "g3", "g4"); + : "g2", "g3", "g4", "cc"); return csum_fold(sum); } |