1 /*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * from tahoe: in_cksum.c 1.2 86/01/05
34 * from: @(#)in_cksum.c 1.3 (Berkeley) 1/19/91
35 * $FreeBSD: src/sys/i386/i386/in_cksum.c,v 1.8.4.2 1999/09/05 08:11:08 peter Exp $
36 */
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/mbuf.h>
41
42 extern int in_cksum __P((struct mbuf *m, int len));
43
44 /*
45 * Checksum routine for Internet Protocol family headers.
46 *
47 * This routine is very heavily used in the network
48 * code and should be modified for each CPU to be as fast as possible.
49 *
50 * This implementation is 386 version.
51 */
52
53 #undef ADDCARRY
54 #define ADDCARRY(x) if ((x) > 0xffff) (x) -= 0xffff
55 #define REDUCE {sum = (sum & 0xffff) + (sum >> 16); ADDCARRY(sum);}
56
57 /*
58 * Thanks to gcc we don't have to guess
59 * which registers contain sum & w.
60 */
61 #define ADD(n) __asm("addl " #n "(%2), %0" : "=r" (sum) : "" (sum), "r" (w))
62 #define ADDC(n) __asm("adcl " #n "(%2), %0" : "=r" (sum) : "" (sum), "r" (w))
63 #define LOAD(n) __asm volatile("movb " #n "(%1), %0" : "=r" (junk) : "r" (w))
64 #define MOP __asm("adcl $0, %0" : "=r" (sum) : "" (sum))
65
66 int
67 in_cksum(m, len)
68 register struct mbuf *m;
69 register int len;
70 {
71 register u_short *w;
72 register unsigned sum = 0;
73 register int mlen = 0;
74 int byte_swapped = 0;
75 union { char c[2]; u_short s; } su;
76
77 for (;m && len; m = m->m_next) {
78 if (m->m_len == 0)
79 continue;
80 w = mtod(m, u_short *);
81 if (mlen == -1) {
82 /*
83 * The first byte of this mbuf is the continuation
84 * of a word spanning between this mbuf and the
85 * last mbuf.
86 */
87
88 /* su.c[0] is already saved when scanning previous
89 * mbuf. sum was REDUCEd when we found mlen == -1
90 */
91 su.c[1] = *(u_char *)w;
92 sum += su.s;
93 w = (u_short *)((char *)w + 1);
94 mlen = m->m_len - 1;
95 len--;
96 } else
97 mlen = m->m_len;
98 if (len < mlen)
99 mlen = len;
100 len -= mlen;
101 /*
102 * Force to long boundary so we do longword aligned
103 * memory operations
104 */
105 if (3 & (int) w) {
106 REDUCE;
107 if ((1 & (int) w) && (mlen > 0)) {
108 sum <<= 8;
109 su.c[0] = *(char *)w;
110 w = (u_short *)((char *)w + 1);
111 mlen--;
112 byte_swapped = 1;
113 }
114 if ((2 & (int) w) && (mlen >= 2)) {
115 sum += *w++;
116 mlen -= 2;
117 }
118 }
119 /*
120 * Advance to a 486 cache line boundary.
121 */
122 if (4 & (int) w && mlen >= 4) {
123 ADD(0);
124 MOP;
125 w += 2;
126 mlen -= 4;
127 }
128 if (8 & (int) w && mlen >= 8) {
129 ADD(0);
130 ADDC(4);
131 MOP;
132 w += 4;
133 mlen -= 8;
134 }
135 /*
136 * Do as much of the checksum as possible 32 bits at at time.
137 * In fact, this loop is unrolled to make overhead from
138 * branches &c small.
139 */
140 mlen -= 1;
141 while ((mlen -= 32) >= 0) {
142 u_char junk;
143 /*
144 * Add with carry 16 words and fold in the last
145 * carry by adding a 0 with carry.
146 *
147 * The early ADD(16) and the LOAD(32) are to load
148 * the next 2 cache lines in advance on 486's. The
149 * 486 has a penalty of 2 clock cycles for loading
150 * a cache line, plus whatever time the external
151 * memory takes to load the first word(s) addressed.
152 * These penalties are unavoidable. Subsequent
153 * accesses to a cache line being loaded (and to
154 * other external memory?) are delayed until the
155 * whole load finishes. These penalties are mostly
156 * avoided by not accessing external memory for
157 * 8 cycles after the ADD(16) and 12 cycles after
158 * the LOAD(32). The loop terminates when mlen
159 * is initially 33 (not 32) to guaranteed that
160 * the LOAD(32) is within bounds.
161 */
162 ADD(16);
163 ADDC(0);
164 ADDC(4);
165 ADDC(8);
166 ADDC(12);
167 LOAD(32);
168 ADDC(20);
169 ADDC(24);
170 ADDC(28);
171 MOP;
172 w += 16;
173 }
174 mlen += 32 + 1;
175 if (mlen >= 32) {
176 ADD(16);
177 ADDC(0);
178 ADDC(4);
179 ADDC(8);
180 ADDC(12);
181 ADDC(20);
182 ADDC(24);
183 ADDC(28);
184 MOP;
185 w += 16;
186 mlen -= 32;
187 }
188 if (mlen >= 16) {
189 ADD(0);
190 ADDC(4);
191 ADDC(8);
192 ADDC(12);
193 MOP;
194 w += 8;
195 mlen -= 16;
196 }
197 if (mlen >= 8) {
198 ADD(0);
199 ADDC(4);
200 MOP;
201 w += 4;
202 mlen -= 8;
203 }
204 if (mlen == 0 && byte_swapped == 0)
205 continue; /* worth 1% maybe ?? */
206 REDUCE;
207 while ((mlen -= 2) >= 0) {
208 sum += *w++;
209 }
210 if (byte_swapped) {
211 sum <<= 8;
212 byte_swapped = 0;
213 if (mlen == -1) {
214 su.c[1] = *(char *)w;
215 sum += su.s;
216 mlen = 0;
217 } else
218 mlen = -1;
219 } else if (mlen == -1)
220 /*
221 * This mbuf has odd number of bytes.
222 * There could be a word split betwen
223 * this mbuf and the next mbuf.
224 * Save the last byte (to prepend to next mbuf).
225 */
226 su.c[0] = *(char *)w;
227 }
228
229 if (len)
230 printf("cksum: out of data\n");
231 if (mlen == -1) {
232 /* The last mbuf has odd # of bytes. Follow the
233 standard (the odd byte is shifted left by 8 bits) */
234 su.c[1] = 0;
235 sum += su.s;
236 }
237 REDUCE;
238 return (~sum & 0xffff);
239 }
Cache object: b3454ca4db3828e35bddd2c138d96913
|