/* * arch/alpha/lib/ev67-strlen_user.S * 21264 version contributed by Rick Gorton <rick.gorton@api-networks.com> * * Return the length of the string including the NULL 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. * * Much of the information about 21264 scheduling/coding comes from: * Compiler Writer's Guide for the Alpha 21264 * abbreviated as 'CWG' in other comments here * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html * Scheduling notation: * E - either cluster * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 * Try not to change the actual algorithm if possible for consistency. */ #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 4 __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 nop nop nop .globl __strnlen_user .align 4 __strnlen_user: .prologue 0 EX( ldq_u t0, 0(a0) ) # L : load first quadword (a0 may be misaligned) lda t1, -1(zero) # E : insqh t1, a0, t1 # U : andnot a0, 7, v0 # E : or t1, t0, t0 # E : subq a0, 1, a0 # E : get our +1 for the return cmpbge zero, t0, t1 # E : t1 <- bitmask: bit i == 1 <==> i-th byte == 0 subq a1, 7, t2 # E : subq a0, v0, t0 # E : bne t1, $found # U : addq t2, t0, t2 # E : addq a1, 1, a1 # E : nop # E : nop # E : .align 4 $loop: ble t2, $limit # U : EX( ldq t0, 8(v0) ) # L : nop # E : nop # E : cmpbge zero, t0, t1 # E : subq t2, 8, t2 # E : addq v0, 8, v0 # E : addr += 8 beq t1, $loop # U : $found: cttz t1, t2 # U0 : addq v0, t2, v0 # E : subq v0, a0, v0 # E : ret # L0 : $exception: nop nop nop ret .align 4 # currently redundant $limit: nop nop subq a1, t2, v0 ret .end __strlen_user