forked from mirrors/linux
		
	Add unwinder information so oops in the findbit functions can create a proper backtrace. Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
		
			
				
	
	
		
			139 lines
		
	
	
	
		
			3.1 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			139 lines
		
	
	
	
		
			3.1 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
/* SPDX-License-Identifier: GPL-2.0-only */
 | 
						|
/*
 | 
						|
 *  linux/arch/arm/lib/findbit.S
 | 
						|
 *
 | 
						|
 *  Copyright (C) 1995-2000 Russell King
 | 
						|
 *
 | 
						|
 * 16th March 2001 - John Ripley <jripley@sonicblue.com>
 | 
						|
 *   Fixed so that "size" is an exclusive not an inclusive quantity.
 | 
						|
 *   All users of these functions expect exclusive sizes, and may
 | 
						|
 *   also call with zero size.
 | 
						|
 * Reworked by rmk.
 | 
						|
 */
 | 
						|
#include <linux/linkage.h>
 | 
						|
#include <asm/assembler.h>
 | 
						|
#include <asm/unwind.h>
 | 
						|
                .text
 | 
						|
 | 
						|
#ifdef __ARMEB__
 | 
						|
#define SWAB_ENDIAN le
 | 
						|
#else
 | 
						|
#define SWAB_ENDIAN be
 | 
						|
#endif
 | 
						|
 | 
						|
		.macro	find_first, endian, set, name
 | 
						|
ENTRY(_find_first_\name\()bit_\endian)
 | 
						|
	UNWIND(	.fnstart)
 | 
						|
		teq	r1, #0
 | 
						|
		beq	3f
 | 
						|
		mov	r2, #0
 | 
						|
1:		ldr	r3, [r0], #4
 | 
						|
		.ifeq \set
 | 
						|
		mvns	r3, r3			@ invert/test bits
 | 
						|
		.else
 | 
						|
		movs	r3, r3			@ test bits
 | 
						|
		.endif
 | 
						|
		.ifc \endian, SWAB_ENDIAN
 | 
						|
		bne	.L_found_swab
 | 
						|
		.else
 | 
						|
		bne	.L_found		@ found the bit?
 | 
						|
		.endif
 | 
						|
		add	r2, r2, #32		@ next index
 | 
						|
2:		cmp	r2, r1			@ any more?
 | 
						|
		blo	1b
 | 
						|
3:		mov	r0, r1			@ no more bits
 | 
						|
		ret	lr
 | 
						|
	UNWIND(	.fnend)
 | 
						|
ENDPROC(_find_first_\name\()bit_\endian)
 | 
						|
		.endm
 | 
						|
 | 
						|
		.macro	find_next, endian, set, name
 | 
						|
ENTRY(_find_next_\name\()bit_\endian)
 | 
						|
	UNWIND(	.fnstart)
 | 
						|
		cmp	r2, r1
 | 
						|
		bhs	3b
 | 
						|
		mov	ip, r2, lsr #5		@ word index
 | 
						|
		add	r0, r0, ip, lsl #2
 | 
						|
		ands	ip, r2, #31		@ bit position
 | 
						|
		beq	1b
 | 
						|
		ldr	r3, [r0], #4
 | 
						|
		.ifeq \set
 | 
						|
		mvn	r3, r3			@ invert bits
 | 
						|
		.endif
 | 
						|
		.ifc \endian, SWAB_ENDIAN
 | 
						|
		rev_l	r3, ip
 | 
						|
		.if	.Lrev_l_uses_tmp
 | 
						|
		@ we need to recompute ip because rev_l will have overwritten
 | 
						|
		@ it.
 | 
						|
		and	ip, r2, #31		@ bit position
 | 
						|
		.endif
 | 
						|
		.endif
 | 
						|
		movs	r3, r3, lsr ip		@ shift off unused bits
 | 
						|
		bne	.L_found
 | 
						|
		orr	r2, r2, #31		@ no zero bits
 | 
						|
		add	r2, r2, #1		@ align bit pointer
 | 
						|
		b	2b			@ loop for next bit
 | 
						|
	UNWIND(	.fnend)
 | 
						|
ENDPROC(_find_next_\name\()bit_\endian)
 | 
						|
		.endm
 | 
						|
 | 
						|
		.macro	find_bit, endian, set, name
 | 
						|
		find_first \endian, \set, \name
 | 
						|
		find_next  \endian, \set, \name
 | 
						|
		.endm
 | 
						|
 | 
						|
/* _find_first_zero_bit_le and _find_next_zero_bit_le */
 | 
						|
		find_bit le, 0, zero_
 | 
						|
 | 
						|
/* _find_first_bit_le and _find_next_bit_le */
 | 
						|
		find_bit le, 1
 | 
						|
 | 
						|
#ifdef __ARMEB__
 | 
						|
 | 
						|
/* _find_first_zero_bit_be and _find_next_zero_bit_be */
 | 
						|
		find_bit be, 0, zero_
 | 
						|
 | 
						|
/* _find_first_bit_be and _find_next_bit_be */
 | 
						|
		find_bit be, 1
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
/*
 | 
						|
 * One or more bits in the LSB of r3 are assumed to be set.
 | 
						|
 */
 | 
						|
.L_found_swab:
 | 
						|
	UNWIND(	.fnstart)
 | 
						|
		rev_l	r3, ip
 | 
						|
.L_found:
 | 
						|
#if __LINUX_ARM_ARCH__ >= 7
 | 
						|
		rbit	r3, r3			@ reverse bits
 | 
						|
		clz	r3, r3			@ count high zero bits
 | 
						|
		add	r0, r2, r3		@ add offset of first set bit
 | 
						|
#elif __LINUX_ARM_ARCH__ >= 5
 | 
						|
		rsb	r0, r3, #0
 | 
						|
		and	r3, r3, r0		@ mask out lowest bit set
 | 
						|
		clz	r3, r3			@ count high zero bits
 | 
						|
		rsb	r3, r3, #31		@ offset of first set bit
 | 
						|
		add	r0, r2, r3		@ add offset of first set bit
 | 
						|
#else
 | 
						|
		mov	ip, #~0
 | 
						|
		tst	r3, ip, lsr #16		@ test bits 0-15
 | 
						|
		addeq	r2, r2, #16
 | 
						|
		moveq	r3, r3, lsr #16
 | 
						|
		tst	r3, #0x00ff
 | 
						|
		addeq	r2, r2, #8
 | 
						|
		moveq	r3, r3, lsr #8
 | 
						|
		tst	r3, #0x000f
 | 
						|
		addeq	r2, r2, #4
 | 
						|
		moveq	r3, r3, lsr #4
 | 
						|
		tst	r3, #0x0003
 | 
						|
		addeq	r2, r2, #2
 | 
						|
		moveq	r3, r3, lsr #2
 | 
						|
		tst	r3, #0x0001
 | 
						|
		addeq	r2, r2, #1
 | 
						|
		mov	r0, r2
 | 
						|
#endif
 | 
						|
		cmp	r1, r0			@ Clamp to maxbit
 | 
						|
		movlo	r0, r1
 | 
						|
		ret	lr
 | 
						|
	UNWIND(	.fnend)
 |