- Linus: more PageDirty / swapcache handling
[davej-history.git] / arch / mips64 / lib / memcpy.S
blobeb51e10692e76d0e2a08dfb9c00065d67130c520
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  * Unified implementation of memcpy, memmove and the __copy_user backend.
7  *
8  * Copyright (C) 1998, 1999, 2000 Ralf Baechle
9  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
10  *
11  * For __rmemcpy and memmove an exception is always a kernel bug, therefore
12  * they're not protected.  In order to keep the exception fixup routine
13  * simple all memory accesses in __copy_user to src rsp. dst are stricly
14  * incremental.  The fixup routine depends on $at not being changed.
15  */
16 #include <asm/asm.h>
17 #include <asm/offset.h>
18 #include <asm/regdef.h>
21  * The fixup routine for copy_to_user depends on copying strictly in
22  * increasing order.  Gas expands the ulw/usw macros in the wrong order for
23  * little endian machines, so we cannot depend on them.
24  */
25 #ifdef __MIPSEB__
26 #define uswL    swl
27 #define uswU    swr
28 #define ulwL    lwl
29 #define ulwU    lwr
30 #define usdL    sdl
31 #define usdU    sdr
32 #define uldL    ldl
33 #define uldU    ldr
34 #endif
35 #ifdef __MIPSEL__
36 #define uswL    swr
37 #define uswU    swl
38 #define ulwL    lwr
39 #define ulwU    lwl
40 #define usdL    sdr
41 #define usdU    sdl
42 #define uldL    ldr
43 #define uldU    ldl
44 #endif
46 #define EX(insn,reg,addr,handler)                       \
47 9:      insn    reg, addr;                              \
48         .section __ex_table,"a";                        \
49         PTR     9b, handler;                            \
50         .previous
52 #define UEX(insn,reg,addr,handler)                      \
53 9:      insn ## L reg, addr;                            \
54 10:     insn ## U reg, 3 + addr;                        \
55         .section __ex_table,"a";                        \
56         PTR     9b, handler;                            \
57         PTR     10b, handler;                           \
58         .previous
60 #define UEXD(insn,reg,addr,handler)                     \
61 9:      insn ## L reg, addr;                            \
62 10:     insn ## U reg, 7 + addr;                        \
63         .section __ex_table,"a";                        \
64         PTR     9b, handler;                            \
65         PTR     10b, handler;                           \
66         .previous
68 /* ascending order, destination aligned  */
69 #define MOVE_BIGGERCHUNK(src, dst, offset, t0, t1, t2, t3) \
70         EX(ld, t0, (offset + 0x00)(src), l_fixup); \
71         EX(ld, t1, (offset + 0x08)(src), l_fixup); \
72         EX(ld, t2, (offset + 0x10)(src), l_fixup); \
73         EX(ld, t3, (offset + 0x18)(src), l_fixup); \
74         EX(sd, t0, (offset + 0x00)(dst), s_fixup); \
75         EX(sd, t1, (offset + 0x08)(dst), s_fixup); \
76         EX(sd, t2, (offset + 0x10)(dst), s_fixup); \
77         EX(sd, t3, (offset + 0x18)(dst), s_fixup); \
78         EX(ld, t0, (offset + 0x20)(src), l_fixup); \
79         EX(ld, t1, (offset + 0x28)(src), l_fixup); \
80         EX(ld, t2, (offset + 0x30)(src), l_fixup); \
81         EX(ld, t3, (offset + 0x38)(src), l_fixup); \
82         EX(sd, t0, (offset + 0x20)(dst), s_fixup); \
83         EX(sd, t1, (offset + 0x28)(dst), s_fixup); \
84         EX(sd, t2, (offset + 0x30)(dst), s_fixup); \
85         EX(sd, t3, (offset + 0x38)(dst), s_fixup)
87 /* ascending order, destination aligned  */
88 #define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3) \
89         EX(lw, t0, (offset + 0x00)(src), l_fixup); \
90         EX(lw, t1, (offset + 0x04)(src), l_fixup); \
91         EX(lw, t2, (offset + 0x08)(src), l_fixup); \
92         EX(lw, t3, (offset + 0x0c)(src), l_fixup); \
93         EX(sw, t0, (offset + 0x00)(dst), s_fixup); \
94         EX(sw, t1, (offset + 0x04)(dst), s_fixup); \
95         EX(sw, t2, (offset + 0x08)(dst), s_fixup); \
96         EX(sw, t3, (offset + 0x0c)(dst), s_fixup); \
97         EX(lw, t0, (offset + 0x10)(src), l_fixup); \
98         EX(lw, t1, (offset + 0x14)(src), l_fixup); \
99         EX(lw, t2, (offset + 0x18)(src), l_fixup); \
100         EX(lw, t3, (offset + 0x1c)(src), l_fixup); \
101         EX(sw, t0, (offset + 0x10)(dst), s_fixup); \
102         EX(sw, t1, (offset + 0x14)(dst), s_fixup); \
103         EX(sw, t2, (offset + 0x18)(dst), s_fixup); \
104         EX(sw, t3, (offset + 0x1c)(dst), s_fixup)
106 /* ascending order, destination unaligned  */
107 #define UMOVE_BIGGERCHUNK(src, dst, offset, t0, t1, t2, t3) \
108         EX(ld, t0, (offset + 0x00)(src), l_fixup); \
109         EX(ld, t1, (offset + 0x08)(src), l_fixup); \
110         EX(ld, t2, (offset + 0x10)(src), l_fixup); \
111         EX(ld, t3, (offset + 0x18)(src), l_fixup); \
112         UEXD(usd, t0, (offset + 0x00)(dst), s_fixup); \
113         UEXD(usd, t1, (offset + 0x08)(dst), s_fixup); \
114         UEXD(usd, t2, (offset + 0x10)(dst), s_fixup); \
115         UEXD(usd, t3, (offset + 0x18)(dst), s_fixup); \
116         EX(ld, t0, (offset + 0x20)(src), l_fixup); \
117         EX(ld, t1, (offset + 0x28)(src), l_fixup); \
118         EX(ld, t2, (offset + 0x30)(src), l_fixup); \
119         EX(ld, t3, (offset + 0x38)(src), l_fixup); \
120         UEXD(usd, t0, (offset + 0x20)(dst), s_fixup); \
121         UEXD(usd, t1, (offset + 0x28)(dst), s_fixup); \
122         UEXD(usd, t2, (offset + 0x30)(dst), s_fixup); \
123         UEXD(usd, t3, (offset + 0x38)(dst), s_fixup)
125 /* ascending order, destination unaligned  */
126 #define UMOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3) \
127         EX(lw, t0, (offset + 0x00)(src), l_fixup); \
128         EX(lw, t1, (offset + 0x04)(src), l_fixup); \
129         EX(lw, t2, (offset + 0x08)(src), l_fixup); \
130         EX(lw, t3, (offset + 0x0c)(src), l_fixup); \
131         UEX(usw, t0, (offset + 0x00)(dst), s_fixup); \
132         UEX(usw, t1, (offset + 0x04)(dst), s_fixup); \
133         UEX(usw, t2, (offset + 0x08)(dst), s_fixup); \
134         UEX(usw, t3, (offset + 0x0c)(dst), s_fixup); \
135         EX(lw, t0, (offset + 0x10)(src), l_fixup); \
136         EX(lw, t1, (offset + 0x14)(src), l_fixup); \
137         EX(lw, t2, (offset + 0x18)(src), l_fixup); \
138         EX(lw, t3, (offset + 0x1c)(src), l_fixup); \
139         UEX(usw, t0, (offset + 0x10)(dst), s_fixup); \
140         UEX(usw, t1, (offset + 0x14)(dst), s_fixup); \
141         UEX(usw, t2, (offset + 0x18)(dst), s_fixup); \
142         UEX(usw, t3, (offset + 0x1c)(dst), s_fixup)
144         .text
145         .set    noreorder
146         .set    noat
148         .align  5
149 LEAF(memcpy)                                    /* a0=dst a1=src a2=len */
150         move    v0, a0                          /* return value */
151 __memcpy:
152 FEXPORT(__copy_user)
153         xor     ta0, a0, a1
154         andi    ta0, ta0, 0x7
155         move    t3, a0
156         beqz    ta0, can_align
157          sltiu  t8, a2, 0x8
159         b       memcpy_u_src                    # bad alignment
160          move   ta2, a2
162 can_align:
163         bnez    t8, small_memcpy                # < 8 bytes to copy
164          move   ta2, a2
166         beqz    a2, out
167          andi   t8, a1, 0x1
169 hword_align:
170         beqz    t8, word_align
171          andi   t8, a1, 0x2
173         EX(lb, ta0, (a1), l_fixup)
174         dsubu   a2, a2, 0x1
175         EX(sb, ta0, (a0), s_fixup)
176         daddu   a1, a1, 0x1
177         daddu   a0, a0, 0x1
178         andi    t8, a1, 0x2
180 word_align:
181         beqz    t8, dword_align
182          sltiu  t8, a2, 56
184         EX(lh, ta0, (a1), l_fixup)
185         dsubu   a2, a2, 0x2
186         EX(sh, ta0, (a0), s_fixup)
187         sltiu   t8, a2, 56
188         daddu   a0, a0, 0x2
189         daddu   a1, a1, 0x2
191 dword_align:
192         bnez    t8, do_end_words
193          move   t8, a2
195         andi    t8, a1, 0x4
196         beqz    t8, qword_align
197          andi   t8, a1, 0x8
199         EX(lw, ta0, 0x00(a1), l_fixup)
200         dsubu   a2, a2, 0x4
201         EX(sw, ta0, 0x00(a0), s_fixup)
202         daddu   a1, a1, 0x4
203         daddu   a0, a0, 0x4
204         andi    t8, a1, 0x8
206 qword_align:
207         beqz    t8, oword_align
208          andi   t8, a1, 0x10
210         EX(lw, ta0, 0x00(a1), l_fixup)
211         EX(lw, ta1, 0x04(a1), l_fixup)
212         dsubu   a2, a2, 0x8
213         EX(sw, ta0, 0x00(a0), s_fixup)
214         EX(sw, ta1, 0x04(a0), s_fixup)
215         daddu   a1, a1, 0x8
216         andi    t8, a1, 0x10
217         daddu   a0, a0, 0x8
219 oword_align:
220         beqz    t8, begin_movement
221          srl    t8, a2, 0x7
223         EX(lw, ta3, 0x00(a1), l_fixup)
224         EX(lw, t0, 0x04(a1), l_fixup)
225         EX(lw, ta0, 0x08(a1), l_fixup)
226         EX(lw, ta1, 0x0c(a1), l_fixup)
227         EX(sw, ta3, 0x00(a0), s_fixup)
228         EX(sw, t0, 0x04(a0), s_fixup)
229         EX(sw, ta0, 0x08(a0), s_fixup)
230         EX(sw, ta1, 0x0c(a0), s_fixup)
231         dsubu   a2, a2, 0x10
232         daddu   a1, a1, 0x10
233         srl     t8, a2, 0x7
234         daddu   a0, a0, 0x10
236 begin_movement:
237         beqz    t8, 0f
238          andi   ta2, a2, 0x40
240 move_128bytes:
241         pref    0, 2*128(a0)
242         pref    1, 2*128(a1)
243         MOVE_BIGGERCHUNK(a1, a0, 0x00, ta0, ta1, ta3, t0)
244         MOVE_BIGGERCHUNK(a1, a0, 0x40, ta0, ta1, ta3, t0)
245         dsubu   t8, t8, 0x01
246         daddu   a1, a1, 0x80
247         bnez    t8, move_128bytes
248          daddu  a0, a0, 0x80
251         beqz    ta2, 1f
252          andi   ta2, a2, 0x20
254 move_64bytes:
255         MOVE_BIGGERCHUNK(a1, a0, 0x00, ta0, ta1, ta3, t0)
256         daddu   a1, a1, 0x40
257         daddu   a0, a0, 0x40
260         beqz    ta2, do_end_words
261          andi   t8, a2, 0x1c
263 move_32bytes:
264         MOVE_BIGCHUNK(a1, a0, 0x00, ta0, ta1, ta3, t0)
265         andi    t8, a2, 0x1c
266         daddu   a1, a1, 0x20
267         daddu   a0, a0, 0x20
269 do_end_words:
270         beqz    t8, maybe_end_cruft
271          srl    t8, t8, 0x2
273 end_words:
274         EX(lw, ta0, (a1), l_fixup)
275         dsubu   t8, t8, 0x1
276         EX(sw, ta0, (a0), s_fixup)
277         daddu   a1, a1, 0x4
278         bnez    t8, end_words
279          daddu  a0, a0, 0x4
281 maybe_end_cruft:
282         andi    ta2, a2, 0x3
284 small_memcpy:
285         beqz    ta2, out
286          move   a2, ta2
288 end_bytes:
289         EX(lb, ta0, (a1), l_fixup)
290         dsubu   a2, a2, 0x1
291         EX(sb, ta0, (a0), s_fixup)
292         daddu   a1, a1, 0x1
293         bnez    a2, end_bytes
294          daddu  a0, a0, 0x1
296 out:    jr      ra
297          move   a2, zero
299 /* ------------------------------------------------------------------------- */
301 /* Bad, bad.  At least try to align the source  */
303 memcpy_u_src:
304         bnez    t8, small_memcpy                # < 8 bytes?
305          move   ta2, a2
307         daddiu  ta0, a1, 7                      # ta0: how much to align
308         ori     ta0, 7
309         xori    ta0, 7
310         dsubu   ta0, a1
312         UEXD(uld, ta1, 0(a1), l_fixup)          # dword alignment
313         UEXD(usd, ta1, 0(a0), s_fixup)
315         daddu   a1, ta0                         # src
316         daddu   a0, ta0                         # dst
317         dsubu   a2, ta0                         # len
319         sltiu   t8, a2, 56
320         bnez    t8, u_do_end_words
321          andi   t8, a2, 0x3c
323         andi    t8, a1, 8                       # now qword aligned?
325 u_qword_align:
326         beqz    t8, u_oword_align
327          andi   t8, a1, 0x10
329         EX(ld, ta0, 0x00(a1), l_fixup)
330         dsubu   a2, a2, 0x8
331         UEXD(usd, ta0, 0x00(a0), s_fixup)
332         daddu   a1, a1, 0x8
333         andi    t8, a1, 0x10
334         daddu   a0, a0, 0x8
336 u_oword_align:
337         beqz    t8, u_begin_movement
338          srl    t8, a2, 0x7
340         EX(lw, ta3, 0x08(a1), l_fixup)
341         EX(lw, t0, 0x0c(a1), l_fixup)
342         EX(lw, ta0, 0x00(a1), l_fixup)
343         EX(lw, ta1, 0x04(a1), l_fixup)
344         UEX(usw, ta3, 0x08(a0), s_fixup)
345         UEX(usw, t0, 0x0c(a0), s_fixup)
346         UEX(usw, ta0, 0x00(a0), s_fixup)
347         UEX(usw, ta1, 0x04(a0), s_fixup)
348         dsubu   a2, a2, 0x10
349         daddu   a1, a1, 0x10
350         srl     t8, a2, 0x7
351         daddu   a0, a0, 0x10
353 u_begin_movement:
354         beqz    t8, 0f
355          andi   ta2, a2, 0x40
357 u_move_128bytes:
358         UMOVE_BIGGERCHUNK(a1, a0, 0x00, ta0, ta1, ta3, t0)
359         UMOVE_BIGGERCHUNK(a1, a0, 0x40, ta0, ta1, ta3, t0)
360         dsubu   t8, t8, 0x01
361         daddu   a1, a1, 0x80
362         bnez    t8, u_move_128bytes
363          daddu  a0, a0, 0x80
366         beqz    ta2, 1f
367          andi   ta2, a2, 0x20
369 u_move_64bytes:
370         UMOVE_BIGGERCHUNK(a1, a0, 0x00, ta0, ta1, ta3, t0)
371         daddu   a1, a1, 0x40
372         daddu   a0, a0, 0x40
375         beqz    ta2, u_do_end_words
376          andi   t8, a2, 0x1c
378 u_move_32bytes:
379         UMOVE_BIGCHUNK(a1, a0, 0x00, ta0, ta1, ta3, t0)
380         andi    t8, a2, 0x1c
381         daddu   a1, a1, 0x20
382         daddu   a0, a0, 0x20
384 u_do_end_words:
385         beqz    t8, u_maybe_end_cruft
386          srl    t8, t8, 0x2
388 u_end_words:
389         EX(lw, ta0, 0x00(a1), l_fixup)
390         dsubu   t8, t8, 0x1
391         UEX(usw, ta0, 0x00(a0), s_fixup)
392         daddu   a1, a1, 0x4
393         bnez    t8, u_end_words
394          daddu  a0, a0, 0x4
396 u_maybe_end_cruft:
397         andi    ta2, a2, 0x3
399 u_cannot_optimize:
400         beqz    ta2, out
401          move   a2, ta2
403 u_end_bytes:
404         EX(lb, ta0, (a1), l_fixup)
405         dsubu   a2, a2, 0x1
406         EX(sb, ta0, (a0), s_fixup)
407         daddu   a1, a1, 0x1
408         bnez    a2, u_end_bytes
409          daddu  a0, a0, 0x1
411         jr      ra
412          move   a2, zero
413         END(memcpy)
415 /* descending order, destination aligned  */
416 #define RMOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3) \
417         lw      t0, (offset + 0x10)(src); \
418         lw      t1, (offset + 0x14)(src); \
419         lw      t2, (offset + 0x18)(src); \
420         lw      t3, (offset + 0x1c)(src); \
421         sw      t0, (offset + 0x10)(dst); \
422         sw      t1, (offset + 0x14)(dst); \
423         sw      t2, (offset + 0x18)(dst); \
424         sw      t3, (offset + 0x1c)(dst); \
425         lw      t0, (offset + 0x00)(src); \
426         lw      t1, (offset + 0x04)(src); \
427         lw      t2, (offset + 0x08)(src); \
428         lw      t3, (offset + 0x0c)(src); \
429         sw      t0, (offset + 0x00)(dst); \
430         sw      t1, (offset + 0x04)(dst); \
431         sw      t2, (offset + 0x08)(dst); \
432         sw      t3, (offset + 0x0c)(dst)
434 /* descending order, destination ununaligned  */
435 #define RUMOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3) \
436         lw      t0, (offset + 0x10)(src); \
437         lw      t1, (offset + 0x14)(src); \
438         lw      t2, (offset + 0x18)(src); \
439         lw      t3, (offset + 0x1c)(src); \
440         usw     t0, (offset + 0x10)(dst); \
441         usw     t1, (offset + 0x14)(dst); \
442         usw     t2, (offset + 0x18)(dst); \
443         usw     t3, (offset + 0x1c)(dst); \
444         lw      t0, (offset + 0x00)(src); \
445         lw      t1, (offset + 0x04)(src); \
446         lw      t2, (offset + 0x08)(src); \
447         lw      t3, (offset + 0x0c)(src); \
448         usw     t0, (offset + 0x00)(dst); \
449         usw     t1, (offset + 0x04)(dst); \
450         usw     t2, (offset + 0x08)(dst); \
451         usw     t3, (offset + 0x0c)(dst)
453         .align  5
454 LEAF(memmove)
455         sltu    ta0, a0, a1                     # dst < src -> memcpy
456         bnez    ta0, memcpy
457          daddu  v0, a0, a2
458         sltu    ta0, v0, a1                     # dst + len < src -> non-
459         bnez    ta0, __memcpy                   # overlapping, can use memcpy
460          move   v0, a0                          /* return value */
461         END(memmove)
463 LEAF(__rmemcpy)                                 /* a0=dst a1=src a2=len */
464         daddu   a0, a2                          # dst = dst + len
465         daddu   a1, a2                          # src = src + len
467 #if 0 /* Horror fix */
468         xor     ta0, a0, a1
469         andi    ta0, ta0, 0x3
470         move    t3, a0
471         beqz    ta0, r_can_align
472          sltiu  t8, a2, 0x8
474         b       r_memcpy_u_src                  # bad alignment
475          move   ta2, a2
477 r_can_align:
478         bnez    t8, r_small_memcpy              # < 8 bytes to copy
479          move   ta2, a2
481         beqz    a2, r_out
482          andi   t8, a1, 0x1
484 r_hword_align:
485         beqz    t8, r_word_align
486          andi   t8, a1, 0x2
488         lb      ta0, -1(a1)
489         dsubu   a2, a2, 0x1
490         sb      ta0, -1(a0)
491         dsubu   a1, a1, 0x1
492         dsubu   a0, a0, 0x1
493         andi    t8, a1, 0x2
495 r_word_align:
496         beqz    t8, r_dword_align
497          sltiu  t8, a2, 56
498         
499         lh      ta0, -2(a1)
500         dsubu   a2, a2, 0x2
501         sh      ta0, -2(a0)
502         sltiu   t8, a2, 56
503         dsubu   a0, a0, 0x2
504         dsubu   a1, a1, 0x2
506 r_dword_align:
507         bnez    t8, r_do_end_words
508          move   t8, a2
510         andi    t8, a1, 0x4
511         beqz    t8, r_qword_align
512          andi   t8, a1, 0x8
514         lw      ta0, -4(a1)
515         dsubu   a2, a2, 0x4
516         sw      ta0, -4(a0)
517         dsubu   a1, a1, 0x4
518         dsubu   a0, a0, 0x4
519         andi    t8, a1, 0x8
521 r_qword_align:
522         beqz    t8, r_oword_align
523          andi   t8, a1, 0x10
525         dsubu   a1, a1, 0x8
526         lw      ta0, 0x04(a1)
527         lw      ta1, 0x00(a1)
528         dsubu   a0, a0, 0x8
529         sw      ta0, 0x04(a0)
530         sw      ta1, 0x00(a0)
531         dsubu   a2, a2, 0x8
533         andi    t8, a1, 0x10
535 r_oword_align:
536         beqz    t8, r_begin_movement
537          srl    t8, a2, 0x7
539         dsubu   a1, a1, 0x10
540         lw      ta3, 0x08(a1)                   # assumes subblock ordering
541         lw      t0, 0x0c(a1)
542         lw      ta0, 0x00(a1)
543         lw      ta1, 0x04(a1)
544         dsubu   a0, a0, 0x10
545         sw      ta3, 0x08(a0)
546         sw      t0, 0x0c(a0)
547         sw      ta0, 0x00(a0)
548         sw      ta1, 0x04(a0)
549         dsubu   a2, a2, 0x10
550         srl     t8, a2, 0x7
552 r_begin_movement:
553         beqz    t8, 0f
554          andi   ta2, a2, 0x40
556 r_move_128bytes:
557         RMOVE_BIGCHUNK(a1, a0, -0x80, ta0, ta1, ta3, t0)
558         RMOVE_BIGCHUNK(a1, a0, -0x60, ta0, ta1, ta3, t0)
559         RMOVE_BIGCHUNK(a1, a0, -0x40, ta0, ta1, ta3, t0)
560         RMOVE_BIGCHUNK(a1, a0, -0x20, ta0, ta1, ta3, t0)
561         dsubu   t8, t8, 0x01
562         dsubu   a1, a1, 0x80
563         bnez    t8, r_move_128bytes
564          dsubu  a0, a0, 0x80
567         beqz    ta2, 1f
568          andi   ta2, a2, 0x20
570 r_move_64bytes:
571         dsubu   a1, a1, 0x40
572         dsubu   a0, a0, 0x40
573         RMOVE_BIGCHUNK(a1, a0, 0x20, ta0, ta1, ta3, t0)
574         RMOVE_BIGCHUNK(a1, a0, 0x00, ta0, ta1, ta3, t0)
577         beqz    ta2, r_do_end_words
578          andi   t8, a2, 0x1c
580 r_move_32bytes:
581         dsubu   a1, a1, 0x20
582         dsubu   a0, a0, 0x20
583         RMOVE_BIGCHUNK(a1, a0, 0x00, ta0, ta1, ta3, t0)
584         andi    t8, a2, 0x1c
586 r_do_end_words:
587         beqz    t8, r_maybe_end_cruft
588          srl    t8, t8, 0x2
590 r_end_words:
591         lw      ta0, -4(a1)
592         dsubu   t8, t8, 0x1
593         sw      ta0, -4(a0)
594         dsubu   a1, a1, 0x4
595         bnez    t8, r_end_words
596          dsubu  a0, a0, 0x4
598 r_maybe_end_cruft:
599         andi    ta2, a2, 0x3
601 r_small_memcpy:
602         beqz    ta2, r_out
603          move   a2, ta2
604 #endif /* Horror fix */
606 r_end_bytes:
607         lb      ta0, -1(a1)
608         dsubu   a2, a2, 0x1
609         sb      ta0, -1(a0)
610         dsubu   a1, a1, 0x1
611         bnez    a2, r_end_bytes
612          dsubu  a0, a0, 0x1
614 r_out:
615         jr      ra
616          move   a2, zero
618 #if 0 /* Horror fix */
619 /* ------------------------------------------------------------------------- */
621 /* Bad, bad.  At least try to align the source  */
623 r_memcpy_u_src:
624         bnez    t8, r_small_memcpy              # < 8 bytes?
625          move   ta2, a2
627         andi    ta0, a1, 7                      # ta0: how much to align
629         ulw     ta1, -8(a1)                     # dword alignment
630         ulw     ta2, -4(a1)
631         usw     ta1, -8(a0)
632         usw     ta2, -4(a0)
634         dsubu   a1, ta0                         # src
635         dsubu   a0, ta0                         # dst
636         dsubu   a2, ta0                         # len
638         sltiu   t8, a2, 56
639         bnez    t8, ru_do_end_words
640          andi   t8, a2, 0x3c
642         andi    t8, a1, 8                       # now qword aligned?
644 ru_qword_align:
645         beqz    t8, ru_oword_align
646          andi   t8, a1, 0x10
648         dsubu   a1, a1, 0x8
649         lw      ta0, 0x00(a1)
650         lw      ta1, 0x04(a1)
651         dsubu   a0, a0, 0x8
652         usw     ta0, 0x00(a0)
653         usw     ta1, 0x04(a0)
654         dsubu   a2, a2, 0x8
656         andi    t8, a1, 0x10
658 ru_oword_align:
659         beqz    t8, ru_begin_movement
660          srl    t8, a2, 0x7
662         dsubu   a1, a1, 0x10
663         lw      ta3, 0x08(a1)                   # assumes subblock ordering
664         lw      t0, 0x0c(a1)
665         lw      ta0, 0x00(a1)
666         lw      ta1, 0x04(a1)
667         dsubu   a0, a0, 0x10
668         usw     ta3, 0x08(a0)
669         usw     t0, 0x0c(a0)
670         usw     ta0, 0x00(a0)
671         usw     ta1, 0x04(a0)
672         dsubu   a2, a2, 0x10
674         srl     t8, a2, 0x7
676 ru_begin_movement:
677         beqz    t8, 0f
678          andi   ta2, a2, 0x40
680 ru_move_128bytes:
681         RUMOVE_BIGCHUNK(a1, a0, -0x80, ta0, ta1, ta3, t0)
682         RUMOVE_BIGCHUNK(a1, a0, -0x60, ta0, ta1, ta3, t0)
683         RUMOVE_BIGCHUNK(a1, a0, -0x40, ta0, ta1, ta3, t0)
684         RUMOVE_BIGCHUNK(a1, a0, -0x20, ta0, ta1, ta3, t0)
685         dsubu   t8, t8, 0x01
686         dsubu   a1, a1, 0x80
687         bnez    t8, ru_move_128bytes
688          dsubu  a0, a0, 0x80
691         beqz    ta2, 1f
692          andi   ta2, a2, 0x20
694 ru_move_64bytes:
695         dsubu   a1, a1, 0x40
696         dsubu   a0, a0, 0x40
697         RUMOVE_BIGCHUNK(a1, a0, 0x20, ta0, ta1, ta3, t0)
698         RUMOVE_BIGCHUNK(a1, a0, 0x00, ta0, ta1, ta3, t0)
701         beqz    ta2, ru_do_end_words
702          andi   t8, a2, 0x1c
704 ru_move_32bytes:
705         dsubu   a1, a1, 0x20
706         dsubu   a0, a0, 0x20
707         RUMOVE_BIGCHUNK(a1, a0, 0x00, ta0, ta1, ta3, t0)
708         andi    t8, a2, 0x1c
710 ru_do_end_words:
711         beqz    t8, ru_maybe_end_cruft
712          srl    t8, t8, 0x2
714 ru_end_words:
715         lw      ta0, -4(a1)
716         usw     ta0, -4(a0)
717         dsubu   t8, t8, 0x1
718         dsubu   a1, a1, 0x4
719         bnez    t8, ru_end_words
720          dsubu  a0, a0, 0x4
722 ru_maybe_end_cruft:
723         andi    ta2, a2, 0x3
725 ru_cannot_optimize:
726         beqz    ta2, r_out
727          move   a2, ta2
729 ru_end_bytes:
730         lb      ta0, -1(a1)
731         dsubu   a2, a2, 0x1
732         sb      ta0, -1(a0)
733         dsubu   a1, a1, 0x1
734         bnez    a2, ru_end_bytes
735          dsubu  a0, a0, 0x1
737         jr      ra
738          move   a2, zero
739 #endif /* Horror fix */
740         END(__rmemcpy)
742 l_fixup:                                        # clear the rest of the buffer
743         ld      ta0, THREAD_BUADDR($28)
744          nop
745         dsubu   a2, AT, ta0                     # a2 bytes to go
746         daddu   a0, ta0                         # compute start address in a1
747         dsubu   a0, a1
748         j       __bzero
749          move   a1, zero
751 s_fixup:
752         jr      ra
753          nop