pandora: defconfig: update
[pandora-kernel.git] / arch / x86 / lib / checksum_32.S
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  *              Pentium Pro/II routines:
12  *              Alexander Kjeldaas <astor@guardian.no>
13  *              Finn Arne Gangstad <finnag@guardian.no>
14  *              Lots of code moved from tcp.c and ip.c; see those files
15  *              for more names.
16  *
17  * Changes:     Ingo Molnar, converted csum_partial_copy() to 2.1 exception
18  *                           handling.
19  *              Andi Kleen,  add zeroing on error
20  *                   converted to pure assembler
21  *
22  *              This program is free software; you can redistribute it and/or
23  *              modify it under the terms of the GNU General Public License
24  *              as published by the Free Software Foundation; either version
25  *              2 of the License, or (at your option) any later version.
26  */
27
28 #include <linux/linkage.h>
29 #include <asm/dwarf2.h>
30 #include <asm/errno.h>
31 #include <asm/nospec-branch.h>
32
33 /*
34  * computes a partial checksum, e.g. for TCP/UDP fragments
35  */
36
37 /*      
38 unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
39  */
40                 
41 .text
42                 
43 #ifndef CONFIG_X86_USE_PPRO_CHECKSUM
44
45           /*            
46            * Experiments with Ethernet and SLIP connections show that buff
47            * is aligned on either a 2-byte or 4-byte boundary.  We get at
48            * least a twofold speedup on 486 and Pentium if it is 4-byte aligned.
49            * Fortunately, it is easy to convert 2-byte alignment to 4-byte
50            * alignment for the unrolled loop.
51            */           
52 ENTRY(csum_partial)
53         CFI_STARTPROC
54         pushl_cfi %esi
55         CFI_REL_OFFSET esi, 0
56         pushl_cfi %ebx
57         CFI_REL_OFFSET ebx, 0
58         movl 20(%esp),%eax      # Function arg: unsigned int sum
59         movl 16(%esp),%ecx      # Function arg: int len
60         movl 12(%esp),%esi      # Function arg: unsigned char *buff
61         testl $3, %esi          # Check alignment.
62         jz 2f                   # Jump if alignment is ok.
63         testl $1, %esi          # Check alignment.
64         jz 10f                  # Jump if alignment is boundary of 2bytes.
65
66         # buf is odd
67         dec %ecx
68         jl 8f
69         movzbl (%esi), %ebx
70         adcl %ebx, %eax
71         roll $8, %eax
72         inc %esi
73         testl $2, %esi
74         jz 2f
75 10:
76         subl $2, %ecx           # Alignment uses up two bytes.
77         jae 1f                  # Jump if we had at least two bytes.
78         addl $2, %ecx           # ecx was < 2.  Deal with it.
79         jmp 4f
80 1:      movw (%esi), %bx
81         addl $2, %esi
82         addw %bx, %ax
83         adcl $0, %eax
84 2:
85         movl %ecx, %edx
86         shrl $5, %ecx
87         jz 2f
88         testl %esi, %esi
89 1:      movl (%esi), %ebx
90         adcl %ebx, %eax
91         movl 4(%esi), %ebx
92         adcl %ebx, %eax
93         movl 8(%esi), %ebx
94         adcl %ebx, %eax
95         movl 12(%esi), %ebx
96         adcl %ebx, %eax
97         movl 16(%esi), %ebx
98         adcl %ebx, %eax
99         movl 20(%esi), %ebx
100         adcl %ebx, %eax
101         movl 24(%esi), %ebx
102         adcl %ebx, %eax
103         movl 28(%esi), %ebx
104         adcl %ebx, %eax
105         lea 32(%esi), %esi
106         dec %ecx
107         jne 1b
108         adcl $0, %eax
109 2:      movl %edx, %ecx
110         andl $0x1c, %edx
111         je 4f
112         shrl $2, %edx           # This clears CF
113 3:      adcl (%esi), %eax
114         lea 4(%esi), %esi
115         dec %edx
116         jne 3b
117         adcl $0, %eax
118 4:      andl $3, %ecx
119         jz 7f
120         cmpl $2, %ecx
121         jb 5f
122         movw (%esi),%cx
123         leal 2(%esi),%esi
124         je 6f
125         shll $16,%ecx
126 5:      movb (%esi),%cl
127 6:      addl %ecx,%eax
128         adcl $0, %eax 
129 7:      
130         testl $1, 12(%esp)
131         jz 8f
132         roll $8, %eax
133 8:
134         popl_cfi %ebx
135         CFI_RESTORE ebx
136         popl_cfi %esi
137         CFI_RESTORE esi
138         ret
139         CFI_ENDPROC
140 ENDPROC(csum_partial)
141
142 #else
143
144 /* Version for PentiumII/PPro */
145
146 ENTRY(csum_partial)
147         CFI_STARTPROC
148         pushl_cfi %esi
149         CFI_REL_OFFSET esi, 0
150         pushl_cfi %ebx
151         CFI_REL_OFFSET ebx, 0
152         movl 20(%esp),%eax      # Function arg: unsigned int sum
153         movl 16(%esp),%ecx      # Function arg: int len
154         movl 12(%esp),%esi      # Function arg: const unsigned char *buf
155
156         testl $3, %esi         
157         jnz 25f                 
158 10:
159         movl %ecx, %edx
160         movl %ecx, %ebx
161         andl $0x7c, %ebx
162         shrl $7, %ecx
163         addl %ebx,%esi
164         shrl $2, %ebx  
165         negl %ebx
166         lea 45f(%ebx,%ebx,2), %ebx
167         testl %esi, %esi
168         JMP_NOSPEC %ebx
169
170         # Handle 2-byte-aligned regions
171 20:     addw (%esi), %ax
172         lea 2(%esi), %esi
173         adcl $0, %eax
174         jmp 10b
175 25:
176         testl $1, %esi         
177         jz 30f                 
178         # buf is odd
179         dec %ecx
180         jl 90f
181         movzbl (%esi), %ebx
182         addl %ebx, %eax
183         adcl $0, %eax
184         roll $8, %eax
185         inc %esi
186         testl $2, %esi
187         jz 10b
188
189 30:     subl $2, %ecx          
190         ja 20b                 
191         je 32f
192         addl $2, %ecx
193         jz 80f
194         movzbl (%esi),%ebx      # csumming 1 byte, 2-aligned
195         addl %ebx, %eax
196         adcl $0, %eax
197         jmp 80f
198 32:
199         addw (%esi), %ax        # csumming 2 bytes, 2-aligned
200         adcl $0, %eax
201         jmp 80f
202
203 40: 
204         addl -128(%esi), %eax
205         adcl -124(%esi), %eax
206         adcl -120(%esi), %eax
207         adcl -116(%esi), %eax   
208         adcl -112(%esi), %eax   
209         adcl -108(%esi), %eax
210         adcl -104(%esi), %eax
211         adcl -100(%esi), %eax
212         adcl -96(%esi), %eax
213         adcl -92(%esi), %eax
214         adcl -88(%esi), %eax
215         adcl -84(%esi), %eax
216         adcl -80(%esi), %eax
217         adcl -76(%esi), %eax
218         adcl -72(%esi), %eax
219         adcl -68(%esi), %eax
220         adcl -64(%esi), %eax     
221         adcl -60(%esi), %eax     
222         adcl -56(%esi), %eax     
223         adcl -52(%esi), %eax   
224         adcl -48(%esi), %eax   
225         adcl -44(%esi), %eax
226         adcl -40(%esi), %eax
227         adcl -36(%esi), %eax
228         adcl -32(%esi), %eax
229         adcl -28(%esi), %eax
230         adcl -24(%esi), %eax
231         adcl -20(%esi), %eax
232         adcl -16(%esi), %eax
233         adcl -12(%esi), %eax
234         adcl -8(%esi), %eax
235         adcl -4(%esi), %eax
236 45:
237         lea 128(%esi), %esi
238         adcl $0, %eax
239         dec %ecx
240         jge 40b
241         movl %edx, %ecx
242 50:     andl $3, %ecx
243         jz 80f
244
245         # Handle the last 1-3 bytes without jumping
246         notl %ecx               # 1->2, 2->1, 3->0, higher bits are masked
247         movl $0xffffff,%ebx     # by the shll and shrl instructions
248         shll $3,%ecx
249         shrl %cl,%ebx
250         andl -128(%esi),%ebx    # esi is 4-aligned so should be ok
251         addl %ebx,%eax
252         adcl $0,%eax
253 80: 
254         testl $1, 12(%esp)
255         jz 90f
256         roll $8, %eax
257 90: 
258         popl_cfi %ebx
259         CFI_RESTORE ebx
260         popl_cfi %esi
261         CFI_RESTORE esi
262         ret
263         CFI_ENDPROC
264 ENDPROC(csum_partial)
265                                 
266 #endif
267
268 /*
269 unsigned int csum_partial_copy_generic (const char *src, char *dst,
270                                   int len, int sum, int *src_err_ptr, int *dst_err_ptr)
271  */ 
272
273 /*
274  * Copy from ds while checksumming, otherwise like csum_partial
275  *
276  * The macros SRC and DST specify the type of access for the instruction.
277  * thus we can call a custom exception handler for all access types.
278  *
279  * FIXME: could someone double-check whether I haven't mixed up some SRC and
280  *        DST definitions? It's damn hard to trigger all cases.  I hope I got
281  *        them all but there's no guarantee.
282  */
283
284 #define SRC(y...)                       \
285         9999: y;                        \
286         .section __ex_table, "a";       \
287         .long 9999b, 6001f      ;       \
288         .previous
289
290 #define DST(y...)                       \
291         9999: y;                        \
292         .section __ex_table, "a";       \
293         .long 9999b, 6002f      ;       \
294         .previous
295
296 #ifndef CONFIG_X86_USE_PPRO_CHECKSUM
297
298 #define ARGBASE 16              
299 #define FP              12
300                 
301 ENTRY(csum_partial_copy_generic)
302         CFI_STARTPROC
303         subl  $4,%esp   
304         CFI_ADJUST_CFA_OFFSET 4
305         pushl_cfi %edi
306         CFI_REL_OFFSET edi, 0
307         pushl_cfi %esi
308         CFI_REL_OFFSET esi, 0
309         pushl_cfi %ebx
310         CFI_REL_OFFSET ebx, 0
311         movl ARGBASE+16(%esp),%eax      # sum
312         movl ARGBASE+12(%esp),%ecx      # len
313         movl ARGBASE+4(%esp),%esi       # src
314         movl ARGBASE+8(%esp),%edi       # dst
315
316         testl $2, %edi                  # Check alignment. 
317         jz 2f                           # Jump if alignment is ok.
318         subl $2, %ecx                   # Alignment uses up two bytes.
319         jae 1f                          # Jump if we had at least two bytes.
320         addl $2, %ecx                   # ecx was < 2.  Deal with it.
321         jmp 4f
322 SRC(1:  movw (%esi), %bx        )
323         addl $2, %esi
324 DST(    movw %bx, (%edi)        )
325         addl $2, %edi
326         addw %bx, %ax   
327         adcl $0, %eax
328 2:
329         movl %ecx, FP(%esp)
330         shrl $5, %ecx
331         jz 2f
332         testl %esi, %esi
333 SRC(1:  movl (%esi), %ebx       )
334 SRC(    movl 4(%esi), %edx      )
335         adcl %ebx, %eax
336 DST(    movl %ebx, (%edi)       )
337         adcl %edx, %eax
338 DST(    movl %edx, 4(%edi)      )
339
340 SRC(    movl 8(%esi), %ebx      )
341 SRC(    movl 12(%esi), %edx     )
342         adcl %ebx, %eax
343 DST(    movl %ebx, 8(%edi)      )
344         adcl %edx, %eax
345 DST(    movl %edx, 12(%edi)     )
346
347 SRC(    movl 16(%esi), %ebx     )
348 SRC(    movl 20(%esi), %edx     )
349         adcl %ebx, %eax
350 DST(    movl %ebx, 16(%edi)     )
351         adcl %edx, %eax
352 DST(    movl %edx, 20(%edi)     )
353
354 SRC(    movl 24(%esi), %ebx     )
355 SRC(    movl 28(%esi), %edx     )
356         adcl %ebx, %eax
357 DST(    movl %ebx, 24(%edi)     )
358         adcl %edx, %eax
359 DST(    movl %edx, 28(%edi)     )
360
361         lea 32(%esi), %esi
362         lea 32(%edi), %edi
363         dec %ecx
364         jne 1b
365         adcl $0, %eax
366 2:      movl FP(%esp), %edx
367         movl %edx, %ecx
368         andl $0x1c, %edx
369         je 4f
370         shrl $2, %edx                   # This clears CF
371 SRC(3:  movl (%esi), %ebx       )
372         adcl %ebx, %eax
373 DST(    movl %ebx, (%edi)       )
374         lea 4(%esi), %esi
375         lea 4(%edi), %edi
376         dec %edx
377         jne 3b
378         adcl $0, %eax
379 4:      andl $3, %ecx
380         jz 7f
381         cmpl $2, %ecx
382         jb 5f
383 SRC(    movw (%esi), %cx        )
384         leal 2(%esi), %esi
385 DST(    movw %cx, (%edi)        )
386         leal 2(%edi), %edi
387         je 6f
388         shll $16,%ecx
389 SRC(5:  movb (%esi), %cl        )
390 DST(    movb %cl, (%edi)        )
391 6:      addl %ecx, %eax
392         adcl $0, %eax
393 7:
394 5000:
395
396 # Exception handler:
397 .section .fixup, "ax"                                                   
398
399 6001:
400         movl ARGBASE+20(%esp), %ebx     # src_err_ptr
401         movl $-EFAULT, (%ebx)
402
403         # zero the complete destination - computing the rest
404         # is too much work 
405         movl ARGBASE+8(%esp), %edi      # dst
406         movl ARGBASE+12(%esp), %ecx     # len
407         xorl %eax,%eax
408         rep ; stosb
409
410         jmp 5000b
411
412 6002:
413         movl ARGBASE+24(%esp), %ebx     # dst_err_ptr
414         movl $-EFAULT,(%ebx)
415         jmp 5000b
416
417 .previous
418
419         popl_cfi %ebx
420         CFI_RESTORE ebx
421         popl_cfi %esi
422         CFI_RESTORE esi
423         popl_cfi %edi
424         CFI_RESTORE edi
425         popl_cfi %ecx                   # equivalent to addl $4,%esp
426         ret     
427         CFI_ENDPROC
428 ENDPROC(csum_partial_copy_generic)
429
430 #else
431
432 /* Version for PentiumII/PPro */
433
434 #define ROUND1(x) \
435         SRC(movl x(%esi), %ebx  )       ;       \
436         addl %ebx, %eax                 ;       \
437         DST(movl %ebx, x(%edi)  )       ; 
438
439 #define ROUND(x) \
440         SRC(movl x(%esi), %ebx  )       ;       \
441         adcl %ebx, %eax                 ;       \
442         DST(movl %ebx, x(%edi)  )       ;
443
444 #define ARGBASE 12
445                 
446 ENTRY(csum_partial_copy_generic)
447         CFI_STARTPROC
448         pushl_cfi %ebx
449         CFI_REL_OFFSET ebx, 0
450         pushl_cfi %edi
451         CFI_REL_OFFSET edi, 0
452         pushl_cfi %esi
453         CFI_REL_OFFSET esi, 0
454         movl ARGBASE+4(%esp),%esi       #src
455         movl ARGBASE+8(%esp),%edi       #dst    
456         movl ARGBASE+12(%esp),%ecx      #len
457         movl ARGBASE+16(%esp),%eax      #sum
458 #       movl %ecx, %edx  
459         movl %ecx, %ebx  
460         movl %esi, %edx
461         shrl $6, %ecx     
462         andl $0x3c, %ebx  
463         negl %ebx
464         subl %ebx, %esi  
465         subl %ebx, %edi  
466         lea  -1(%esi),%edx
467         andl $-32,%edx
468         lea 3f(%ebx,%ebx), %ebx
469         testl %esi, %esi 
470         JMP_NOSPEC %ebx
471 1:      addl $64,%esi
472         addl $64,%edi 
473         SRC(movb -32(%edx),%bl) ; SRC(movb (%edx),%bl)
474         ROUND1(-64) ROUND(-60) ROUND(-56) ROUND(-52)    
475         ROUND (-48) ROUND(-44) ROUND(-40) ROUND(-36)    
476         ROUND (-32) ROUND(-28) ROUND(-24) ROUND(-20)    
477         ROUND (-16) ROUND(-12) ROUND(-8)  ROUND(-4)     
478 3:      adcl $0,%eax
479         addl $64, %edx
480         dec %ecx
481         jge 1b
482 4:      movl ARGBASE+12(%esp),%edx      #len
483         andl $3, %edx
484         jz 7f
485         cmpl $2, %edx
486         jb 5f
487 SRC(    movw (%esi), %dx         )
488         leal 2(%esi), %esi
489 DST(    movw %dx, (%edi)         )
490         leal 2(%edi), %edi
491         je 6f
492         shll $16,%edx
493 5:
494 SRC(    movb (%esi), %dl         )
495 DST(    movb %dl, (%edi)         )
496 6:      addl %edx, %eax
497         adcl $0, %eax
498 7:
499 .section .fixup, "ax"
500 6001:   movl    ARGBASE+20(%esp), %ebx  # src_err_ptr   
501         movl $-EFAULT, (%ebx)
502         # zero the complete destination (computing the rest is too much work)
503         movl ARGBASE+8(%esp),%edi       # dst
504         movl ARGBASE+12(%esp),%ecx      # len
505         xorl %eax,%eax
506         rep; stosb
507         jmp 7b
508 6002:   movl ARGBASE+24(%esp), %ebx     # dst_err_ptr
509         movl $-EFAULT, (%ebx)
510         jmp  7b                 
511 .previous                               
512
513         popl_cfi %esi
514         CFI_RESTORE esi
515         popl_cfi %edi
516         CFI_RESTORE edi
517         popl_cfi %ebx
518         CFI_RESTORE ebx
519         ret
520         CFI_ENDPROC
521 ENDPROC(csum_partial_copy_generic)
522                                 
523 #undef ROUND
524 #undef ROUND1           
525                 
526 #endif