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