diff options
Diffstat (limited to 'arch/m68k/lib/checksum.c')
-rw-r--r-- | arch/m68k/lib/checksum.c | 422 |
1 files changed, 422 insertions, 0 deletions
diff --git a/arch/m68k/lib/checksum.c b/arch/m68k/lib/checksum.c new file mode 100644 index 000000000000..4a5c5445c610 --- /dev/null +++ b/arch/m68k/lib/checksum.c | |||
@@ -0,0 +1,422 @@ | |||
1 | /* | ||
2 | * INET An implementation of the TCP/IP protocol suite for the LINUX | ||
3 | * operating system. INET is implemented using the BSD Socket | ||
4 | * interface as the means of communication with the user level. | ||
5 | * | ||
6 | * IP/TCP/UDP checksumming routines | ||
7 | * | ||
8 | * Authors: Jorge Cwik, <jorge@laser.satlink.net> | ||
9 | * Arnt Gulbrandsen, <agulbra@nvg.unit.no> | ||
10 | * Tom May, <ftom@netcom.com> | ||
11 | * Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de> | ||
12 | * Lots of code moved from tcp.c and ip.c; see those files | ||
13 | * for more names. | ||
14 | * | ||
15 | * 03/02/96 Jes Sorensen, Andreas Schwab, Roman Hodek: | ||
16 | * Fixed some nasty bugs, causing some horrible crashes. | ||
17 | * A: At some points, the sum (%0) was used as | ||
18 | * length-counter instead of the length counter | ||
19 | * (%1). Thanks to Roman Hodek for pointing this out. | ||
20 | * B: GCC seems to mess up if one uses too many | ||
21 | * data-registers to hold input values and one tries to | ||
22 | * specify d0 and d1 as scratch registers. Letting gcc | ||
23 | * choose these registers itself solves the problem. | ||
24 | * | ||
25 | * This program is free software; you can redistribute it and/or | ||
26 | * modify it under the terms of the GNU General Public License | ||
27 | * as published by the Free Software Foundation; either version | ||
28 | * 2 of the License, or (at your option) any later version. | ||
29 | * | ||
30 | * 1998/8/31 Andreas Schwab: | ||
31 | * Zero out rest of buffer on exception in | ||
32 | * csum_partial_copy_from_user. | ||
33 | */ | ||
34 | |||
35 | #include <linux/module.h> | ||
36 | #include <net/checksum.h> | ||
37 | |||
38 | /* | ||
39 | * computes a partial checksum, e.g. for TCP/UDP fragments | ||
40 | */ | ||
41 | |||
42 | unsigned int | ||
43 | csum_partial (const unsigned char *buff, int len, unsigned int sum) | ||
44 | { | ||
45 | unsigned long tmp1, tmp2; | ||
46 | /* | ||
47 | * Experiments with ethernet and slip connections show that buff | ||
48 | * is aligned on either a 2-byte or 4-byte boundary. | ||
49 | */ | ||
50 | __asm__("movel %2,%3\n\t" | ||
51 | "btst #1,%3\n\t" /* Check alignment */ | ||
52 | "jeq 2f\n\t" | ||
53 | "subql #2,%1\n\t" /* buff%4==2: treat first word */ | ||
54 | "jgt 1f\n\t" | ||
55 | "addql #2,%1\n\t" /* len was == 2, treat only rest */ | ||
56 | "jra 4f\n" | ||
57 | "1:\t" | ||
58 | "addw %2@+,%0\n\t" /* add first word to sum */ | ||
59 | "clrl %3\n\t" | ||
60 | "addxl %3,%0\n" /* add X bit */ | ||
61 | "2:\t" | ||
62 | /* unrolled loop for the main part: do 8 longs at once */ | ||
63 | "movel %1,%3\n\t" /* save len in tmp1 */ | ||
64 | "lsrl #5,%1\n\t" /* len/32 */ | ||
65 | "jeq 2f\n\t" /* not enough... */ | ||
66 | "subql #1,%1\n" | ||
67 | "1:\t" | ||
68 | "movel %2@+,%4\n\t" | ||
69 | "addxl %4,%0\n\t" | ||
70 | "movel %2@+,%4\n\t" | ||
71 | "addxl %4,%0\n\t" | ||
72 | "movel %2@+,%4\n\t" | ||
73 | "addxl %4,%0\n\t" | ||
74 | "movel %2@+,%4\n\t" | ||
75 | "addxl %4,%0\n\t" | ||
76 | "movel %2@+,%4\n\t" | ||
77 | "addxl %4,%0\n\t" | ||
78 | "movel %2@+,%4\n\t" | ||
79 | "addxl %4,%0\n\t" | ||
80 | "movel %2@+,%4\n\t" | ||
81 | "addxl %4,%0\n\t" | ||
82 | "movel %2@+,%4\n\t" | ||
83 | "addxl %4,%0\n\t" | ||
84 | "dbra %1,1b\n\t" | ||
85 | "clrl %4\n\t" | ||
86 | "addxl %4,%0\n\t" /* add X bit */ | ||
87 | "clrw %1\n\t" | ||
88 | "subql #1,%1\n\t" | ||
89 | "jcc 1b\n" | ||
90 | "2:\t" | ||
91 | "movel %3,%1\n\t" /* restore len from tmp1 */ | ||
92 | "andw #0x1c,%3\n\t" /* number of rest longs */ | ||
93 | "jeq 4f\n\t" | ||
94 | "lsrw #2,%3\n\t" | ||
95 | "subqw #1,%3\n" | ||
96 | "3:\t" | ||
97 | /* loop for rest longs */ | ||
98 | "movel %2@+,%4\n\t" | ||
99 | "addxl %4,%0\n\t" | ||
100 | "dbra %3,3b\n\t" | ||
101 | "clrl %4\n\t" | ||
102 | "addxl %4,%0\n" /* add X bit */ | ||
103 | "4:\t" | ||
104 | /* now check for rest bytes that do not fit into longs */ | ||
105 | "andw #3,%1\n\t" | ||
106 | "jeq 7f\n\t" | ||
107 | "clrl %4\n\t" /* clear tmp2 for rest bytes */ | ||
108 | "subqw #2,%1\n\t" | ||
109 | "jlt 5f\n\t" | ||
110 | "movew %2@+,%4\n\t" /* have rest >= 2: get word */ | ||
111 | "swap %4\n\t" /* into bits 16..31 */ | ||
112 | "tstw %1\n\t" /* another byte? */ | ||
113 | "jeq 6f\n" | ||
114 | "5:\t" | ||
115 | "moveb %2@,%4\n\t" /* have odd rest: get byte */ | ||
116 | "lslw #8,%4\n\t" /* into bits 8..15; 16..31 untouched */ | ||
117 | "6:\t" | ||
118 | "addl %4,%0\n\t" /* now add rest long to sum */ | ||
119 | "clrl %4\n\t" | ||
120 | "addxl %4,%0\n" /* add X bit */ | ||
121 | "7:\t" | ||
122 | : "=d" (sum), "=d" (len), "=a" (buff), | ||
123 | "=&d" (tmp1), "=&d" (tmp2) | ||
124 | : "0" (sum), "1" (len), "2" (buff) | ||
125 | ); | ||
126 | return(sum); | ||
127 | } | ||
128 | |||
129 | EXPORT_SYMBOL(csum_partial); | ||
130 | |||
131 | |||
132 | /* | ||
133 | * copy from user space while checksumming, with exception handling. | ||
134 | */ | ||
135 | |||
136 | unsigned int | ||
137 | csum_partial_copy_from_user(const unsigned char *src, unsigned char *dst, | ||
138 | int len, int sum, int *csum_err) | ||
139 | { | ||
140 | /* | ||
141 | * GCC doesn't like more than 10 operands for the asm | ||
142 | * statements so we have to use tmp2 for the error | ||
143 | * code. | ||
144 | */ | ||
145 | unsigned long tmp1, tmp2; | ||
146 | |||
147 | __asm__("movel %2,%4\n\t" | ||
148 | "btst #1,%4\n\t" /* Check alignment */ | ||
149 | "jeq 2f\n\t" | ||
150 | "subql #2,%1\n\t" /* buff%4==2: treat first word */ | ||
151 | "jgt 1f\n\t" | ||
152 | "addql #2,%1\n\t" /* len was == 2, treat only rest */ | ||
153 | "jra 4f\n" | ||
154 | "1:\n" | ||
155 | "10:\t" | ||
156 | "movesw %2@+,%4\n\t" /* add first word to sum */ | ||
157 | "addw %4,%0\n\t" | ||
158 | "movew %4,%3@+\n\t" | ||
159 | "clrl %4\n\t" | ||
160 | "addxl %4,%0\n" /* add X bit */ | ||
161 | "2:\t" | ||
162 | /* unrolled loop for the main part: do 8 longs at once */ | ||
163 | "movel %1,%4\n\t" /* save len in tmp1 */ | ||
164 | "lsrl #5,%1\n\t" /* len/32 */ | ||
165 | "jeq 2f\n\t" /* not enough... */ | ||
166 | "subql #1,%1\n" | ||
167 | "1:\n" | ||
168 | "11:\t" | ||
169 | "movesl %2@+,%5\n\t" | ||
170 | "addxl %5,%0\n\t" | ||
171 | "movel %5,%3@+\n\t" | ||
172 | "12:\t" | ||
173 | "movesl %2@+,%5\n\t" | ||
174 | "addxl %5,%0\n\t" | ||
175 | "movel %5,%3@+\n\t" | ||
176 | "13:\t" | ||
177 | "movesl %2@+,%5\n\t" | ||
178 | "addxl %5,%0\n\t" | ||
179 | "movel %5,%3@+\n\t" | ||
180 | "14:\t" | ||
181 | "movesl %2@+,%5\n\t" | ||
182 | "addxl %5,%0\n\t" | ||
183 | "movel %5,%3@+\n\t" | ||
184 | "15:\t" | ||
185 | "movesl %2@+,%5\n\t" | ||
186 | "addxl %5,%0\n\t" | ||
187 | "movel %5,%3@+\n\t" | ||
188 | "16:\t" | ||
189 | "movesl %2@+,%5\n\t" | ||
190 | "addxl %5,%0\n\t" | ||
191 | "movel %5,%3@+\n\t" | ||
192 | "17:\t" | ||
193 | "movesl %2@+,%5\n\t" | ||
194 | "addxl %5,%0\n\t" | ||
195 | "movel %5,%3@+\n\t" | ||
196 | "18:\t" | ||
197 | "movesl %2@+,%5\n\t" | ||
198 | "addxl %5,%0\n\t" | ||
199 | "movel %5,%3@+\n\t" | ||
200 | "dbra %1,1b\n\t" | ||
201 | "clrl %5\n\t" | ||
202 | "addxl %5,%0\n\t" /* add X bit */ | ||
203 | "clrw %1\n\t" | ||
204 | "subql #1,%1\n\t" | ||
205 | "jcc 1b\n" | ||
206 | "2:\t" | ||
207 | "movel %4,%1\n\t" /* restore len from tmp1 */ | ||
208 | "andw #0x1c,%4\n\t" /* number of rest longs */ | ||
209 | "jeq 4f\n\t" | ||
210 | "lsrw #2,%4\n\t" | ||
211 | "subqw #1,%4\n" | ||
212 | "3:\n" | ||
213 | /* loop for rest longs */ | ||
214 | "19:\t" | ||
215 | "movesl %2@+,%5\n\t" | ||
216 | "addxl %5,%0\n\t" | ||
217 | "movel %5,%3@+\n\t" | ||
218 | "dbra %4,3b\n\t" | ||
219 | "clrl %5\n\t" | ||
220 | "addxl %5,%0\n" /* add X bit */ | ||
221 | "4:\t" | ||
222 | /* now check for rest bytes that do not fit into longs */ | ||
223 | "andw #3,%1\n\t" | ||
224 | "jeq 7f\n\t" | ||
225 | "clrl %5\n\t" /* clear tmp2 for rest bytes */ | ||
226 | "subqw #2,%1\n\t" | ||
227 | "jlt 5f\n\t" | ||
228 | "20:\t" | ||
229 | "movesw %2@+,%5\n\t" /* have rest >= 2: get word */ | ||
230 | "movew %5,%3@+\n\t" | ||
231 | "swap %5\n\t" /* into bits 16..31 */ | ||
232 | "tstw %1\n\t" /* another byte? */ | ||
233 | "jeq 6f\n" | ||
234 | "5:\n" | ||
235 | "21:\t" | ||
236 | "movesb %2@,%5\n\t" /* have odd rest: get byte */ | ||
237 | "moveb %5,%3@+\n\t" | ||
238 | "lslw #8,%5\n\t" /* into bits 8..15; 16..31 untouched */ | ||
239 | "6:\t" | ||
240 | "addl %5,%0\n\t" /* now add rest long to sum */ | ||
241 | "clrl %5\n\t" | ||
242 | "addxl %5,%0\n\t" /* add X bit */ | ||
243 | "7:\t" | ||
244 | "clrl %5\n" /* no error - clear return value */ | ||
245 | "8:\n" | ||
246 | ".section .fixup,\"ax\"\n" | ||
247 | ".even\n" | ||
248 | /* If any exception occurs zero out the rest. | ||
249 | Similarities with the code above are intentional :-) */ | ||
250 | "90:\t" | ||
251 | "clrw %3@+\n\t" | ||
252 | "movel %1,%4\n\t" | ||
253 | "lsrl #5,%1\n\t" | ||
254 | "jeq 1f\n\t" | ||
255 | "subql #1,%1\n" | ||
256 | "91:\t" | ||
257 | "clrl %3@+\n" | ||
258 | "92:\t" | ||
259 | "clrl %3@+\n" | ||
260 | "93:\t" | ||
261 | "clrl %3@+\n" | ||
262 | "94:\t" | ||
263 | "clrl %3@+\n" | ||
264 | "95:\t" | ||
265 | "clrl %3@+\n" | ||
266 | "96:\t" | ||
267 | "clrl %3@+\n" | ||
268 | "97:\t" | ||
269 | "clrl %3@+\n" | ||
270 | "98:\t" | ||
271 | "clrl %3@+\n\t" | ||
272 | "dbra %1,91b\n\t" | ||
273 | "clrw %1\n\t" | ||
274 | "subql #1,%1\n\t" | ||
275 | "jcc 91b\n" | ||
276 | "1:\t" | ||
277 | "movel %4,%1\n\t" | ||
278 | "andw #0x1c,%4\n\t" | ||
279 | "jeq 1f\n\t" | ||
280 | "lsrw #2,%4\n\t" | ||
281 | "subqw #1,%4\n" | ||
282 | "99:\t" | ||
283 | "clrl %3@+\n\t" | ||
284 | "dbra %4,99b\n\t" | ||
285 | "1:\t" | ||
286 | "andw #3,%1\n\t" | ||
287 | "jeq 9f\n" | ||
288 | "100:\t" | ||
289 | "clrw %3@+\n\t" | ||
290 | "tstw %1\n\t" | ||
291 | "jeq 9f\n" | ||
292 | "101:\t" | ||
293 | "clrb %3@+\n" | ||
294 | "9:\t" | ||
295 | #define STR(X) STR1(X) | ||
296 | #define STR1(X) #X | ||
297 | "moveq #-" STR(EFAULT) ",%5\n\t" | ||
298 | "jra 8b\n" | ||
299 | ".previous\n" | ||
300 | ".section __ex_table,\"a\"\n" | ||
301 | ".long 10b,90b\n" | ||
302 | ".long 11b,91b\n" | ||
303 | ".long 12b,92b\n" | ||
304 | ".long 13b,93b\n" | ||
305 | ".long 14b,94b\n" | ||
306 | ".long 15b,95b\n" | ||
307 | ".long 16b,96b\n" | ||
308 | ".long 17b,97b\n" | ||
309 | ".long 18b,98b\n" | ||
310 | ".long 19b,99b\n" | ||
311 | ".long 20b,100b\n" | ||
312 | ".long 21b,101b\n" | ||
313 | ".previous" | ||
314 | : "=d" (sum), "=d" (len), "=a" (src), "=a" (dst), | ||
315 | "=&d" (tmp1), "=d" (tmp2) | ||
316 | : "0" (sum), "1" (len), "2" (src), "3" (dst) | ||
317 | ); | ||
318 | |||
319 | *csum_err = tmp2; | ||
320 | |||
321 | return(sum); | ||
322 | } | ||
323 | |||
324 | /* | ||
325 | * copy from kernel space while checksumming, otherwise like csum_partial | ||
326 | */ | ||
327 | |||
328 | unsigned int | ||
329 | csum_partial_copy_nocheck(const unsigned char *src, unsigned char *dst, int len, int sum) | ||
330 | { | ||
331 | unsigned long tmp1, tmp2; | ||
332 | __asm__("movel %2,%4\n\t" | ||
333 | "btst #1,%4\n\t" /* Check alignment */ | ||
334 | "jeq 2f\n\t" | ||
335 | "subql #2,%1\n\t" /* buff%4==2: treat first word */ | ||
336 | "jgt 1f\n\t" | ||
337 | "addql #2,%1\n\t" /* len was == 2, treat only rest */ | ||
338 | "jra 4f\n" | ||
339 | "1:\t" | ||
340 | "movew %2@+,%4\n\t" /* add first word to sum */ | ||
341 | "addw %4,%0\n\t" | ||
342 | "movew %4,%3@+\n\t" | ||
343 | "clrl %4\n\t" | ||
344 | "addxl %4,%0\n" /* add X bit */ | ||
345 | "2:\t" | ||
346 | /* unrolled loop for the main part: do 8 longs at once */ | ||
347 | "movel %1,%4\n\t" /* save len in tmp1 */ | ||
348 | "lsrl #5,%1\n\t" /* len/32 */ | ||
349 | "jeq 2f\n\t" /* not enough... */ | ||
350 | "subql #1,%1\n" | ||
351 | "1:\t" | ||
352 | "movel %2@+,%5\n\t" | ||
353 | "addxl %5,%0\n\t" | ||
354 | "movel %5,%3@+\n\t" | ||
355 | "movel %2@+,%5\n\t" | ||
356 | "addxl %5,%0\n\t" | ||
357 | "movel %5,%3@+\n\t" | ||
358 | "movel %2@+,%5\n\t" | ||
359 | "addxl %5,%0\n\t" | ||
360 | "movel %5,%3@+\n\t" | ||
361 | "movel %2@+,%5\n\t" | ||
362 | "addxl %5,%0\n\t" | ||
363 | "movel %5,%3@+\n\t" | ||
364 | "movel %2@+,%5\n\t" | ||
365 | "addxl %5,%0\n\t" | ||
366 | "movel %5,%3@+\n\t" | ||
367 | "movel %2@+,%5\n\t" | ||
368 | "addxl %5,%0\n\t" | ||
369 | "movel %5,%3@+\n\t" | ||
370 | "movel %2@+,%5\n\t" | ||
371 | "addxl %5,%0\n\t" | ||
372 | "movel %5,%3@+\n\t" | ||
373 | "movel %2@+,%5\n\t" | ||
374 | "addxl %5,%0\n\t" | ||
375 | "movel %5,%3@+\n\t" | ||
376 | "dbra %1,1b\n\t" | ||
377 | "clrl %5\n\t" | ||
378 | "addxl %5,%0\n\t" /* add X bit */ | ||
379 | "clrw %1\n\t" | ||
380 | "subql #1,%1\n\t" | ||
381 | "jcc 1b\n" | ||
382 | "2:\t" | ||
383 | "movel %4,%1\n\t" /* restore len from tmp1 */ | ||
384 | "andw #0x1c,%4\n\t" /* number of rest longs */ | ||
385 | "jeq 4f\n\t" | ||
386 | "lsrw #2,%4\n\t" | ||
387 | "subqw #1,%4\n" | ||
388 | "3:\t" | ||
389 | /* loop for rest longs */ | ||
390 | "movel %2@+,%5\n\t" | ||
391 | "addxl %5,%0\n\t" | ||
392 | "movel %5,%3@+\n\t" | ||
393 | "dbra %4,3b\n\t" | ||
394 | "clrl %5\n\t" | ||
395 | "addxl %5,%0\n" /* add X bit */ | ||
396 | "4:\t" | ||
397 | /* now check for rest bytes that do not fit into longs */ | ||
398 | "andw #3,%1\n\t" | ||
399 | "jeq 7f\n\t" | ||
400 | "clrl %5\n\t" /* clear tmp2 for rest bytes */ | ||
401 | "subqw #2,%1\n\t" | ||
402 | "jlt 5f\n\t" | ||
403 | "movew %2@+,%5\n\t" /* have rest >= 2: get word */ | ||
404 | "movew %5,%3@+\n\t" | ||
405 | "swap %5\n\t" /* into bits 16..31 */ | ||
406 | "tstw %1\n\t" /* another byte? */ | ||
407 | "jeq 6f\n" | ||
408 | "5:\t" | ||
409 | "moveb %2@,%5\n\t" /* have odd rest: get byte */ | ||
410 | "moveb %5,%3@+\n\t" | ||
411 | "lslw #8,%5\n" /* into bits 8..15; 16..31 untouched */ | ||
412 | "6:\t" | ||
413 | "addl %5,%0\n\t" /* now add rest long to sum */ | ||
414 | "clrl %5\n\t" | ||
415 | "addxl %5,%0\n" /* add X bit */ | ||
416 | "7:\t" | ||
417 | : "=d" (sum), "=d" (len), "=a" (src), "=a" (dst), | ||
418 | "=&d" (tmp1), "=&d" (tmp2) | ||
419 | : "0" (sum), "1" (len), "2" (src), "3" (dst) | ||
420 | ); | ||
421 | return(sum); | ||
422 | } | ||