Merge branch 'upstream' of git://lost.foo-projects.org/~ahkok/git/netdev-2.6 into...
[linux-2.6] / arch / alpha / lib / ev67-strlen_user.S
1 /*
2  * arch/alpha/lib/ev67-strlen_user.S
3  * 21264 version contributed by Rick Gorton <rick.gorton@api-networks.com>
4  *
5  * Return the length of the string including the NULL terminator
6  * (strlen+1) or zero if an error occurred.
7  *
8  * In places where it is critical to limit the processing time,
9  * and the data is not trusted, strnlen_user() should be used.
10  * It will return a value greater than its second argument if
11  * that limit would be exceeded. This implementation is allowed
12  * to access memory beyond the limit, but will not cross a page
13  * boundary when doing so.
14  *
15  * Much of the information about 21264 scheduling/coding comes from:
16  *      Compiler Writer's Guide for the Alpha 21264
17  *      abbreviated as 'CWG' in other comments here
18  *      ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html
19  * Scheduling notation:
20  *      E       - either cluster
21  *      U       - upper subcluster; U0 - subcluster U0; U1 - subcluster U1
22  *      L       - lower subcluster; L0 - subcluster L0; L1 - subcluster L1
23  * Try not to change the actual algorithm if possible for consistency.
24  */
25
26 #include <asm/regdef.h>
27
28
29 /* Allow an exception for an insn; exit if we get one.  */
30 #define EX(x,y...)                      \
31         99: x,##y;                      \
32         .section __ex_table,"a";        \
33         .long 99b - .;                  \
34         lda v0, $exception-99b(zero);   \
35         .previous
36
37
38         .set noreorder
39         .set noat
40         .text
41
42         .globl __strlen_user
43         .ent __strlen_user
44         .frame sp, 0, ra
45
46         .align 4
47 __strlen_user:
48         ldah    a1, 32767(zero) # do not use plain strlen_user() for strings
49                                 # that might be almost 2 GB long; you should
50                                 # be using strnlen_user() instead
51         nop
52         nop
53         nop
54
55         .globl __strnlen_user
56
57         .align 4
58 __strnlen_user:
59         .prologue 0
60         EX( ldq_u t0, 0(a0) )   # L : load first quadword (a0 may be misaligned)
61         lda     t1, -1(zero)    # E :
62
63         insqh   t1, a0, t1      # U :
64         andnot  a0, 7, v0       # E :
65         or      t1, t0, t0      # E :
66         subq    a0, 1, a0       # E : get our +1 for the return 
67
68         cmpbge  zero, t0, t1    # E : t1 <- bitmask: bit i == 1 <==> i-th byte == 0
69         subq    a1, 7, t2       # E :
70         subq    a0, v0, t0      # E :
71         bne     t1, $found      # U :
72
73         addq    t2, t0, t2      # E :
74         addq    a1, 1, a1       # E :
75         nop                     # E :
76         nop                     # E :
77
78         .align 4
79 $loop:  ble     t2, $limit      # U :
80         EX( ldq t0, 8(v0) )     # L :
81         nop                     # E :
82         nop                     # E :
83
84         cmpbge  zero, t0, t1    # E :
85         subq    t2, 8, t2       # E :
86         addq    v0, 8, v0       # E : addr += 8
87         beq     t1, $loop       # U :
88
89 $found: cttz    t1, t2          # U0 :
90         addq    v0, t2, v0      # E :
91         subq    v0, a0, v0      # E :
92         ret                     # L0 :
93
94 $exception:
95         nop
96         nop
97         nop
98         ret
99
100         .align 4                # currently redundant
101 $limit:
102         nop
103         nop
104         subq    a1, t2, v0
105         ret
106
107         .end __strlen_user