summaryrefslogtreecommitdiffstats
path: root/arch/mips64/lib/memset.S
blob: fdb30700c7be84bd9e3c14f363726d2e31fae45d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/*
 * 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.
 */
#include <asm/asm.h>
#include <asm/offset.h>
#include <asm/regdef.h>
#include <asm/mipsregs.h>
#include <asm/stackframe.h>

#define EX(insn,reg,addr,handler)			\
9:	insn	reg, addr;				\
	.section __ex_table,"a"; 			\
	PTR	9b, handler; 				\
	.previous

#define F_FILL64(dst, offset, val, fixup)		\
	EX(sd, val, (offset + 0x00)(dst), fixup);	\
	EX(sd, val, (offset + 0x08)(dst), fixup);	\
	EX(sd, val, (offset + 0x10)(dst), fixup);	\
	EX(sd, val, (offset + 0x18)(dst), fixup);	\
	EX(sd, val, (offset + 0x20)(dst), fixup);	\
	EX(sd, val, (offset + 0x28)(dst), fixup);	\
	EX(sd, val, (offset + 0x30)(dst), fixup);	\
	EX(sd, val, (offset + 0x38)(dst), fixup)

/*
 * 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
 */
	.set	noreorder
	.align	5
LEAF(memset)
	beqz	a1, 1f
	 move	v0, a0				/* result */

	andi	a1, 0xff			/* spread fillword */
	dsll	t1, a1, 8
	or	a1, t1
	dsll	t1, a1, 16
	or	a1, t1
	dsll	t1, a1, 32
	or	a1, t1

1:

FEXPORT(__bzero)
	.type	__bzero, @function
	sltiu	t0, a2, 8			/* very small region? */
	bnez	t0, small_memset
	 andi	t0, a0, 7			/* aligned? */

	beqz	t0, 1f
	 dsubu	t0, 8				/* alignment in bytes */

#ifdef __MIPSEB__
	EX(sdl, a1, (a0), first_fixup)		/* make dword aligned */
#endif
#ifdef __MIPSEL__
	EX(sdr, a1, (a0), first_fixup)		/* make dword aligned */
#endif
	dsubu	a0, t0				/* dword align ptr */
	daddu	a2, t0				/* correct size */

1:	ori	t1, a2, 0x3f			/* # of full blocks */
	xori	t1, 0x3f
	beqz	t1, memset_partial		/* no block to fill */
	 andi	t0, a2, 0x38

	daddu	t1, a0				/* end address */
	.set	reorder
1:	daddiu	a0, 64
	F_FILL64(a0, -64, a1, fwd_fixup)
	bne	t1, a0, 1b
	.set	noreorder

memset_partial:
	la	t1, 2f				/* where to start */
	.set	noat
	dsrl	AT, t0, 1
	dsubu	t1, AT
	.set	noat
	jr	t1
	 daddu	a0, t0				/* dest ptr */

	F_FILL64(a0, -64, a1, partial_fixup)	/* ... but first do dwds ... */
2:	andi	a2, 7				/* 0 <= n <= 7 to go */

	beqz	a2, 1f
	 daddu	a0, a2				/* What's left */
#ifdef __MIPSEB__
	EX(sdr, a1, -1(a0), last_fixup)
#endif
#ifdef __MIPSEL__
	EX(sdl, a1, -1(a0), last_fixup)
#endif
1:	jr	ra
	 move	a2, zero

small_memset:
	beqz	a2, 2f
	 daddu	t1, a0, a2

1:	daddiu	a0, 1				/* fill bytewise */
	bne	t1, a0, 1b
	 sb	a1, -1(a0)

2:	jr	ra				/* done */
	 move	a2, zero
	END(memset)

first_fixup:
	jr	ra
	 nop

fwd_fixup:
	ld	t0, THREAD_BUADDR($28)
	andi	a2, 0x3f
	daddu	a2, t1
	jr	ra
	 dsubu	a2, t0

partial_fixup:
	ld	t0, THREAD_BUADDR($28)
	andi	a2, 7
	daddu	a2, t1
	jr	ra
	 dsubu	a2, t0

last_fixup:
	jr	ra
	 andi	v1, a2, 7