blob: d912e7397ecc94a190a132b649f667b94774c1b9 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/arch/arm/lib/memset.S
3 *
4 * Copyright (C) 1995-2000 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ASM optimised string functions
11 */
12#include <linux/linkage.h>
13#include <asm/assembler.h>
14
15 .text
16 .align 5
17 .word 0
18
191: subs r2, r2, #4 @ 1 do we have enough
20 blt 5f @ 1 bytes to align with?
21 cmp r3, #2 @ 1
Ivan Djelic455bd4c2013-03-06 20:09:27 +010022 strltb r1, [ip], #1 @ 1
23 strleb r1, [ip], #1 @ 1
24 strb r1, [ip], #1 @ 1
Linus Torvalds1da177e2005-04-16 15:20:36 -070025 add r2, r2, r3 @ 1 (r2 = r2 - (4 - r3))
26/*
27 * The pointer is now aligned and the length is adjusted. Try doing the
Russell King59f0cb02008-10-27 11:24:09 +000028 * memset again.
Linus Torvalds1da177e2005-04-16 15:20:36 -070029 */
30
31ENTRY(memset)
Ivan Djelic455bd4c2013-03-06 20:09:27 +010032/*
33 * Preserve the contents of r0 for the return value.
34 */
35 mov ip, r0
36 ands r3, ip, #3 @ 1 unaligned?
Linus Torvalds1da177e2005-04-16 15:20:36 -070037 bne 1b @ 1
38/*
Ivan Djelic455bd4c2013-03-06 20:09:27 +010039 * we know that the pointer in ip is aligned to a word boundary.
Linus Torvalds1da177e2005-04-16 15:20:36 -070040 */
41 orr r1, r1, r1, lsl #8
42 orr r1, r1, r1, lsl #16
43 mov r3, r1
44 cmp r2, #16
45 blt 4f
Nicolas Pitref91a8dc2008-04-11 21:04:28 -040046
47#if ! CALGN(1)+0
48
Linus Torvalds1da177e2005-04-16 15:20:36 -070049/*
Ivan Djelic455bd4c2013-03-06 20:09:27 +010050 * We need 2 extra registers for this loop - use r8 and the LR
Linus Torvalds1da177e2005-04-16 15:20:36 -070051 */
Ivan Djelic455bd4c2013-03-06 20:09:27 +010052 stmfd sp!, {r8, lr}
53 mov r8, r1
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 mov lr, r1
55
562: subs r2, r2, #64
Ivan Djelic455bd4c2013-03-06 20:09:27 +010057 stmgeia ip!, {r1, r3, r8, lr} @ 64 bytes at a time.
58 stmgeia ip!, {r1, r3, r8, lr}
59 stmgeia ip!, {r1, r3, r8, lr}
60 stmgeia ip!, {r1, r3, r8, lr}
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 bgt 2b
Ivan Djelic455bd4c2013-03-06 20:09:27 +010062 ldmeqfd sp!, {r8, pc} @ Now <64 bytes to go.
Linus Torvalds1da177e2005-04-16 15:20:36 -070063/*
64 * No need to correct the count; we're only testing bits from now on
65 */
66 tst r2, #32
Ivan Djelic455bd4c2013-03-06 20:09:27 +010067 stmneia ip!, {r1, r3, r8, lr}
68 stmneia ip!, {r1, r3, r8, lr}
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 tst r2, #16
Ivan Djelic455bd4c2013-03-06 20:09:27 +010070 stmneia ip!, {r1, r3, r8, lr}
71 ldmfd sp!, {r8, lr}
Linus Torvalds1da177e2005-04-16 15:20:36 -070072
Nicolas Pitref91a8dc2008-04-11 21:04:28 -040073#else
74
75/*
76 * This version aligns the destination pointer in order to write
77 * whole cache lines at once.
78 */
79
Ivan Djelic455bd4c2013-03-06 20:09:27 +010080 stmfd sp!, {r4-r8, lr}
Nicolas Pitref91a8dc2008-04-11 21:04:28 -040081 mov r4, r1
82 mov r5, r1
83 mov r6, r1
84 mov r7, r1
Ivan Djelic455bd4c2013-03-06 20:09:27 +010085 mov r8, r1
Nicolas Pitref91a8dc2008-04-11 21:04:28 -040086 mov lr, r1
87
88 cmp r2, #96
Ivan Djelic455bd4c2013-03-06 20:09:27 +010089 tstgt ip, #31
Nicolas Pitref91a8dc2008-04-11 21:04:28 -040090 ble 3f
91
Ivan Djelic455bd4c2013-03-06 20:09:27 +010092 and r8, ip, #31
93 rsb r8, r8, #32
94 sub r2, r2, r8
95 movs r8, r8, lsl #(32 - 4)
96 stmcsia ip!, {r4, r5, r6, r7}
97 stmmiia ip!, {r4, r5}
98 tst r8, #(1 << 30)
99 mov r8, r1
100 strne r1, [ip], #4
Nicolas Pitref91a8dc2008-04-11 21:04:28 -0400101
1023: subs r2, r2, #64
Ivan Djelic455bd4c2013-03-06 20:09:27 +0100103 stmgeia ip!, {r1, r3-r8, lr}
104 stmgeia ip!, {r1, r3-r8, lr}
Nicolas Pitref91a8dc2008-04-11 21:04:28 -0400105 bgt 3b
Ivan Djelic455bd4c2013-03-06 20:09:27 +0100106 ldmeqfd sp!, {r4-r8, pc}
Nicolas Pitref91a8dc2008-04-11 21:04:28 -0400107
108 tst r2, #32
Ivan Djelic455bd4c2013-03-06 20:09:27 +0100109 stmneia ip!, {r1, r3-r8, lr}
Nicolas Pitref91a8dc2008-04-11 21:04:28 -0400110 tst r2, #16
Ivan Djelic455bd4c2013-03-06 20:09:27 +0100111 stmneia ip!, {r4-r7}
112 ldmfd sp!, {r4-r8, lr}
Nicolas Pitref91a8dc2008-04-11 21:04:28 -0400113
114#endif
115
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164: tst r2, #8
Ivan Djelic455bd4c2013-03-06 20:09:27 +0100117 stmneia ip!, {r1, r3}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 tst r2, #4
Ivan Djelic455bd4c2013-03-06 20:09:27 +0100119 strne r1, [ip], #4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120/*
121 * When we get here, we've got less than 4 bytes to zero. We
122 * may have an unaligned pointer as well.
123 */
1245: tst r2, #2
Ivan Djelic455bd4c2013-03-06 20:09:27 +0100125 strneb r1, [ip], #1
126 strneb r1, [ip], #1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 tst r2, #1
Ivan Djelic455bd4c2013-03-06 20:09:27 +0100128 strneb r1, [ip], #1
Russell King7999d8d2006-06-25 11:17:23 +0100129 mov pc, lr
Catalin Marinas93ed3972008-08-28 11:22:32 +0100130ENDPROC(memset)