xref: /kernel/linux/linux-6.6/arch/mips/lib/memset.S (revision 62306a36)
162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
362306a36Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
462306a36Sopenharmony_ci * for more details.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 1998, 1999, 2000 by Ralf Baechle
762306a36Sopenharmony_ci * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
862306a36Sopenharmony_ci * Copyright (C) 2007 by Maciej W. Rozycki
962306a36Sopenharmony_ci * Copyright (C) 2011, 2012 MIPS Technologies, Inc.
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci#include <linux/export.h>
1262306a36Sopenharmony_ci#include <asm/asm.h>
1362306a36Sopenharmony_ci#include <asm/asm-offsets.h>
1462306a36Sopenharmony_ci#include <asm/regdef.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#if LONGSIZE == 4
1762306a36Sopenharmony_ci#define LONG_S_L swl
1862306a36Sopenharmony_ci#define LONG_S_R swr
1962306a36Sopenharmony_ci#else
2062306a36Sopenharmony_ci#define LONG_S_L sdl
2162306a36Sopenharmony_ci#define LONG_S_R sdr
2262306a36Sopenharmony_ci#endif
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#ifdef CONFIG_CPU_MICROMIPS
2562306a36Sopenharmony_ci#define STORSIZE (LONGSIZE * 2)
2662306a36Sopenharmony_ci#define STORMASK (STORSIZE - 1)
2762306a36Sopenharmony_ci#define FILL64RG t8
2862306a36Sopenharmony_ci#define FILLPTRG t7
2962306a36Sopenharmony_ci#undef  LONG_S
3062306a36Sopenharmony_ci#define LONG_S LONG_SP
3162306a36Sopenharmony_ci#else
3262306a36Sopenharmony_ci#define STORSIZE LONGSIZE
3362306a36Sopenharmony_ci#define STORMASK LONGMASK
3462306a36Sopenharmony_ci#define FILL64RG a1
3562306a36Sopenharmony_ci#define FILLPTRG t0
3662306a36Sopenharmony_ci#endif
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define LEGACY_MODE 1
3962306a36Sopenharmony_ci#define EVA_MODE    2
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci/*
4262306a36Sopenharmony_ci * No need to protect it with EVA #ifdefery. The generated block of code
4362306a36Sopenharmony_ci * will never be assembled if EVA is not enabled.
4462306a36Sopenharmony_ci */
4562306a36Sopenharmony_ci#define __EVAFY(insn, reg, addr) __BUILD_EVA_INSN(insn##e, reg, addr)
4662306a36Sopenharmony_ci#define ___BUILD_EVA_INSN(insn, reg, addr) __EVAFY(insn, reg, addr)
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#define EX(insn,reg,addr,handler)			\
4962306a36Sopenharmony_ci	.if \mode == LEGACY_MODE;			\
5062306a36Sopenharmony_ci9:		insn	reg, addr;			\
5162306a36Sopenharmony_ci	.else;						\
5262306a36Sopenharmony_ci9:		___BUILD_EVA_INSN(insn, reg, addr);	\
5362306a36Sopenharmony_ci	.endif;						\
5462306a36Sopenharmony_ci	.section __ex_table,"a";			\
5562306a36Sopenharmony_ci	PTR_WD	9b, handler;				\
5662306a36Sopenharmony_ci	.previous
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	.macro	f_fill64 dst, offset, val, fixup, mode
5962306a36Sopenharmony_ci	EX(LONG_S, \val, (\offset +  0 * STORSIZE)(\dst), \fixup)
6062306a36Sopenharmony_ci	EX(LONG_S, \val, (\offset +  1 * STORSIZE)(\dst), \fixup)
6162306a36Sopenharmony_ci	EX(LONG_S, \val, (\offset +  2 * STORSIZE)(\dst), \fixup)
6262306a36Sopenharmony_ci	EX(LONG_S, \val, (\offset +  3 * STORSIZE)(\dst), \fixup)
6362306a36Sopenharmony_ci#if ((defined(CONFIG_CPU_MICROMIPS) && (LONGSIZE == 4)) || !defined(CONFIG_CPU_MICROMIPS))
6462306a36Sopenharmony_ci	EX(LONG_S, \val, (\offset +  4 * STORSIZE)(\dst), \fixup)
6562306a36Sopenharmony_ci	EX(LONG_S, \val, (\offset +  5 * STORSIZE)(\dst), \fixup)
6662306a36Sopenharmony_ci	EX(LONG_S, \val, (\offset +  6 * STORSIZE)(\dst), \fixup)
6762306a36Sopenharmony_ci	EX(LONG_S, \val, (\offset +  7 * STORSIZE)(\dst), \fixup)
6862306a36Sopenharmony_ci#endif
6962306a36Sopenharmony_ci#if (!defined(CONFIG_CPU_MICROMIPS) && (LONGSIZE == 4))
7062306a36Sopenharmony_ci	EX(LONG_S, \val, (\offset +  8 * STORSIZE)(\dst), \fixup)
7162306a36Sopenharmony_ci	EX(LONG_S, \val, (\offset +  9 * STORSIZE)(\dst), \fixup)
7262306a36Sopenharmony_ci	EX(LONG_S, \val, (\offset + 10 * STORSIZE)(\dst), \fixup)
7362306a36Sopenharmony_ci	EX(LONG_S, \val, (\offset + 11 * STORSIZE)(\dst), \fixup)
7462306a36Sopenharmony_ci	EX(LONG_S, \val, (\offset + 12 * STORSIZE)(\dst), \fixup)
7562306a36Sopenharmony_ci	EX(LONG_S, \val, (\offset + 13 * STORSIZE)(\dst), \fixup)
7662306a36Sopenharmony_ci	EX(LONG_S, \val, (\offset + 14 * STORSIZE)(\dst), \fixup)
7762306a36Sopenharmony_ci	EX(LONG_S, \val, (\offset + 15 * STORSIZE)(\dst), \fixup)
7862306a36Sopenharmony_ci#endif
7962306a36Sopenharmony_ci	.endm
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	.align	5
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	/*
8462306a36Sopenharmony_ci	 * Macro to generate the __bzero{,_user} symbol
8562306a36Sopenharmony_ci	 * Arguments:
8662306a36Sopenharmony_ci	 * mode: LEGACY_MODE or EVA_MODE
8762306a36Sopenharmony_ci	 */
8862306a36Sopenharmony_ci	.macro __BUILD_BZERO mode
8962306a36Sopenharmony_ci	/* Initialize __memset if this is the first time we call this macro */
9062306a36Sopenharmony_ci	.ifnotdef __memset
9162306a36Sopenharmony_ci	.set __memset, 1
9262306a36Sopenharmony_ci	.hidden __memset /* Make sure it does not leak */
9362306a36Sopenharmony_ci	.endif
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	sltiu		t0, a2, STORSIZE	/* very small region? */
9662306a36Sopenharmony_ci	.set		noreorder
9762306a36Sopenharmony_ci	bnez		t0, .Lsmall_memset\@
9862306a36Sopenharmony_ci	 andi		t0, a0, STORMASK	/* aligned? */
9962306a36Sopenharmony_ci	.set		reorder
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci#ifdef CONFIG_CPU_MICROMIPS
10262306a36Sopenharmony_ci	move		t8, a1			/* used by 'swp' instruction */
10362306a36Sopenharmony_ci	move		t9, a1
10462306a36Sopenharmony_ci#endif
10562306a36Sopenharmony_ci	.set		noreorder
10662306a36Sopenharmony_ci#ifndef CONFIG_CPU_DADDI_WORKAROUNDS
10762306a36Sopenharmony_ci	beqz		t0, 1f
10862306a36Sopenharmony_ci	 PTR_SUBU	t0, STORSIZE		/* alignment in bytes */
10962306a36Sopenharmony_ci#else
11062306a36Sopenharmony_ci	.set		noat
11162306a36Sopenharmony_ci	li		AT, STORSIZE
11262306a36Sopenharmony_ci	beqz		t0, 1f
11362306a36Sopenharmony_ci	 PTR_SUBU	t0, AT			/* alignment in bytes */
11462306a36Sopenharmony_ci	.set		at
11562306a36Sopenharmony_ci#endif
11662306a36Sopenharmony_ci	.set		reorder
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci#ifndef CONFIG_CPU_NO_LOAD_STORE_LR
11962306a36Sopenharmony_ci	R10KCBARRIER(0(ra))
12062306a36Sopenharmony_ci#ifdef __MIPSEB__
12162306a36Sopenharmony_ci	EX(LONG_S_L, a1, (a0), .Lfirst_fixup\@)	/* make word/dword aligned */
12262306a36Sopenharmony_ci#else
12362306a36Sopenharmony_ci	EX(LONG_S_R, a1, (a0), .Lfirst_fixup\@)	/* make word/dword aligned */
12462306a36Sopenharmony_ci#endif
12562306a36Sopenharmony_ci	PTR_SUBU	a0, t0			/* long align ptr */
12662306a36Sopenharmony_ci	PTR_ADDU	a2, t0			/* correct size */
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci#else /* CONFIG_CPU_NO_LOAD_STORE_LR */
12962306a36Sopenharmony_ci#define STORE_BYTE(N)				\
13062306a36Sopenharmony_ci	EX(sb, a1, N(a0), .Lbyte_fixup\@);	\
13162306a36Sopenharmony_ci	.set		noreorder;		\
13262306a36Sopenharmony_ci	beqz		t0, 0f;			\
13362306a36Sopenharmony_ci	 PTR_ADDU	t0, 1;			\
13462306a36Sopenharmony_ci	.set		reorder;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	PTR_ADDU	a2, t0			/* correct size */
13762306a36Sopenharmony_ci	PTR_ADDU	t0, 1
13862306a36Sopenharmony_ci	STORE_BYTE(0)
13962306a36Sopenharmony_ci	STORE_BYTE(1)
14062306a36Sopenharmony_ci#if LONGSIZE == 4
14162306a36Sopenharmony_ci	EX(sb, a1, 2(a0), .Lbyte_fixup\@)
14262306a36Sopenharmony_ci#else
14362306a36Sopenharmony_ci	STORE_BYTE(2)
14462306a36Sopenharmony_ci	STORE_BYTE(3)
14562306a36Sopenharmony_ci	STORE_BYTE(4)
14662306a36Sopenharmony_ci	STORE_BYTE(5)
14762306a36Sopenharmony_ci	EX(sb, a1, 6(a0), .Lbyte_fixup\@)
14862306a36Sopenharmony_ci#endif
14962306a36Sopenharmony_ci0:
15062306a36Sopenharmony_ci	ori		a0, STORMASK
15162306a36Sopenharmony_ci	xori		a0, STORMASK
15262306a36Sopenharmony_ci	PTR_ADDIU	a0, STORSIZE
15362306a36Sopenharmony_ci#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */
15462306a36Sopenharmony_ci1:	ori		t1, a2, 0x3f		/* # of full blocks */
15562306a36Sopenharmony_ci	xori		t1, 0x3f
15662306a36Sopenharmony_ci	andi		t0, a2, 0x40-STORSIZE
15762306a36Sopenharmony_ci	beqz		t1, .Lmemset_partial\@	/* no block to fill */
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	PTR_ADDU	t1, a0			/* end address */
16062306a36Sopenharmony_ci1:	PTR_ADDIU	a0, 64
16162306a36Sopenharmony_ci	R10KCBARRIER(0(ra))
16262306a36Sopenharmony_ci	f_fill64 a0, -64, FILL64RG, .Lfwd_fixup\@, \mode
16362306a36Sopenharmony_ci	bne		t1, a0, 1b
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci.Lmemset_partial\@:
16662306a36Sopenharmony_ci	R10KCBARRIER(0(ra))
16762306a36Sopenharmony_ci	PTR_LA		t1, 2f			/* where to start */
16862306a36Sopenharmony_ci#ifdef CONFIG_CPU_MICROMIPS
16962306a36Sopenharmony_ci	LONG_SRL	t7, t0, 1
17062306a36Sopenharmony_ci#endif
17162306a36Sopenharmony_ci#if LONGSIZE == 4
17262306a36Sopenharmony_ci	PTR_SUBU	t1, FILLPTRG
17362306a36Sopenharmony_ci#else
17462306a36Sopenharmony_ci	.set		noat
17562306a36Sopenharmony_ci	LONG_SRL	AT, FILLPTRG, 1
17662306a36Sopenharmony_ci	PTR_SUBU	t1, AT
17762306a36Sopenharmony_ci	.set		at
17862306a36Sopenharmony_ci#endif
17962306a36Sopenharmony_ci	PTR_ADDU	a0, t0			/* dest ptr */
18062306a36Sopenharmony_ci	jr		t1
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	/* ... but first do longs ... */
18362306a36Sopenharmony_ci	f_fill64 a0, -64, FILL64RG, .Lpartial_fixup\@, \mode
18462306a36Sopenharmony_ci2:	andi		a2, STORMASK		/* At most one long to go */
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	.set		noreorder
18762306a36Sopenharmony_ci	beqz		a2, 1f
18862306a36Sopenharmony_ci#ifndef CONFIG_CPU_NO_LOAD_STORE_LR
18962306a36Sopenharmony_ci	 PTR_ADDU	a0, a2			/* What's left */
19062306a36Sopenharmony_ci	.set		reorder
19162306a36Sopenharmony_ci	R10KCBARRIER(0(ra))
19262306a36Sopenharmony_ci#ifdef __MIPSEB__
19362306a36Sopenharmony_ci	EX(LONG_S_R, a1, -1(a0), .Llast_fixup\@)
19462306a36Sopenharmony_ci#else
19562306a36Sopenharmony_ci	EX(LONG_S_L, a1, -1(a0), .Llast_fixup\@)
19662306a36Sopenharmony_ci#endif
19762306a36Sopenharmony_ci#else /* CONFIG_CPU_NO_LOAD_STORE_LR */
19862306a36Sopenharmony_ci	 PTR_SUBU	t0, $0, a2
19962306a36Sopenharmony_ci	.set		reorder
20062306a36Sopenharmony_ci	move		a2, zero		/* No remaining longs */
20162306a36Sopenharmony_ci	PTR_ADDIU	t0, 1
20262306a36Sopenharmony_ci	STORE_BYTE(0)
20362306a36Sopenharmony_ci	STORE_BYTE(1)
20462306a36Sopenharmony_ci#if LONGSIZE == 4
20562306a36Sopenharmony_ci	EX(sb, a1, 2(a0), .Lbyte_fixup\@)
20662306a36Sopenharmony_ci#else
20762306a36Sopenharmony_ci	STORE_BYTE(2)
20862306a36Sopenharmony_ci	STORE_BYTE(3)
20962306a36Sopenharmony_ci	STORE_BYTE(4)
21062306a36Sopenharmony_ci	STORE_BYTE(5)
21162306a36Sopenharmony_ci	EX(sb, a1, 6(a0), .Lbyte_fixup\@)
21262306a36Sopenharmony_ci#endif
21362306a36Sopenharmony_ci0:
21462306a36Sopenharmony_ci#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */
21562306a36Sopenharmony_ci1:	move		a2, zero
21662306a36Sopenharmony_ci	jr		ra
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci.Lsmall_memset\@:
21962306a36Sopenharmony_ci	PTR_ADDU	t1, a0, a2
22062306a36Sopenharmony_ci	beqz		a2, 2f
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci1:	PTR_ADDIU	a0, 1			/* fill bytewise */
22362306a36Sopenharmony_ci	R10KCBARRIER(0(ra))
22462306a36Sopenharmony_ci	.set		noreorder
22562306a36Sopenharmony_ci	bne		t1, a0, 1b
22662306a36Sopenharmony_ci	 EX(sb, a1, -1(a0), .Lsmall_fixup\@)
22762306a36Sopenharmony_ci	.set		reorder
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci2:	move		a2, zero
23062306a36Sopenharmony_ci	jr		ra			/* done */
23162306a36Sopenharmony_ci	.if __memset == 1
23262306a36Sopenharmony_ci	END(memset)
23362306a36Sopenharmony_ci	.set __memset, 0
23462306a36Sopenharmony_ci	.hidden __memset
23562306a36Sopenharmony_ci	.endif
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci#ifdef CONFIG_CPU_NO_LOAD_STORE_LR
23862306a36Sopenharmony_ci.Lbyte_fixup\@:
23962306a36Sopenharmony_ci	/*
24062306a36Sopenharmony_ci	 * unset_bytes = (#bytes - (#unaligned bytes)) - (-#unaligned bytes remaining + 1) + 1
24162306a36Sopenharmony_ci	 *      a2     =             a2                -              t0                   + 1
24262306a36Sopenharmony_ci	 */
24362306a36Sopenharmony_ci	PTR_SUBU	a2, t0
24462306a36Sopenharmony_ci	PTR_ADDIU	a2, 1
24562306a36Sopenharmony_ci	jr		ra
24662306a36Sopenharmony_ci#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci.Lfirst_fixup\@:
24962306a36Sopenharmony_ci	/* unset_bytes already in a2 */
25062306a36Sopenharmony_ci	jr	ra
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci.Lfwd_fixup\@:
25362306a36Sopenharmony_ci	/*
25462306a36Sopenharmony_ci	 * unset_bytes = partial_start_addr +  #bytes   -     fault_addr
25562306a36Sopenharmony_ci	 *      a2     =         t1         + (a2 & 3f) - $28->task->BUADDR
25662306a36Sopenharmony_ci	 */
25762306a36Sopenharmony_ci	PTR_L		t0, TI_TASK($28)
25862306a36Sopenharmony_ci	andi		a2, 0x3f
25962306a36Sopenharmony_ci	LONG_L		t0, THREAD_BUADDR(t0)
26062306a36Sopenharmony_ci	LONG_ADDU	a2, t1
26162306a36Sopenharmony_ci	LONG_SUBU	a2, t0
26262306a36Sopenharmony_ci	jr		ra
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci.Lpartial_fixup\@:
26562306a36Sopenharmony_ci	/*
26662306a36Sopenharmony_ci	 * unset_bytes = partial_end_addr +      #bytes     -     fault_addr
26762306a36Sopenharmony_ci	 *      a2     =       a0         + (a2 & STORMASK) - $28->task->BUADDR
26862306a36Sopenharmony_ci	 */
26962306a36Sopenharmony_ci	PTR_L		t0, TI_TASK($28)
27062306a36Sopenharmony_ci	andi		a2, STORMASK
27162306a36Sopenharmony_ci	LONG_L		t0, THREAD_BUADDR(t0)
27262306a36Sopenharmony_ci	LONG_ADDU	a2, a0
27362306a36Sopenharmony_ci	LONG_SUBU	a2, t0
27462306a36Sopenharmony_ci	jr		ra
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci.Llast_fixup\@:
27762306a36Sopenharmony_ci	/* unset_bytes already in a2 */
27862306a36Sopenharmony_ci	jr		ra
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci.Lsmall_fixup\@:
28162306a36Sopenharmony_ci	/*
28262306a36Sopenharmony_ci	 * unset_bytes = end_addr - current_addr + 1
28362306a36Sopenharmony_ci	 *      a2     =    t1    -      a0      + 1
28462306a36Sopenharmony_ci	 */
28562306a36Sopenharmony_ci	PTR_SUBU	a2, t1, a0
28662306a36Sopenharmony_ci	PTR_ADDIU	a2, 1
28762306a36Sopenharmony_ci	jr		ra
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	.endm
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci/*
29262306a36Sopenharmony_ci * memset(void *s, int c, size_t n)
29362306a36Sopenharmony_ci *
29462306a36Sopenharmony_ci * a0: start of area to clear
29562306a36Sopenharmony_ci * a1: char to fill with
29662306a36Sopenharmony_ci * a2: size of area to clear
29762306a36Sopenharmony_ci */
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ciLEAF(memset)
30062306a36Sopenharmony_ciEXPORT_SYMBOL(memset)
30162306a36Sopenharmony_ci	move		v0, a0			/* result */
30262306a36Sopenharmony_ci	beqz		a1, 1f
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	andi		a1, 0xff		/* spread fillword */
30562306a36Sopenharmony_ci	LONG_SLL		t1, a1, 8
30662306a36Sopenharmony_ci	or		a1, t1
30762306a36Sopenharmony_ci	LONG_SLL		t1, a1, 16
30862306a36Sopenharmony_ci#if LONGSIZE == 8
30962306a36Sopenharmony_ci	or		a1, t1
31062306a36Sopenharmony_ci	LONG_SLL		t1, a1, 32
31162306a36Sopenharmony_ci#endif
31262306a36Sopenharmony_ci	or		a1, t1
31362306a36Sopenharmony_ci1:
31462306a36Sopenharmony_ci#ifndef CONFIG_EVA
31562306a36Sopenharmony_ciFEXPORT(__bzero)
31662306a36Sopenharmony_ciEXPORT_SYMBOL(__bzero)
31762306a36Sopenharmony_ci#endif
31862306a36Sopenharmony_ci	__BUILD_BZERO LEGACY_MODE
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci#ifdef CONFIG_EVA
32162306a36Sopenharmony_ciLEAF(__bzero)
32262306a36Sopenharmony_ciEXPORT_SYMBOL(__bzero)
32362306a36Sopenharmony_ci	__BUILD_BZERO EVA_MODE
32462306a36Sopenharmony_ciEND(__bzero)
32562306a36Sopenharmony_ci#endif
326