| /* | 
 |  * 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 |