Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * arch/alpha/lib/strlen_user.S | |
3 | * | |
4 | * Return the length of the string including the NUL terminator | |
5 | * (strlen+1) or zero if an error occurred. | |
6 | * | |
7 | * In places where it is critical to limit the processing time, | |
8 | * and the data is not trusted, strnlen_user() should be used. | |
9 | * It will return a value greater than its second argument if | |
10 | * that limit would be exceeded. This implementation is allowed | |
11 | * to access memory beyond the limit, but will not cross a page | |
12 | * boundary when doing so. | |
13 | */ | |
14 | ||
15 | #include <asm/regdef.h> | |
16 | ||
17 | ||
18 | /* Allow an exception for an insn; exit if we get one. */ | |
19 | #define EX(x,y...) \ | |
20 | 99: x,##y; \ | |
21 | .section __ex_table,"a"; \ | |
22 | .long 99b - .; \ | |
23 | lda v0, $exception-99b(zero); \ | |
24 | .previous | |
25 | ||
26 | ||
27 | .set noreorder | |
28 | .set noat | |
29 | .text | |
30 | ||
31 | .globl __strlen_user | |
32 | .ent __strlen_user | |
33 | .frame sp, 0, ra | |
34 | ||
35 | .align 3 | |
36 | __strlen_user: | |
37 | ldah a1, 32767(zero) # do not use plain strlen_user() for strings | |
38 | # that might be almost 2 GB long; you should | |
39 | # be using strnlen_user() instead | |
40 | ||
41 | .globl __strnlen_user | |
42 | ||
43 | .align 3 | |
44 | __strnlen_user: | |
45 | .prologue 0 | |
46 | ||
47 | EX( ldq_u t0, 0(a0) ) # load first quadword (a0 may be misaligned) | |
48 | lda t1, -1(zero) | |
49 | insqh t1, a0, t1 | |
50 | andnot a0, 7, v0 | |
51 | or t1, t0, t0 | |
52 | subq a0, 1, a0 # get our +1 for the return | |
53 | cmpbge zero, t0, t1 # t1 <- bitmask: bit i == 1 <==> i-th byte == 0 | |
54 | subq a1, 7, t2 | |
55 | subq a0, v0, t0 | |
56 | bne t1, $found | |
57 | ||
58 | addq t2, t0, t2 | |
59 | addq a1, 1, a1 | |
60 | ||
61 | .align 3 | |
62 | $loop: ble t2, $limit | |
63 | EX( ldq t0, 8(v0) ) | |
64 | subq t2, 8, t2 | |
65 | addq v0, 8, v0 # addr += 8 | |
66 | cmpbge zero, t0, t1 | |
67 | beq t1, $loop | |
68 | ||
69 | $found: negq t1, t2 # clear all but least set bit | |
70 | and t1, t2, t1 | |
71 | ||
72 | and t1, 0xf0, t2 # binary search for that set bit | |
73 | and t1, 0xcc, t3 | |
74 | and t1, 0xaa, t4 | |
75 | cmovne t2, 4, t2 | |
76 | cmovne t3, 2, t3 | |
77 | cmovne t4, 1, t4 | |
78 | addq t2, t3, t2 | |
79 | addq v0, t4, v0 | |
80 | addq v0, t2, v0 | |
81 | nop # dual issue next two on ev4 and ev5 | |
82 | subq v0, a0, v0 | |
83 | $exception: | |
84 | ret | |
85 | ||
86 | .align 3 # currently redundant | |
87 | $limit: | |
88 | subq a1, t2, v0 | |
89 | ret | |
90 | ||
91 | .end __strlen_user |