1 /*
2  * ChaCha/XChaCha NEON helper functions
3  *
4  * Copyright (C) 2016 Linaro, Ltd. <ard.biesheuvel@linaro.org>
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  * Based on:
11  * ChaCha20 256-bit cipher algorithm, RFC7539, x64 SSE3 functions
12  *
13  * Copyright (C) 2015 Martin Willi
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 2 of the License, or
18  * (at your option) any later version.
19  */
20 
21  /*
22   * NEON doesn't have a rotate instruction.  The alternatives are, more or less:
23   *
24   * (a)  vshl.u32 + vsri.u32		(needs temporary register)
25   * (b)  vshl.u32 + vshr.u32 + vorr	(needs temporary register)
26   * (c)  vrev32.16			(16-bit rotations only)
27   * (d)  vtbl.8 + vtbl.8		(multiple of 8 bits rotations only,
28   *					 needs index vector)
29   *
30   * ChaCha has 16, 12, 8, and 7-bit rotations.  For the 12 and 7-bit rotations,
31   * the only choices are (a) and (b).  We use (a) since it takes two-thirds the
32   * cycles of (b) on both Cortex-A7 and Cortex-A53.
33   *
34   * For the 16-bit rotation, we use vrev32.16 since it's consistently fastest
35   * and doesn't need a temporary register.
36   *
37   * For the 8-bit rotation, we use vtbl.8 + vtbl.8.  On Cortex-A7, this sequence
38   * is twice as fast as (a), even when doing (a) on multiple registers
39   * simultaneously to eliminate the stall between vshl and vsri.  Also, it
40   * parallelizes better when temporary registers are scarce.
41   *
42   * A disadvantage is that on Cortex-A53, the vtbl sequence is the same speed as
43   * (a), so the need to load the rotation table actually makes the vtbl method
44   * slightly slower overall on that CPU (~1.3% slower ChaCha20).  Still, it
45   * seems to be a good compromise to get a more significant speed boost on some
46   * CPUs, e.g. ~4.8% faster ChaCha20 on Cortex-A7.
47   */
48 
49 #include <linux/linkage.h>
50 #include <asm/cache.h>
51 
52 	.text
53 	.fpu		neon
54 	.align		5
55 
56 /*
57  * chacha_permute - permute one block
58  *
59  * Permute one 64-byte block where the state matrix is stored in the four NEON
60  * registers q0-q3.  It performs matrix operations on four words in parallel,
61  * but requires shuffling to rearrange the words after each round.
62  *
63  * The round count is given in r3.
64  *
65  * Clobbers: r3, ip, q4-q5
66  */
67 chacha_permute:
68 
69 	adr		ip, .Lrol8_table
70 	vld1.8		{d10}, [ip, :64]
71 
72 .Ldoubleround:
73 	// x0 += x1, x3 = rotl32(x3 ^ x0, 16)
74 	vadd.i32	q0, q0, q1
75 	veor		q3, q3, q0
76 	vrev32.16	q3, q3
77 
78 	// x2 += x3, x1 = rotl32(x1 ^ x2, 12)
79 	vadd.i32	q2, q2, q3
80 	veor		q4, q1, q2
81 	vshl.u32	q1, q4, #12
82 	vsri.u32	q1, q4, #20
83 
84 	// x0 += x1, x3 = rotl32(x3 ^ x0, 8)
85 	vadd.i32	q0, q0, q1
86 	veor		q3, q3, q0
87 	vtbl.8		d6, {d6}, d10
88 	vtbl.8		d7, {d7}, d10
89 
90 	// x2 += x3, x1 = rotl32(x1 ^ x2, 7)
91 	vadd.i32	q2, q2, q3
92 	veor		q4, q1, q2
93 	vshl.u32	q1, q4, #7
94 	vsri.u32	q1, q4, #25
95 
96 	// x1 = shuffle32(x1, MASK(0, 3, 2, 1))
97 	vext.8		q1, q1, q1, #4
98 	// x2 = shuffle32(x2, MASK(1, 0, 3, 2))
99 	vext.8		q2, q2, q2, #8
100 	// x3 = shuffle32(x3, MASK(2, 1, 0, 3))
101 	vext.8		q3, q3, q3, #12
102 
103 	// x0 += x1, x3 = rotl32(x3 ^ x0, 16)
104 	vadd.i32	q0, q0, q1
105 	veor		q3, q3, q0
106 	vrev32.16	q3, q3
107 
108 	// x2 += x3, x1 = rotl32(x1 ^ x2, 12)
109 	vadd.i32	q2, q2, q3
110 	veor		q4, q1, q2
111 	vshl.u32	q1, q4, #12
112 	vsri.u32	q1, q4, #20
113 
114 	// x0 += x1, x3 = rotl32(x3 ^ x0, 8)
115 	vadd.i32	q0, q0, q1
116 	veor		q3, q3, q0
117 	vtbl.8		d6, {d6}, d10
118 	vtbl.8		d7, {d7}, d10
119 
120 	// x2 += x3, x1 = rotl32(x1 ^ x2, 7)
121 	vadd.i32	q2, q2, q3
122 	veor		q4, q1, q2
123 	vshl.u32	q1, q4, #7
124 	vsri.u32	q1, q4, #25
125 
126 	// x1 = shuffle32(x1, MASK(2, 1, 0, 3))
127 	vext.8		q1, q1, q1, #12
128 	// x2 = shuffle32(x2, MASK(1, 0, 3, 2))
129 	vext.8		q2, q2, q2, #8
130 	// x3 = shuffle32(x3, MASK(0, 3, 2, 1))
131 	vext.8		q3, q3, q3, #4
132 
133 	subs		r3, r3, #2
134 	bne		.Ldoubleround
135 
136 	bx		lr
137 ENDPROC(chacha_permute)
138 
139 ENTRY(chacha_block_xor_neon)
140 	// r0: Input state matrix, s
141 	// r1: 1 data block output, o
142 	// r2: 1 data block input, i
143 	// r3: nrounds
144 	push		{lr}
145 
146 	// x0..3 = s0..3
147 	add		ip, r0, #0x20
148 	vld1.32		{q0-q1}, [r0]
149 	vld1.32		{q2-q3}, [ip]
150 
151 	vmov		q8, q0
152 	vmov		q9, q1
153 	vmov		q10, q2
154 	vmov		q11, q3
155 
156 	bl		chacha_permute
157 
158 	add		ip, r2, #0x20
159 	vld1.8		{q4-q5}, [r2]
160 	vld1.8		{q6-q7}, [ip]
161 
162 	// o0 = i0 ^ (x0 + s0)
163 	vadd.i32	q0, q0, q8
164 	veor		q0, q0, q4
165 
166 	// o1 = i1 ^ (x1 + s1)
167 	vadd.i32	q1, q1, q9
168 	veor		q1, q1, q5
169 
170 	// o2 = i2 ^ (x2 + s2)
171 	vadd.i32	q2, q2, q10
172 	veor		q2, q2, q6
173 
174 	// o3 = i3 ^ (x3 + s3)
175 	vadd.i32	q3, q3, q11
176 	veor		q3, q3, q7
177 
178 	add		ip, r1, #0x20
179 	vst1.8		{q0-q1}, [r1]
180 	vst1.8		{q2-q3}, [ip]
181 
182 	pop		{pc}
183 ENDPROC(chacha_block_xor_neon)
184 
185 ENTRY(hchacha_block_neon)
186 	// r0: Input state matrix, s
187 	// r1: output (8 32-bit words)
188 	// r2: nrounds
189 	push		{lr}
190 
191 	vld1.32		{q0-q1}, [r0]!
192 	vld1.32		{q2-q3}, [r0]
193 
194 	mov		r3, r2
195 	bl		chacha_permute
196 
197 	vst1.32		{q0}, [r1]!
198 	vst1.32		{q3}, [r1]
199 
200 	pop		{pc}
201 ENDPROC(hchacha_block_neon)
202 
203 	.align		4
204 .Lctrinc:	.word	0, 1, 2, 3
205 .Lrol8_table:	.byte	3, 0, 1, 2, 7, 4, 5, 6
206 
207 	.align		5
208 ENTRY(chacha_4block_xor_neon)
209 	push		{r4, lr}
210 	mov		r4, sp			// preserve the stack pointer
211 	sub		ip, sp, #0x20		// allocate a 32 byte buffer
212 	bic		ip, ip, #0x1f		// aligned to 32 bytes
213 	mov		sp, ip
214 
215 	// r0: Input state matrix, s
216 	// r1: 4 data blocks output, o
217 	// r2: 4 data blocks input, i
218 	// r3: nrounds
219 
220 	//
221 	// This function encrypts four consecutive ChaCha blocks by loading
222 	// the state matrix in NEON registers four times. The algorithm performs
223 	// each operation on the corresponding word of each state matrix, hence
224 	// requires no word shuffling. The words are re-interleaved before the
225 	// final addition of the original state and the XORing step.
226 	//
227 
228 	// x0..15[0-3] = s0..15[0-3]
229 	add		ip, r0, #0x20
230 	vld1.32		{q0-q1}, [r0]
231 	vld1.32		{q2-q3}, [ip]
232 
233 	adr		lr, .Lctrinc
234 	vdup.32		q15, d7[1]
235 	vdup.32		q14, d7[0]
236 	vld1.32		{q4}, [lr, :128]
237 	vdup.32		q13, d6[1]
238 	vdup.32		q12, d6[0]
239 	vdup.32		q11, d5[1]
240 	vdup.32		q10, d5[0]
241 	vadd.u32	q12, q12, q4		// x12 += counter values 0-3
242 	vdup.32		q9, d4[1]
243 	vdup.32		q8, d4[0]
244 	vdup.32		q7, d3[1]
245 	vdup.32		q6, d3[0]
246 	vdup.32		q5, d2[1]
247 	vdup.32		q4, d2[0]
248 	vdup.32		q3, d1[1]
249 	vdup.32		q2, d1[0]
250 	vdup.32		q1, d0[1]
251 	vdup.32		q0, d0[0]
252 
253 	adr		ip, .Lrol8_table
254 	b		1f
255 
256 .Ldoubleround4:
257 	vld1.32		{q8-q9}, [sp, :256]
258 1:
259 	// x0 += x4, x12 = rotl32(x12 ^ x0, 16)
260 	// x1 += x5, x13 = rotl32(x13 ^ x1, 16)
261 	// x2 += x6, x14 = rotl32(x14 ^ x2, 16)
262 	// x3 += x7, x15 = rotl32(x15 ^ x3, 16)
263 	vadd.i32	q0, q0, q4
264 	vadd.i32	q1, q1, q5
265 	vadd.i32	q2, q2, q6
266 	vadd.i32	q3, q3, q7
267 
268 	veor		q12, q12, q0
269 	veor		q13, q13, q1
270 	veor		q14, q14, q2
271 	veor		q15, q15, q3
272 
273 	vrev32.16	q12, q12
274 	vrev32.16	q13, q13
275 	vrev32.16	q14, q14
276 	vrev32.16	q15, q15
277 
278 	// x8 += x12, x4 = rotl32(x4 ^ x8, 12)
279 	// x9 += x13, x5 = rotl32(x5 ^ x9, 12)
280 	// x10 += x14, x6 = rotl32(x6 ^ x10, 12)
281 	// x11 += x15, x7 = rotl32(x7 ^ x11, 12)
282 	vadd.i32	q8, q8, q12
283 	vadd.i32	q9, q9, q13
284 	vadd.i32	q10, q10, q14
285 	vadd.i32	q11, q11, q15
286 
287 	vst1.32		{q8-q9}, [sp, :256]
288 
289 	veor		q8, q4, q8
290 	veor		q9, q5, q9
291 	vshl.u32	q4, q8, #12
292 	vshl.u32	q5, q9, #12
293 	vsri.u32	q4, q8, #20
294 	vsri.u32	q5, q9, #20
295 
296 	veor		q8, q6, q10
297 	veor		q9, q7, q11
298 	vshl.u32	q6, q8, #12
299 	vshl.u32	q7, q9, #12
300 	vsri.u32	q6, q8, #20
301 	vsri.u32	q7, q9, #20
302 
303 	// x0 += x4, x12 = rotl32(x12 ^ x0, 8)
304 	// x1 += x5, x13 = rotl32(x13 ^ x1, 8)
305 	// x2 += x6, x14 = rotl32(x14 ^ x2, 8)
306 	// x3 += x7, x15 = rotl32(x15 ^ x3, 8)
307 	vld1.8		{d16}, [ip, :64]
308 	vadd.i32	q0, q0, q4
309 	vadd.i32	q1, q1, q5
310 	vadd.i32	q2, q2, q6
311 	vadd.i32	q3, q3, q7
312 
313 	veor		q12, q12, q0
314 	veor		q13, q13, q1
315 	veor		q14, q14, q2
316 	veor		q15, q15, q3
317 
318 	vtbl.8		d24, {d24}, d16
319 	vtbl.8		d25, {d25}, d16
320 	vtbl.8		d26, {d26}, d16
321 	vtbl.8		d27, {d27}, d16
322 	vtbl.8		d28, {d28}, d16
323 	vtbl.8		d29, {d29}, d16
324 	vtbl.8		d30, {d30}, d16
325 	vtbl.8		d31, {d31}, d16
326 
327 	vld1.32		{q8-q9}, [sp, :256]
328 
329 	// x8 += x12, x4 = rotl32(x4 ^ x8, 7)
330 	// x9 += x13, x5 = rotl32(x5 ^ x9, 7)
331 	// x10 += x14, x6 = rotl32(x6 ^ x10, 7)
332 	// x11 += x15, x7 = rotl32(x7 ^ x11, 7)
333 	vadd.i32	q8, q8, q12
334 	vadd.i32	q9, q9, q13
335 	vadd.i32	q10, q10, q14
336 	vadd.i32	q11, q11, q15
337 
338 	vst1.32		{q8-q9}, [sp, :256]
339 
340 	veor		q8, q4, q8
341 	veor		q9, q5, q9
342 	vshl.u32	q4, q8, #7
343 	vshl.u32	q5, q9, #7
344 	vsri.u32	q4, q8, #25
345 	vsri.u32	q5, q9, #25
346 
347 	veor		q8, q6, q10
348 	veor		q9, q7, q11
349 	vshl.u32	q6, q8, #7
350 	vshl.u32	q7, q9, #7
351 	vsri.u32	q6, q8, #25
352 	vsri.u32	q7, q9, #25
353 
354 	vld1.32		{q8-q9}, [sp, :256]
355 
356 	// x0 += x5, x15 = rotl32(x15 ^ x0, 16)
357 	// x1 += x6, x12 = rotl32(x12 ^ x1, 16)
358 	// x2 += x7, x13 = rotl32(x13 ^ x2, 16)
359 	// x3 += x4, x14 = rotl32(x14 ^ x3, 16)
360 	vadd.i32	q0, q0, q5
361 	vadd.i32	q1, q1, q6
362 	vadd.i32	q2, q2, q7
363 	vadd.i32	q3, q3, q4
364 
365 	veor		q15, q15, q0
366 	veor		q12, q12, q1
367 	veor		q13, q13, q2
368 	veor		q14, q14, q3
369 
370 	vrev32.16	q15, q15
371 	vrev32.16	q12, q12
372 	vrev32.16	q13, q13
373 	vrev32.16	q14, q14
374 
375 	// x10 += x15, x5 = rotl32(x5 ^ x10, 12)
376 	// x11 += x12, x6 = rotl32(x6 ^ x11, 12)
377 	// x8 += x13, x7 = rotl32(x7 ^ x8, 12)
378 	// x9 += x14, x4 = rotl32(x4 ^ x9, 12)
379 	vadd.i32	q10, q10, q15
380 	vadd.i32	q11, q11, q12
381 	vadd.i32	q8, q8, q13
382 	vadd.i32	q9, q9, q14
383 
384 	vst1.32		{q8-q9}, [sp, :256]
385 
386 	veor		q8, q7, q8
387 	veor		q9, q4, q9
388 	vshl.u32	q7, q8, #12
389 	vshl.u32	q4, q9, #12
390 	vsri.u32	q7, q8, #20
391 	vsri.u32	q4, q9, #20
392 
393 	veor		q8, q5, q10
394 	veor		q9, q6, q11
395 	vshl.u32	q5, q8, #12
396 	vshl.u32	q6, q9, #12
397 	vsri.u32	q5, q8, #20
398 	vsri.u32	q6, q9, #20
399 
400 	// x0 += x5, x15 = rotl32(x15 ^ x0, 8)
401 	// x1 += x6, x12 = rotl32(x12 ^ x1, 8)
402 	// x2 += x7, x13 = rotl32(x13 ^ x2, 8)
403 	// x3 += x4, x14 = rotl32(x14 ^ x3, 8)
404 	vld1.8		{d16}, [ip, :64]
405 	vadd.i32	q0, q0, q5
406 	vadd.i32	q1, q1, q6
407 	vadd.i32	q2, q2, q7
408 	vadd.i32	q3, q3, q4
409 
410 	veor		q15, q15, q0
411 	veor		q12, q12, q1
412 	veor		q13, q13, q2
413 	veor		q14, q14, q3
414 
415 	vtbl.8		d30, {d30}, d16
416 	vtbl.8		d31, {d31}, d16
417 	vtbl.8		d24, {d24}, d16
418 	vtbl.8		d25, {d25}, d16
419 	vtbl.8		d26, {d26}, d16
420 	vtbl.8		d27, {d27}, d16
421 	vtbl.8		d28, {d28}, d16
422 	vtbl.8		d29, {d29}, d16
423 
424 	vld1.32		{q8-q9}, [sp, :256]
425 
426 	// x10 += x15, x5 = rotl32(x5 ^ x10, 7)
427 	// x11 += x12, x6 = rotl32(x6 ^ x11, 7)
428 	// x8 += x13, x7 = rotl32(x7 ^ x8, 7)
429 	// x9 += x14, x4 = rotl32(x4 ^ x9, 7)
430 	vadd.i32	q10, q10, q15
431 	vadd.i32	q11, q11, q12
432 	vadd.i32	q8, q8, q13
433 	vadd.i32	q9, q9, q14
434 
435 	vst1.32		{q8-q9}, [sp, :256]
436 
437 	veor		q8, q7, q8
438 	veor		q9, q4, q9
439 	vshl.u32	q7, q8, #7
440 	vshl.u32	q4, q9, #7
441 	vsri.u32	q7, q8, #25
442 	vsri.u32	q4, q9, #25
443 
444 	veor		q8, q5, q10
445 	veor		q9, q6, q11
446 	vshl.u32	q5, q8, #7
447 	vshl.u32	q6, q9, #7
448 	vsri.u32	q5, q8, #25
449 	vsri.u32	q6, q9, #25
450 
451 	subs		r3, r3, #2
452 	bne		.Ldoubleround4
453 
454 	// x0..7[0-3] are in q0-q7, x10..15[0-3] are in q10-q15.
455 	// x8..9[0-3] are on the stack.
456 
457 	// Re-interleave the words in the first two rows of each block (x0..7).
458 	// Also add the counter values 0-3 to x12[0-3].
459 	  vld1.32	{q8}, [lr, :128]	// load counter values 0-3
460 	vzip.32		q0, q1			// => (0 1 0 1) (0 1 0 1)
461 	vzip.32		q2, q3			// => (2 3 2 3) (2 3 2 3)
462 	vzip.32		q4, q5			// => (4 5 4 5) (4 5 4 5)
463 	vzip.32		q6, q7			// => (6 7 6 7) (6 7 6 7)
464 	  vadd.u32	q12, q8			// x12 += counter values 0-3
465 	vswp		d1, d4
466 	vswp		d3, d6
467 	  vld1.32	{q8-q9}, [r0]!		// load s0..7
468 	vswp		d9, d12
469 	vswp		d11, d14
470 
471 	// Swap q1 and q4 so that we'll free up consecutive registers (q0-q1)
472 	// after XORing the first 32 bytes.
473 	vswp		q1, q4
474 
475 	// First two rows of each block are (q0 q1) (q2 q6) (q4 q5) (q3 q7)
476 
477 	// x0..3[0-3] += s0..3[0-3]	(add orig state to 1st row of each block)
478 	vadd.u32	q0, q0, q8
479 	vadd.u32	q2, q2, q8
480 	vadd.u32	q4, q4, q8
481 	vadd.u32	q3, q3, q8
482 
483 	// x4..7[0-3] += s4..7[0-3]	(add orig state to 2nd row of each block)
484 	vadd.u32	q1, q1, q9
485 	vadd.u32	q6, q6, q9
486 	vadd.u32	q5, q5, q9
487 	vadd.u32	q7, q7, q9
488 
489 	// XOR first 32 bytes using keystream from first two rows of first block
490 	vld1.8		{q8-q9}, [r2]!
491 	veor		q8, q8, q0
492 	veor		q9, q9, q1
493 	vst1.8		{q8-q9}, [r1]!
494 
495 	// Re-interleave the words in the last two rows of each block (x8..15).
496 	vld1.32		{q8-q9}, [sp, :256]
497 	  mov		sp, r4		// restore original stack pointer
498 	  ldr		r4, [r4, #8]	// load number of bytes
499 	vzip.32		q12, q13	// => (12 13 12 13) (12 13 12 13)
500 	vzip.32		q14, q15	// => (14 15 14 15) (14 15 14 15)
501 	vzip.32		q8, q9		// => (8 9 8 9) (8 9 8 9)
502 	vzip.32		q10, q11	// => (10 11 10 11) (10 11 10 11)
503 	  vld1.32	{q0-q1}, [r0]	// load s8..15
504 	vswp		d25, d28
505 	vswp		d27, d30
506 	vswp		d17, d20
507 	vswp		d19, d22
508 
509 	// Last two rows of each block are (q8 q12) (q10 q14) (q9 q13) (q11 q15)
510 
511 	// x8..11[0-3] += s8..11[0-3]	(add orig state to 3rd row of each block)
512 	vadd.u32	q8,  q8,  q0
513 	vadd.u32	q10, q10, q0
514 	vadd.u32	q9,  q9,  q0
515 	vadd.u32	q11, q11, q0
516 
517 	// x12..15[0-3] += s12..15[0-3] (add orig state to 4th row of each block)
518 	vadd.u32	q12, q12, q1
519 	vadd.u32	q14, q14, q1
520 	vadd.u32	q13, q13, q1
521 	vadd.u32	q15, q15, q1
522 
523 	// XOR the rest of the data with the keystream
524 
525 	vld1.8		{q0-q1}, [r2]!
526 	subs		r4, r4, #96
527 	veor		q0, q0, q8
528 	veor		q1, q1, q12
529 	ble		.Lle96
530 	vst1.8		{q0-q1}, [r1]!
531 
532 	vld1.8		{q0-q1}, [r2]!
533 	subs		r4, r4, #32
534 	veor		q0, q0, q2
535 	veor		q1, q1, q6
536 	ble		.Lle128
537 	vst1.8		{q0-q1}, [r1]!
538 
539 	vld1.8		{q0-q1}, [r2]!
540 	subs		r4, r4, #32
541 	veor		q0, q0, q10
542 	veor		q1, q1, q14
543 	ble		.Lle160
544 	vst1.8		{q0-q1}, [r1]!
545 
546 	vld1.8		{q0-q1}, [r2]!
547 	subs		r4, r4, #32
548 	veor		q0, q0, q4
549 	veor		q1, q1, q5
550 	ble		.Lle192
551 	vst1.8		{q0-q1}, [r1]!
552 
553 	vld1.8		{q0-q1}, [r2]!
554 	subs		r4, r4, #32
555 	veor		q0, q0, q9
556 	veor		q1, q1, q13
557 	ble		.Lle224
558 	vst1.8		{q0-q1}, [r1]!
559 
560 	vld1.8		{q0-q1}, [r2]!
561 	subs		r4, r4, #32
562 	veor		q0, q0, q3
563 	veor		q1, q1, q7
564 	blt		.Llt256
565 .Lout:
566 	vst1.8		{q0-q1}, [r1]!
567 
568 	vld1.8		{q0-q1}, [r2]
569 	veor		q0, q0, q11
570 	veor		q1, q1, q15
571 	vst1.8		{q0-q1}, [r1]
572 
573 	pop		{r4, pc}
574 
575 .Lle192:
576 	vmov		q4, q9
577 	vmov		q5, q13
578 
579 .Lle160:
580 	// nothing to do
581 
582 .Lfinalblock:
583 	// Process the final block if processing less than 4 full blocks.
584 	// Entered with 32 bytes of ChaCha cipher stream in q4-q5, and the
585 	// previous 32 byte output block that still needs to be written at
586 	// [r1] in q0-q1.
587 	beq		.Lfullblock
588 
589 .Lpartialblock:
590 	adr		lr, .Lpermute + 32
591 	add		r2, r2, r4
592 	add		lr, lr, r4
593 	add		r4, r4, r1
594 
595 	vld1.8		{q2-q3}, [lr]
596 	vld1.8		{q6-q7}, [r2]
597 
598 	add		r4, r4, #32
599 
600 	vtbl.8		d4, {q4-q5}, d4
601 	vtbl.8		d5, {q4-q5}, d5
602 	vtbl.8		d6, {q4-q5}, d6
603 	vtbl.8		d7, {q4-q5}, d7
604 
605 	veor		q6, q6, q2
606 	veor		q7, q7, q3
607 
608 	vst1.8		{q6-q7}, [r4]	// overlapping stores
609 	vst1.8		{q0-q1}, [r1]
610 	pop		{r4, pc}
611 
612 .Lfullblock:
613 	vmov		q11, q4
614 	vmov		q15, q5
615 	b		.Lout
616 .Lle96:
617 	vmov		q4, q2
618 	vmov		q5, q6
619 	b		.Lfinalblock
620 .Lle128:
621 	vmov		q4, q10
622 	vmov		q5, q14
623 	b		.Lfinalblock
624 .Lle224:
625 	vmov		q4, q3
626 	vmov		q5, q7
627 	b		.Lfinalblock
628 .Llt256:
629 	vmov		q4, q11
630 	vmov		q5, q15
631 	b		.Lpartialblock
632 ENDPROC(chacha_4block_xor_neon)
633 
634 	.align		L1_CACHE_SHIFT
635 .Lpermute:
636 	.byte		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
637 	.byte		0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
638 	.byte		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
639 	.byte		0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
640 	.byte		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
641 	.byte		0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
642 	.byte		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
643 	.byte		0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
644