Branch data Line data Source code
1 : : /* SPDX-License-Identifier: GPL-2.0 */
2 : : #ifndef _ASM_X86_CHECKSUM_64_H
3 : : #define _ASM_X86_CHECKSUM_64_H
4 : :
5 : : /*
6 : : * Checksums for x86-64
7 : : * Copyright 2002 by Andi Kleen, SuSE Labs
8 : : * with some code from asm-x86/checksum.h
9 : : */
10 : :
11 : : #include <linux/compiler.h>
12 : : #include <linux/uaccess.h>
13 : : #include <asm/byteorder.h>
14 : :
15 : : /**
16 : : * csum_fold - Fold and invert a 32bit checksum.
17 : : * sum: 32bit unfolded sum
18 : : *
19 : : * Fold a 32bit running checksum to 16bit and invert it. This is usually
20 : : * the last step before putting a checksum into a packet.
21 : : * Make sure not to mix with 64bit checksums.
22 : : */
23 : 351 : static inline __sum16 csum_fold(__wsum sum)
24 : : {
25 : 351 : asm(" addl %1,%0\n"
26 : : " adcl $0xffff,%0"
27 : : : "=r" (sum)
28 : 351 : : "r" ((__force u32)sum << 16),
29 : 351 : "0" ((__force u32)sum & 0xffff0000));
30 [ # # ]: 351 : return (__force __sum16)(~(__force u32)sum >> 16);
31 : : }
32 : :
33 : : /*
34 : : * This is a version of ip_compute_csum() optimized for IP headers,
35 : : * which always checksum on 4 octet boundaries.
36 : : *
37 : : * By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
38 : : * Arnt Gulbrandsen.
39 : : */
40 : :
41 : : /**
42 : : * ip_fast_csum - Compute the IPv4 header checksum efficiently.
43 : : * iph: ipv4 header
44 : : * ihl: length of header / 4
45 : : */
46 : 0 : static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
47 : : {
48 : 0 : unsigned int sum;
49 : :
50 : 0 : asm(" movl (%1), %0\n"
51 : : " subl $4, %2\n"
52 : : " jbe 2f\n"
53 : : " addl 4(%1), %0\n"
54 : : " adcl 8(%1), %0\n"
55 : : " adcl 12(%1), %0\n"
56 : : "1: adcl 16(%1), %0\n"
57 : : " lea 4(%1), %1\n"
58 : : " decl %2\n"
59 : : " jne 1b\n"
60 : : " adcl $0, %0\n"
61 : : " movl %0, %2\n"
62 : : " shrl $16, %0\n"
63 : : " addw %w2, %w0\n"
64 : : " adcl $0, %0\n"
65 : : " notl %0\n"
66 : : "2:"
67 : : /* Since the input registers which are loaded with iph and ihl
68 : : are modified, we must also specify them as outputs, or gcc
69 : : will assume they contain their original values. */
70 : : : "=r" (sum), "=r" (iph), "=r" (ihl)
71 : : : "1" (iph), "2" (ihl)
72 : : : "memory");
73 [ # # ]: 0 : return (__force __sum16)sum;
74 : : }
75 : :
76 : : /**
77 : : * csum_tcpup_nofold - Compute an IPv4 pseudo header checksum.
78 : : * @saddr: source address
79 : : * @daddr: destination address
80 : : * @len: length of packet
81 : : * @proto: ip protocol of packet
82 : : * @sum: initial sum to be added in (32bit unfolded)
83 : : *
84 : : * Returns the pseudo header checksum the input data. Result is
85 : : * 32bit unfolded.
86 : : */
87 : : static inline __wsum
88 : 0 : csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len,
89 : : __u8 proto, __wsum sum)
90 : : {
91 : 0 : asm(" addl %1, %0\n"
92 : : " adcl %2, %0\n"
93 : : " adcl %3, %0\n"
94 : : " adcl $0, %0\n"
95 : : : "=r" (sum)
96 : : : "g" (daddr), "g" (saddr),
97 : 0 : "g" ((len + proto)<<8), "0" (sum));
98 [ # # # # ]: 0 : return sum;
99 : : }
100 : :
101 : :
102 : : /**
103 : : * csum_tcpup_magic - Compute an IPv4 pseudo header checksum.
104 : : * @saddr: source address
105 : : * @daddr: destination address
106 : : * @len: length of packet
107 : : * @proto: ip protocol of packet
108 : : * @sum: initial sum to be added in (32bit unfolded)
109 : : *
110 : : * Returns the 16bit pseudo header checksum the input data already
111 : : * complemented and ready to be filled in.
112 : : */
113 : 0 : static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
114 : : __u32 len, __u8 proto,
115 : : __wsum sum)
116 : : {
117 [ # # # # ]: 0 : return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
118 : : }
119 : :
120 : : /**
121 : : * csum_partial - Compute an internet checksum.
122 : : * @buff: buffer to be checksummed
123 : : * @len: length of buffer.
124 : : * @sum: initial sum to be added in (32bit unfolded)
125 : : *
126 : : * Returns the 32bit unfolded internet checksum of the buffer.
127 : : * Before filling it in it needs to be csum_fold()'ed.
128 : : * buff should be aligned to a 64bit boundary if possible.
129 : : */
130 : : extern __wsum csum_partial(const void *buff, int len, __wsum sum);
131 : :
132 : : #define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER 1
133 : : #define HAVE_CSUM_COPY_USER 1
134 : :
135 : :
136 : : /* Do not call this directly. Use the wrappers below */
137 : : extern __visible __wsum csum_partial_copy_generic(const void *src, const void *dst,
138 : : int len, __wsum sum,
139 : : int *src_err_ptr, int *dst_err_ptr);
140 : :
141 : :
142 : : extern __wsum csum_partial_copy_from_user(const void __user *src, void *dst,
143 : : int len, __wsum isum, int *errp);
144 : : extern __wsum csum_partial_copy_to_user(const void *src, void __user *dst,
145 : : int len, __wsum isum, int *errp);
146 : : extern __wsum csum_partial_copy_nocheck(const void *src, void *dst,
147 : : int len, __wsum sum);
148 : :
149 : : /* Old names. To be removed. */
150 : : #define csum_and_copy_to_user csum_partial_copy_to_user
151 : : #define csum_and_copy_from_user csum_partial_copy_from_user
152 : :
153 : : /**
154 : : * ip_compute_csum - Compute an 16bit IP checksum.
155 : : * @buff: buffer address.
156 : : * @len: length of buffer.
157 : : *
158 : : * Returns the 16bit folded/inverted checksum of the passed buffer.
159 : : * Ready to fill in.
160 : : */
161 : : extern __sum16 ip_compute_csum(const void *buff, int len);
162 : :
163 : : /**
164 : : * csum_ipv6_magic - Compute checksum of an IPv6 pseudo header.
165 : : * @saddr: source address
166 : : * @daddr: destination address
167 : : * @len: length of packet
168 : : * @proto: protocol of packet
169 : : * @sum: initial sum (32bit unfolded) to be added in
170 : : *
171 : : * Computes an IPv6 pseudo header checksum. This sum is added the checksum
172 : : * into UDP/TCP packets and contains some link layer information.
173 : : * Returns the unfolded 32bit checksum.
174 : : */
175 : :
176 : : struct in6_addr;
177 : :
178 : : #define _HAVE_ARCH_IPV6_CSUM 1
179 : : extern __sum16
180 : : csum_ipv6_magic(const struct in6_addr *saddr, const struct in6_addr *daddr,
181 : : __u32 len, __u8 proto, __wsum sum);
182 : :
183 : 1053 : static inline unsigned add32_with_carry(unsigned a, unsigned b)
184 : : {
185 : 1053 : asm("addl %2,%0\n\t"
186 : : "adcl $0,%0"
187 : : : "=r" (a)
188 : : : "0" (a), "rm" (b));
189 [ + - - + ]: 702 : return a;
190 : : }
191 : :
192 : : #define HAVE_ARCH_CSUM_ADD
193 : 0 : static inline __wsum csum_add(__wsum csum, __wsum addend)
194 : : {
195 [ # # # # : 0 : return (__force __wsum)add32_with_carry((__force unsigned)csum,
# # ]
196 : : (__force unsigned)addend);
197 : : }
198 : :
199 : : #endif /* _ASM_X86_CHECKSUM_64_H */
|