| /* | |
| * arch/alpha/lib/strlen_user.S | |
| * | |
| * Return the length of the string including the NUL terminator | |
| * (strlen+1) or zero if an error occurred. | |
| * | |
| * In places where it is critical to limit the processing time, | |
| * and the data is not trusted, strnlen_user() should be used. | |
| * It will return a value greater than its second argument if | |
| * that limit would be exceeded. This implementation is allowed | |
| * to access memory beyond the limit, but will not cross a page | |
| * boundary when doing so. | |
| */ | |
| #include <asm/regdef.h> | |
| /* Allow an exception for an insn; exit if we get one. */ | |
| #define EX(x,y...) \ | |
| 99: x,##y; \ | |
| .section __ex_table,"a"; \ | |
| .long 99b - .; \ | |
| lda v0, $exception-99b(zero); \ | |
| .previous | |
| .set noreorder | |
| .set noat | |
| .text | |
| .globl __strlen_user | |
| .ent __strlen_user | |
| .frame sp, 0, ra | |
| .align 3 | |
| __strlen_user: | |
| ldah a1, 32767(zero) # do not use plain strlen_user() for strings | |
| # that might be almost 2 GB long; you should | |
| # be using strnlen_user() instead | |
| .globl __strnlen_user | |
| .align 3 | |
| __strnlen_user: | |
| .prologue 0 | |
| EX( ldq_u t0, 0(a0) ) # load first quadword (a0 may be misaligned) | |
| lda t1, -1(zero) | |
| insqh t1, a0, t1 | |
| andnot a0, 7, v0 | |
| or t1, t0, t0 | |
| subq a0, 1, a0 # get our +1 for the return | |
| cmpbge zero, t0, t1 # t1 <- bitmask: bit i == 1 <==> i-th byte == 0 | |
| subq a1, 7, t2 | |
| subq a0, v0, t0 | |
| bne t1, $found | |
| addq t2, t0, t2 | |
| addq a1, 1, a1 | |
| .align 3 | |
| $loop: ble t2, $limit | |
| EX( ldq t0, 8(v0) ) | |
| subq t2, 8, t2 | |
| addq v0, 8, v0 # addr += 8 | |
| cmpbge zero, t0, t1 | |
| beq t1, $loop | |
| $found: negq t1, t2 # clear all but least set bit | |
| and t1, t2, t1 | |
| and t1, 0xf0, t2 # binary search for that set bit | |
| and t1, 0xcc, t3 | |
| and t1, 0xaa, t4 | |
| cmovne t2, 4, t2 | |
| cmovne t3, 2, t3 | |
| cmovne t4, 1, t4 | |
| addq t2, t3, t2 | |
| addq v0, t4, v0 | |
| addq v0, t2, v0 | |
| nop # dual issue next two on ev4 and ev5 | |
| subq v0, a0, v0 | |
| $exception: | |
| ret | |
| .align 3 # currently redundant | |
| $limit: | |
| subq a1, t2, v0 | |
| ret | |
| .end __strlen_user |