Commit | Line | Data |
---|---|---|
7e300dab | 1 | // SPDX-License-Identifier: GPL-2.0-only |
d76c1ae4 IM |
2 | /* |
3 | * Copyright 2002, 2003 Andi Kleen, SuSE Labs. | |
0df025b7 | 4 | * |
1da177e4 LT |
5 | * Wrappers of assembly checksum functions for x86-64. |
6 | */ | |
1da177e4 | 7 | #include <asm/checksum.h> |
e683014c | 8 | #include <linux/export.h> |
13d4ea09 | 9 | #include <linux/uaccess.h> |
7263dda4 | 10 | #include <asm/smap.h> |
1da177e4 | 11 | |
0df025b7 | 12 | /** |
0a5ea224 | 13 | * csum_and_copy_from_user - Copy and checksum from user space. |
0df025b7 | 14 | * @src: source address (user space) |
1da177e4 LT |
15 | * @dst: destination address |
16 | * @len: number of bytes to be copied. | |
17 | * @isum: initial sum that is added into the result (32bit unfolded) | |
18 | * @errp: set to -EFAULT for an bad source address. | |
0df025b7 | 19 | * |
1da177e4 | 20 | * Returns an 32bit unfolded checksum of the buffer. |
0df025b7 PC |
21 | * src and dst are best aligned to 64bits. |
22 | */ | |
a4f89fb7 | 23 | __wsum |
daf52375 | 24 | csum_and_copy_from_user(const void __user *src, void *dst, int len) |
0df025b7 | 25 | { |
daf52375 | 26 | __wsum sum; |
c693cc46 | 27 | |
1da177e4 | 28 | might_sleep(); |
73e800ec | 29 | if (!user_access_begin(src, len)) |
c693cc46 | 30 | return 0; |
daf52375 | 31 | sum = csum_partial_copy_generic((__force const void *)src, dst, len); |
73e800ec | 32 | user_access_end(); |
daf52375 | 33 | return sum; |
0df025b7 | 34 | } |
1da177e4 | 35 | |
0df025b7 | 36 | /** |
2a89b674 | 37 | * csum_and_copy_to_user - Copy and checksum to user space. |
1da177e4 LT |
38 | * @src: source address |
39 | * @dst: destination address (user space) | |
40 | * @len: number of bytes to be copied. | |
41 | * @isum: initial sum that is added into the result (32bit unfolded) | |
42 | * @errp: set to -EFAULT for an bad destination address. | |
0df025b7 | 43 | * |
1da177e4 LT |
44 | * Returns an 32bit unfolded checksum of the buffer. |
45 | * src and dst are best aligned to 64bits. | |
0df025b7 | 46 | */ |
a4f89fb7 | 47 | __wsum |
daf52375 | 48 | csum_and_copy_to_user(const void *src, void __user *dst, int len) |
0df025b7 | 49 | { |
daf52375 | 50 | __wsum sum; |
7263dda4 | 51 | |
1da177e4 | 52 | might_sleep(); |
c693cc46 | 53 | if (!user_access_begin(dst, len)) |
0df025b7 | 54 | return 0; |
daf52375 | 55 | sum = csum_partial_copy_generic(src, (void __force *)dst, len); |
73e800ec | 56 | user_access_end(); |
daf52375 | 57 | return sum; |
0df025b7 | 58 | } |
1da177e4 | 59 | |
0df025b7 | 60 | /** |
1da177e4 LT |
61 | * csum_partial_copy_nocheck - Copy and checksum. |
62 | * @src: source address | |
63 | * @dst: destination address | |
64 | * @len: number of bytes to be copied. | |
c15acff3 | 65 | * @sum: initial sum that is added into the result (32bit unfolded) |
0df025b7 | 66 | * |
1da177e4 | 67 | * Returns an 32bit unfolded checksum of the buffer. |
0df025b7 | 68 | */ |
a4f89fb7 | 69 | __wsum |
cc44c17b | 70 | csum_partial_copy_nocheck(const void *src, void *dst, int len) |
0df025b7 | 71 | { |
daf52375 | 72 | return csum_partial_copy_generic(src, dst, len); |
0df025b7 | 73 | } |
2ee60e17 | 74 | EXPORT_SYMBOL(csum_partial_copy_nocheck); |
1da177e4 | 75 | |
a4f89fb7 AV |
76 | __sum16 csum_ipv6_magic(const struct in6_addr *saddr, |
77 | const struct in6_addr *daddr, | |
1e940829 | 78 | __u32 len, __u8 proto, __wsum sum) |
1da177e4 LT |
79 | { |
80 | __u64 rest, sum64; | |
0df025b7 | 81 | |
a4f89fb7 AV |
82 | rest = (__force __u64)htonl(len) + (__force __u64)htons(proto) + |
83 | (__force __u64)sum; | |
d76c1ae4 IM |
84 | |
85 | asm(" addq (%[saddr]),%[sum]\n" | |
86 | " adcq 8(%[saddr]),%[sum]\n" | |
87 | " adcq (%[daddr]),%[sum]\n" | |
88 | " adcq 8(%[daddr]),%[sum]\n" | |
89 | " adcq $0,%[sum]\n" | |
90 | ||
0df025b7 PC |
91 | : [sum] "=r" (sum64) |
92 | : "[sum]" (rest), [saddr] "r" (saddr), [daddr] "r" (daddr)); | |
1da177e4 | 93 | |
d76c1ae4 IM |
94 | return csum_fold( |
95 | (__force __wsum)add32_with_carry(sum64 & 0xffffffff, sum64>>32)); | |
96 | } | |
1da177e4 | 97 | EXPORT_SYMBOL(csum_ipv6_magic); |