1/* Copyright (c) 2012, Linaro Limited
2   All rights reserved.
3
4   Redistribution and use in source and binary forms, with or without
5   modification, are permitted provided that the following conditions are met:
6       * Redistributions of source code must retain the above copyright
7         notice, this list of conditions and the following disclaimer.
8       * Redistributions in binary form must reproduce the above copyright
9         notice, this list of conditions and the following disclaimer in the
10         documentation and/or other materials provided with the distribution.
11       * Neither the name of the Linaro nor the
12         names of its contributors may be used to endorse or promote products
13         derived from this software without specific prior written permission.
14
15   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19   HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28/* Assumptions:
29 *
30 * ARMv8-a, AArch64
31 * Unaligned accesses
32 *
33 */
34
35/* By default we assume that the DC instruction can be used to zero
36   data blocks more efficiently.  In some circumstances this might be
37   unsafe, for example in an asymmetric multiprocessor environment with
38   different DC clear lengths (neither the upper nor lower lengths are
39   safe to use). */
40
41#define dst  		x0
42#define count		x2
43#define tmp1		x3
44#define tmp1w		w3
45#define tmp2		x4
46#define tmp2w		w4
47#define zva_len_x	x5
48#define zva_len		w5
49#define zva_bits_x	x6
50
51#define A_l		x1
52#define A_lw		w1
53#define tmp3w		w9
54
55#define ENTRY(f) \
56  .text; \
57  .globl f; \
58  .align 0; \
59  .type f, %function; \
60  f: \
61  .cfi_startproc \
62
63#define END(f) \
64  .cfi_endproc; \
65  .size f, .-f; \
66
67ENTRY(android_memset16)
68	ands   A_lw, A_lw, #0xffff
69	b.eq	.Lzero_mem
70	orr	A_lw, A_lw, A_lw, lsl #16
71	b .Lexpand_to_64
72END(android_memset16)
73
74ENTRY(android_memset32)
75	cmp	    A_lw, #0
76	b.eq	.Lzero_mem
77.Lexpand_to_64:
78	orr	A_l, A_l, A_l, lsl #32
79.Ltail_maybe_long:
80	cmp	count, #64
81	b.ge	.Lnot_short
82.Ltail_maybe_tiny:
83	cmp	count, #15
84	b.le	.Ltail15tiny
85.Ltail63:
86	ands	tmp1, count, #0x30
87	b.eq	.Ltail15
88	add	dst, dst, tmp1
89	cmp	tmp1w, #0x20
90	b.eq	1f
91	b.lt	2f
92	stp	A_l, A_l, [dst, #-48]
931:
94	stp	A_l, A_l, [dst, #-32]
952:
96	stp	A_l, A_l, [dst, #-16]
97
98.Ltail15:
99	and	count, count, #15
100	add	dst, dst, count
101	stp	A_l, A_l, [dst, #-16]	/* Repeat some/all of last store. */
102	ret
103
104.Ltail15tiny:
105	/* Set up to 15 bytes.  Does not assume earlier memory
106	   being set.  */
107	tbz	count, #3, 1f
108	str	A_l, [dst], #8
1091:
110	tbz	count, #2, 1f
111	str	A_lw, [dst], #4
1121:
113	tbz	count, #1, 1f
114	strh	A_lw, [dst], #2
1151:
116	ret
117
118	/* Critical loop.  Start at a new cache line boundary.  Assuming
119	 * 64 bytes per line, this ensures the entire loop is in one line.  */
120	.p2align 6
121.Lnot_short:
122	neg	tmp2, dst
123	ands	tmp2, tmp2, #15
124	b.eq	2f
125	/* Bring DST to 128-bit (16-byte) alignment.  We know that there's
126	 * more than that to set, so we simply store 16 bytes and advance by
127	 * the amount required to reach alignment.  */
128	sub	count, count, tmp2
129	stp	A_l, A_l, [dst]
130	add	dst, dst, tmp2
131	/* There may be less than 63 bytes to go now.  */
132	cmp	count, #63
133	b.le	.Ltail63
1342:
135	sub	dst, dst, #16		/* Pre-bias.  */
136	sub	count, count, #64
1371:
138	stp	A_l, A_l, [dst, #16]
139	stp	A_l, A_l, [dst, #32]
140	stp	A_l, A_l, [dst, #48]
141	stp	A_l, A_l, [dst, #64]!
142	subs	count, count, #64
143	b.ge	1b
144	tst	count, #0x3f
145	add	dst, dst, #16
146	b.ne	.Ltail63
147	ret
148
149	/* For zeroing memory, check to see if we can use the ZVA feature to
150	 * zero entire 'cache' lines.  */
151.Lzero_mem:
152	mov	A_l, #0
153	cmp	count, #63
154	b.le	.Ltail_maybe_tiny
155	neg	tmp2, dst
156	ands	tmp2, tmp2, #15
157	b.eq	1f
158	sub	count, count, tmp2
159	stp	A_l, A_l, [dst]
160	add	dst, dst, tmp2
161	cmp	count, #63
162	b.le	.Ltail63
1631:
164	/* For zeroing small amounts of memory, it's not worth setting up
165	 * the line-clear code.  */
166	cmp	count, #128
167	b.lt	.Lnot_short
168	mrs	tmp1, dczid_el0
169	tbnz	tmp1, #4, .Lnot_short
170	mov	tmp3w, #4
171	and	zva_len, tmp1w, #15	/* Safety: other bits reserved.  */
172	lsl	zva_len, tmp3w, zva_len
173
174.Lzero_by_line:
175	/* Compute how far we need to go to become suitably aligned.  We're
176	 * already at quad-word alignment.  */
177	cmp	count, zva_len_x
178	b.lt	.Lnot_short		/* Not enough to reach alignment.  */
179	sub	zva_bits_x, zva_len_x, #1
180	neg	tmp2, dst
181	ands	tmp2, tmp2, zva_bits_x
182	b.eq	1f			/* Already aligned.  */
183	/* Not aligned, check that there's enough to copy after alignment.  */
184	sub	tmp1, count, tmp2
185	cmp	tmp1, #64
186	ccmp	tmp1, zva_len_x, #8, ge	/* NZCV=0b1000 */
187	b.lt	.Lnot_short
188	/* We know that there's at least 64 bytes to zero and that it's safe
189	 * to overrun by 64 bytes.  */
190	mov	count, tmp1
1912:
192	stp	A_l, A_l, [dst]
193	stp	A_l, A_l, [dst, #16]
194	stp	A_l, A_l, [dst, #32]
195	subs	tmp2, tmp2, #64
196	stp	A_l, A_l, [dst, #48]
197	add	dst, dst, #64
198	b.ge	2b
199	/* We've overrun a bit, so adjust dst downwards.  */
200	add	dst, dst, tmp2
2011:
202	sub	count, count, zva_len_x
2033:
204	dc	zva, dst
205	add	dst, dst, zva_len_x
206	subs	count, count, zva_len_x
207	b.ge	3b
208	ands	count, count, zva_bits_x
209	b.ne	.Ltail_maybe_long
210	ret
211END(android_memset32)
212