323 lines · 7.4 KB · Assembly
RawDownload
/* * This file is subject to the terms and conditions of the GNU General Public * License.  See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 1998, 1999, 2000 by Ralf Baechle * Copyright (C) 1999, 2000 Silicon Graphics, Inc. * Copyright (C) 2007 by Maciej W. Rozycki * Copyright (C) 2011, 2012 MIPS Technologies, Inc. */#include <linux/export.h>#include <asm/asm.h>#include <asm/asm-offsets.h>#include <asm/regdef.h> #if LONGSIZE == 4#define LONG_S_L swl#define LONG_S_R swr#else#define LONG_S_L sdl#define LONG_S_R sdr#endif #ifdef CONFIG_CPU_MICROMIPS#define STORSIZE (LONGSIZE * 2)#define STORMASK (STORSIZE - 1)#define FILL64RG t8#define FILLPTRG t7#undef  LONG_S#define LONG_S LONG_SP#else#define STORSIZE LONGSIZE#define STORMASK LONGMASK#define FILL64RG a1#define FILLPTRG t0#endif #define LEGACY_MODE 1#define EVA_MODE    2 /* * No need to protect it with EVA #ifdefery. The generated block of code * will never be assembled if EVA is not enabled. */#define __EVAFY(insn, reg, addr) __BUILD_EVA_INSN(insn##e, reg, addr)#define ___BUILD_EVA_INSN(insn, reg, addr) __EVAFY(insn, reg, addr) #define EX(insn,reg,addr,handler)			\	.if \mode == LEGACY_MODE;			\9:		insn	reg, addr;			\	.else;						\9:		___BUILD_EVA_INSN(insn, reg, addr);	\	.endif;						\	.section __ex_table,"a";			\	PTR_WD	9b, handler;				\	.previous 	.macro	f_fill64 dst, offset, val, fixup, mode	EX(LONG_S, \val, (\offset +  0 * STORSIZE)(\dst), \fixup)	EX(LONG_S, \val, (\offset +  1 * STORSIZE)(\dst), \fixup)	EX(LONG_S, \val, (\offset +  2 * STORSIZE)(\dst), \fixup)	EX(LONG_S, \val, (\offset +  3 * STORSIZE)(\dst), \fixup)#if ((defined(CONFIG_CPU_MICROMIPS) && (LONGSIZE == 4)) || !defined(CONFIG_CPU_MICROMIPS))	EX(LONG_S, \val, (\offset +  4 * STORSIZE)(\dst), \fixup)	EX(LONG_S, \val, (\offset +  5 * STORSIZE)(\dst), \fixup)	EX(LONG_S, \val, (\offset +  6 * STORSIZE)(\dst), \fixup)	EX(LONG_S, \val, (\offset +  7 * STORSIZE)(\dst), \fixup)#endif#if (!defined(CONFIG_CPU_MICROMIPS) && (LONGSIZE == 4))	EX(LONG_S, \val, (\offset +  8 * STORSIZE)(\dst), \fixup)	EX(LONG_S, \val, (\offset +  9 * STORSIZE)(\dst), \fixup)	EX(LONG_S, \val, (\offset + 10 * STORSIZE)(\dst), \fixup)	EX(LONG_S, \val, (\offset + 11 * STORSIZE)(\dst), \fixup)	EX(LONG_S, \val, (\offset + 12 * STORSIZE)(\dst), \fixup)	EX(LONG_S, \val, (\offset + 13 * STORSIZE)(\dst), \fixup)	EX(LONG_S, \val, (\offset + 14 * STORSIZE)(\dst), \fixup)	EX(LONG_S, \val, (\offset + 15 * STORSIZE)(\dst), \fixup)#endif	.endm 	.align	5 	/*	 * Macro to generate the __bzero{,_user} symbol	 * Arguments:	 * mode: LEGACY_MODE or EVA_MODE	 */	.macro __BUILD_BZERO mode	/* Initialize __memset if this is the first time we call this macro */	.ifnotdef __memset	.set __memset, 1	.endif 	sltiu		t0, a2, STORSIZE	/* very small region? */	.set		noreorder	bnez		t0, .Lsmall_memset\@	 andi		t0, a0, STORMASK	/* aligned? */	.set		reorder #ifdef CONFIG_CPU_MICROMIPS	move		t8, a1			/* used by 'swp' instruction */	move		t9, a1#endif	.set		noreorder#ifndef CONFIG_CPU_DADDI_WORKAROUNDS	beqz		t0, 1f	 PTR_SUBU	t0, STORSIZE		/* alignment in bytes */#else	.set		noat	li		AT, STORSIZE	beqz		t0, 1f	 PTR_SUBU	t0, AT			/* alignment in bytes */	.set		at#endif	.set		reorder #ifndef CONFIG_CPU_NO_LOAD_STORE_LR	R10KCBARRIER(0(ra))#ifdef __MIPSEB__	EX(LONG_S_L, a1, (a0), .Lfirst_fixup\@)	/* make word/dword aligned */#else	EX(LONG_S_R, a1, (a0), .Lfirst_fixup\@)	/* make word/dword aligned */#endif	PTR_SUBU	a0, t0			/* long align ptr */	PTR_ADDU	a2, t0			/* correct size */ #else /* CONFIG_CPU_NO_LOAD_STORE_LR */#define STORE_BYTE(N)				\	EX(sb, a1, N(a0), .Lbyte_fixup\@);	\	.set		noreorder;		\	beqz		t0, 0f;			\	 PTR_ADDU	t0, 1;			\	.set		reorder; 	PTR_ADDU	a2, t0			/* correct size */	PTR_ADDU	t0, 1	STORE_BYTE(0)	STORE_BYTE(1)#if LONGSIZE == 4	EX(sb, a1, 2(a0), .Lbyte_fixup\@)#else	STORE_BYTE(2)	STORE_BYTE(3)	STORE_BYTE(4)	STORE_BYTE(5)	EX(sb, a1, 6(a0), .Lbyte_fixup\@)#endif0:	ori		a0, STORMASK	xori		a0, STORMASK	PTR_ADDIU	a0, STORSIZE#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */1:	ori		t1, a2, 0x3f		/* # of full blocks */	xori		t1, 0x3f	andi		t0, a2, 0x40-STORSIZE	beqz		t1, .Lmemset_partial\@	/* no block to fill */ 	PTR_ADDU	t1, a0			/* end address */1:	PTR_ADDIU	a0, 64	R10KCBARRIER(0(ra))	f_fill64 a0, -64, FILL64RG, .Lfwd_fixup\@, \mode	bne		t1, a0, 1b .Lmemset_partial\@:	R10KCBARRIER(0(ra))	PTR_LA		t1, 2f			/* where to start */#ifdef CONFIG_CPU_MICROMIPS	LONG_SRL	t7, t0, 1#endif#if LONGSIZE == 4	PTR_SUBU	t1, FILLPTRG#else	.set		noat	LONG_SRL	AT, FILLPTRG, 1	PTR_SUBU	t1, AT	.set		at#endif	PTR_ADDU	a0, t0			/* dest ptr */	jr		t1 	/* ... but first do longs ... */	f_fill64 a0, -64, FILL64RG, .Lpartial_fixup\@, \mode2:	andi		a2, STORMASK		/* At most one long to go */ 	.set		noreorder	beqz		a2, 1f#ifndef CONFIG_CPU_NO_LOAD_STORE_LR	 PTR_ADDU	a0, a2			/* What's left */	.set		reorder	R10KCBARRIER(0(ra))#ifdef __MIPSEB__	EX(LONG_S_R, a1, -1(a0), .Llast_fixup\@)#else	EX(LONG_S_L, a1, -1(a0), .Llast_fixup\@)#endif#else /* CONFIG_CPU_NO_LOAD_STORE_LR */	 PTR_SUBU	t0, $0, a2	.set		reorder	move		a2, zero		/* No remaining longs */	PTR_ADDIU	t0, 1	STORE_BYTE(0)	STORE_BYTE(1)#if LONGSIZE == 4	EX(sb, a1, 2(a0), .Lbyte_fixup\@)#else	STORE_BYTE(2)	STORE_BYTE(3)	STORE_BYTE(4)	STORE_BYTE(5)	EX(sb, a1, 6(a0), .Lbyte_fixup\@)#endif0:#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */1:	move		a2, zero	jr		ra .Lsmall_memset\@:	PTR_ADDU	t1, a0, a2	beqz		a2, 2f 1:	PTR_ADDIU	a0, 1			/* fill bytewise */	R10KCBARRIER(0(ra))	.set		noreorder	bne		t1, a0, 1b	 EX(sb, a1, -1(a0), .Lsmall_fixup\@)	.set		reorder 2:	move		a2, zero	jr		ra			/* done */	.if __memset == 1	END(memset)	.set __memset, 0	.endif #ifdef CONFIG_CPU_NO_LOAD_STORE_LR.Lbyte_fixup\@:	/*	 * unset_bytes = (#bytes - (#unaligned bytes)) - (-#unaligned bytes remaining + 1) + 1	 *      a2     =             a2                -              t0                   + 1	 */	PTR_SUBU	a2, t0	PTR_ADDIU	a2, 1	jr		ra#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */ .Lfirst_fixup\@:	/* unset_bytes already in a2 */	jr	ra .Lfwd_fixup\@:	/*	 * unset_bytes = partial_start_addr +  #bytes   -     fault_addr	 *      a2     =         t1         + (a2 & 3f) - $28->task->BUADDR	 */	PTR_L		t0, TI_TASK($28)	andi		a2, 0x3f	LONG_L		t0, THREAD_BUADDR(t0)	LONG_ADDU	a2, t1	LONG_SUBU	a2, t0	jr		ra .Lpartial_fixup\@:	/*	 * unset_bytes = partial_end_addr +      #bytes     -     fault_addr	 *      a2     =       a0         + (a2 & STORMASK) - $28->task->BUADDR	 */	PTR_L		t0, TI_TASK($28)	andi		a2, STORMASK	LONG_L		t0, THREAD_BUADDR(t0)	LONG_ADDU	a2, a0	LONG_SUBU	a2, t0	jr		ra .Llast_fixup\@:	/* unset_bytes already in a2 */	jr		ra .Lsmall_fixup\@:	/*	 * unset_bytes = end_addr - current_addr + 1	 *      a2     =    t1    -      a0      + 1	 */	PTR_SUBU	a2, t1, a0	PTR_ADDIU	a2, 1	jr		ra 	.endm /* * memset(void *s, int c, size_t n) * * a0: start of area to clear * a1: char to fill with * a2: size of area to clear */ LEAF(memset)EXPORT_SYMBOL(memset)	move		v0, a0			/* result */	beqz		a1, 1f 	andi		a1, 0xff		/* spread fillword */	LONG_SLL		t1, a1, 8	or		a1, t1	LONG_SLL		t1, a1, 16#if LONGSIZE == 8	or		a1, t1	LONG_SLL		t1, a1, 32#endif	or		a1, t11:#ifndef CONFIG_EVAFEXPORT(__bzero)EXPORT_SYMBOL(__bzero)#endif	__BUILD_BZERO LEGACY_MODE #ifdef CONFIG_EVALEAF(__bzero)EXPORT_SYMBOL(__bzero)	__BUILD_BZERO EVA_MODEEND(__bzero)#endif