linux/arch/x86/lib/csum-wrappers_64.c
<<
>>
Prefs
   1/* Copyright 2002,2003 Andi Kleen, SuSE Labs.
   2 * Subject to the GNU Public License v.2
   3 * 
   4 * Wrappers of assembly checksum functions for x86-64.
   5 */
   6
   7#include <asm/checksum.h>
   8#include <linux/module.h>
   9
  10/** 
  11 * csum_partial_copy_from_user - Copy and checksum from user space. 
  12 * @src: source address (user space) 
  13 * @dst: destination address
  14 * @len: number of bytes to be copied.
  15 * @isum: initial sum that is added into the result (32bit unfolded)
  16 * @errp: set to -EFAULT for an bad source address.
  17 * 
  18 * Returns an 32bit unfolded checksum of the buffer.
  19 * src and dst are best aligned to 64bits. 
  20 */ 
  21__wsum
  22csum_partial_copy_from_user(const void __user *src, void *dst,
  23                            int len, __wsum isum, int *errp)
  24{ 
  25        might_sleep();
  26        *errp = 0;
  27        if (likely(access_ok(VERIFY_READ,src, len))) { 
  28                /* Why 6, not 7? To handle odd addresses aligned we
  29                   would need to do considerable complications to fix the
  30                   checksum which is defined as an 16bit accumulator. The
  31                   fix alignment code is primarily for performance
  32                   compatibility with 32bit and that will handle odd
  33                   addresses slowly too. */
  34                if (unlikely((unsigned long)src & 6)) {                 
  35                        while (((unsigned long)src & 6) && len >= 2) { 
  36                                __u16 val16;                    
  37                                *errp = __get_user(val16, (const __u16 __user *)src);
  38                                if (*errp)
  39                                        return isum;
  40                                *(__u16 *)dst = val16;
  41                                isum = (__force __wsum)add32_with_carry(
  42                                                (__force unsigned)isum, val16);
  43                                src += 2; 
  44                                dst += 2; 
  45                                len -= 2;
  46                        }
  47                }
  48                isum = csum_partial_copy_generic((__force const void *)src,
  49                                        dst, len, isum, errp, NULL);
  50                if (likely(*errp == 0)) 
  51                        return isum;
  52        } 
  53        *errp = -EFAULT;
  54        memset(dst,0,len); 
  55        return isum;            
  56} 
  57
  58EXPORT_SYMBOL(csum_partial_copy_from_user);
  59
  60/** 
  61 * csum_partial_copy_to_user - Copy and checksum to user space. 
  62 * @src: source address
  63 * @dst: destination address (user space)
  64 * @len: number of bytes to be copied.
  65 * @isum: initial sum that is added into the result (32bit unfolded)
  66 * @errp: set to -EFAULT for an bad destination address.
  67 * 
  68 * Returns an 32bit unfolded checksum of the buffer.
  69 * src and dst are best aligned to 64bits.
  70 */ 
  71__wsum
  72csum_partial_copy_to_user(const void *src, void __user *dst,
  73                          int len, __wsum isum, int *errp)
  74{ 
  75        might_sleep();
  76        if (unlikely(!access_ok(VERIFY_WRITE, dst, len))) {
  77                *errp = -EFAULT;
  78                return 0; 
  79        }
  80
  81        if (unlikely((unsigned long)dst & 6)) {
  82                while (((unsigned long)dst & 6) && len >= 2) { 
  83                        __u16 val16 = *(__u16 *)src;
  84                        isum = (__force __wsum)add32_with_carry(
  85                                        (__force unsigned)isum, val16);
  86                        *errp = __put_user(val16, (__u16 __user *)dst);
  87                        if (*errp)
  88                                return isum;
  89                        src += 2; 
  90                        dst += 2; 
  91                        len -= 2;
  92                }
  93        }
  94
  95        *errp = 0;
  96        return csum_partial_copy_generic(src, (void __force *)dst,len,isum,NULL,errp); 
  97} 
  98
  99EXPORT_SYMBOL(csum_partial_copy_to_user);
 100
 101/** 
 102 * csum_partial_copy_nocheck - Copy and checksum.
 103 * @src: source address
 104 * @dst: destination address
 105 * @len: number of bytes to be copied.
 106 * @isum: initial sum that is added into the result (32bit unfolded)
 107 * 
 108 * Returns an 32bit unfolded checksum of the buffer.
 109 */ 
 110__wsum
 111csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
 112{ 
 113        return csum_partial_copy_generic(src,dst,len,sum,NULL,NULL);
 114} 
 115EXPORT_SYMBOL(csum_partial_copy_nocheck);
 116
 117__sum16 csum_ipv6_magic(const struct in6_addr *saddr,
 118                        const struct in6_addr *daddr,
 119                        __u32 len, unsigned short proto, __wsum sum)
 120{
 121        __u64 rest, sum64;
 122     
 123        rest = (__force __u64)htonl(len) + (__force __u64)htons(proto) +
 124                (__force __u64)sum;
 125        asm("  addq (%[saddr]),%[sum]\n"
 126            "  adcq 8(%[saddr]),%[sum]\n"
 127            "  adcq (%[daddr]),%[sum]\n" 
 128            "  adcq 8(%[daddr]),%[sum]\n"
 129            "  adcq $0,%[sum]\n"
 130            : [sum] "=r" (sum64) 
 131            : "[sum]" (rest),[saddr] "r" (saddr), [daddr] "r" (daddr));
 132        return csum_fold((__force __wsum)add32_with_carry(sum64 & 0xffffffff, sum64>>32));
 133}
 134
 135EXPORT_SYMBOL(csum_ipv6_magic);
 136