import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / arch / mips / lib / memset.S
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 1998 by Ralf Baechle
7  */
8 #include <asm/asm.h>
9 #include <asm/offset.h>
10 #include <asm/regdef.h>
11
12 #define EX(insn,reg,addr,handler)                       \
13 9:      insn    reg, addr;                              \
14         .section __ex_table,"a";                        \
15         PTR     9b, handler;                            \
16         .previous
17
18 #define F_FILL64(dst, offset, val, fixup)               \
19         EX(sw, val, (offset + 0x00)(dst), fixup);       \
20         EX(sw, val, (offset + 0x04)(dst), fixup);       \
21         EX(sw, val, (offset + 0x08)(dst), fixup);       \
22         EX(sw, val, (offset + 0x0c)(dst), fixup);       \
23         EX(sw, val, (offset + 0x10)(dst), fixup);       \
24         EX(sw, val, (offset + 0x14)(dst), fixup);       \
25         EX(sw, val, (offset + 0x18)(dst), fixup);       \
26         EX(sw, val, (offset + 0x1c)(dst), fixup);       \
27         EX(sw, val, (offset + 0x20)(dst), fixup);       \
28         EX(sw, val, (offset + 0x24)(dst), fixup);       \
29         EX(sw, val, (offset + 0x28)(dst), fixup);       \
30         EX(sw, val, (offset + 0x2c)(dst), fixup);       \
31         EX(sw, val, (offset + 0x30)(dst), fixup);       \
32         EX(sw, val, (offset + 0x34)(dst), fixup);       \
33         EX(sw, val, (offset + 0x38)(dst), fixup);       \
34         EX(sw, val, (offset + 0x3c)(dst), fixup)
35
36 /*
37  * memset(void *s, int c, size_t n)
38  *
39  * a0: start of area to clear
40  * a1: char to fill with
41  * a2: size of area to clear
42  */
43         .set    noreorder
44         .align  5
45 LEAF(memset)
46         beqz    a1, 1f
47          move   v0, a0                          /* result */
48
49         andi    a1, 0xff                        /* spread fillword */
50         sll     t1, a1, 8
51         or      a1, t1
52         sll     t1, a1, 16
53         or      a1, t1
54 1:
55
56 EXPORT(__bzero)
57         sltiu   t0, a2, 4                       /* very small region? */
58         bnez    t0, small_memset
59          andi   t0, a0, 3                       /* aligned? */
60
61         beqz    t0, 1f
62          subu   t0, 4                           /* alignment in bytes */
63
64 #ifdef __MIPSEB__
65         EX(swl, a1, (a0), first_fixup)          /* make word aligned */
66 #endif
67 #ifdef __MIPSEL__
68         EX(swr, a1, (a0), first_fixup)          /* make word aligned */
69 #endif
70         subu    a0, t0                          /* word align ptr */
71         addu    a2, t0                          /* correct size */
72
73 1:      ori     t1, a2, 0x3f                    /* # of full blocks */
74         xori    t1, 0x3f
75         beqz    t1, memset_partial              /* no block to fill */
76          andi   t0, a2, 0x3c
77
78         addu    t1, a0                          /* end address */
79         .set    reorder
80 1:      addiu   a0, 64
81         F_FILL64(a0, -64, a1, fwd_fixup)
82         bne     t1, a0, 1b
83         .set    noreorder
84
85 memset_partial:
86         PTR_LA  t1, 2f                          /* where to start */
87         subu    t1, t0
88         jr      t1
89          addu   a0, t0                          /* dest ptr */
90
91         .set    push
92         .set    noreorder
93         .set    nomacro
94         F_FILL64(a0, -64, a1, partial_fixup)    /* ... but first do wrds ... */
95 2:      .set    pop
96         andi    a2, 3                           /* 0 <= n <= 3 to go */
97
98         beqz    a2, 1f
99          addu   a0, a2                          /* What's left */
100 #ifdef __MIPSEB__
101         EX(swr, a1, -1(a0), last_fixup)
102 #endif
103 #ifdef __MIPSEL__
104         EX(swl, a1, -1(a0), last_fixup)
105 #endif
106 1:      jr      ra
107          move   a2, zero
108
109 small_memset:
110         beqz    a2, 2f
111          addu   t1, a0, a2
112
113 1:      addiu   a0, 1                           /* fill bytewise */
114         bne     t1, a0, 1b
115          sb     a1, -1(a0)
116
117 2:      jr      ra                              /* done */
118          move   a2, zero
119         END(memset)
120
121 first_fixup:
122         jr      ra
123          nop
124
125 fwd_fixup:
126         lw      t0, THREAD_BUADDR($28)
127         andi    a2, 0x3f
128         addu    a2, t1
129         jr      ra
130          subu   a2, t0
131
132 partial_fixup:
133         lw      t0, THREAD_BUADDR($28)
134         andi    a2, 3
135         addu    a2, t1
136         jr      ra
137          subu   a2, t0
138
139 last_fixup:
140         jr      ra
141          andi   v1, a2, 3