Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * ChaCha/XChaCha NEON helper functions
0003  *
0004  * Copyright (C) 2016 Linaro, Ltd. <ard.biesheuvel@linaro.org>
0005  *
0006  * This program is free software; you can redistribute it and/or modify
0007  * it under the terms of the GNU General Public License version 2 as
0008  * published by the Free Software Foundation.
0009  *
0010  * Based on:
0011  * ChaCha20 256-bit cipher algorithm, RFC7539, x64 SSE3 functions
0012  *
0013  * Copyright (C) 2015 Martin Willi
0014  *
0015  * This program is free software; you can redistribute it and/or modify
0016  * it under the terms of the GNU General Public License as published by
0017  * the Free Software Foundation; either version 2 of the License, or
0018  * (at your option) any later version.
0019  */
0020 
0021  /*
0022   * NEON doesn't have a rotate instruction.  The alternatives are, more or less:
0023   *
0024   * (a)  vshl.u32 + vsri.u32        (needs temporary register)
0025   * (b)  vshl.u32 + vshr.u32 + vorr (needs temporary register)
0026   * (c)  vrev32.16          (16-bit rotations only)
0027   * (d)  vtbl.8 + vtbl.8        (multiple of 8 bits rotations only,
0028   *                  needs index vector)
0029   *
0030   * ChaCha has 16, 12, 8, and 7-bit rotations.  For the 12 and 7-bit rotations,
0031   * the only choices are (a) and (b).  We use (a) since it takes two-thirds the
0032   * cycles of (b) on both Cortex-A7 and Cortex-A53.
0033   *
0034   * For the 16-bit rotation, we use vrev32.16 since it's consistently fastest
0035   * and doesn't need a temporary register.
0036   *
0037   * For the 8-bit rotation, we use vtbl.8 + vtbl.8.  On Cortex-A7, this sequence
0038   * is twice as fast as (a), even when doing (a) on multiple registers
0039   * simultaneously to eliminate the stall between vshl and vsri.  Also, it
0040   * parallelizes better when temporary registers are scarce.
0041   *
0042   * A disadvantage is that on Cortex-A53, the vtbl sequence is the same speed as
0043   * (a), so the need to load the rotation table actually makes the vtbl method
0044   * slightly slower overall on that CPU (~1.3% slower ChaCha20).  Still, it
0045   * seems to be a good compromise to get a more significant speed boost on some
0046   * CPUs, e.g. ~4.8% faster ChaCha20 on Cortex-A7.
0047   */
0048 
0049 #include <linux/linkage.h>
0050 #include <asm/cache.h>
0051 
0052     .text
0053     .fpu        neon
0054     .align      5
0055 
0056 /*
0057  * chacha_permute - permute one block
0058  *
0059  * Permute one 64-byte block where the state matrix is stored in the four NEON
0060  * registers q0-q3.  It performs matrix operations on four words in parallel,
0061  * but requires shuffling to rearrange the words after each round.
0062  *
0063  * The round count is given in r3.
0064  *
0065  * Clobbers: r3, ip, q4-q5
0066  */
0067 chacha_permute:
0068 
0069     adr     ip, .Lrol8_table
0070     vld1.8      {d10}, [ip, :64]
0071 
0072 .Ldoubleround:
0073     // x0 += x1, x3 = rotl32(x3 ^ x0, 16)
0074     vadd.i32    q0, q0, q1
0075     veor        q3, q3, q0
0076     vrev32.16   q3, q3
0077 
0078     // x2 += x3, x1 = rotl32(x1 ^ x2, 12)
0079     vadd.i32    q2, q2, q3
0080     veor        q4, q1, q2
0081     vshl.u32    q1, q4, #12
0082     vsri.u32    q1, q4, #20
0083 
0084     // x0 += x1, x3 = rotl32(x3 ^ x0, 8)
0085     vadd.i32    q0, q0, q1
0086     veor        q3, q3, q0
0087     vtbl.8      d6, {d6}, d10
0088     vtbl.8      d7, {d7}, d10
0089 
0090     // x2 += x3, x1 = rotl32(x1 ^ x2, 7)
0091     vadd.i32    q2, q2, q3
0092     veor        q4, q1, q2
0093     vshl.u32    q1, q4, #7
0094     vsri.u32    q1, q4, #25
0095 
0096     // x1 = shuffle32(x1, MASK(0, 3, 2, 1))
0097     vext.8      q1, q1, q1, #4
0098     // x2 = shuffle32(x2, MASK(1, 0, 3, 2))
0099     vext.8      q2, q2, q2, #8
0100     // x3 = shuffle32(x3, MASK(2, 1, 0, 3))
0101     vext.8      q3, q3, q3, #12
0102 
0103     // x0 += x1, x3 = rotl32(x3 ^ x0, 16)
0104     vadd.i32    q0, q0, q1
0105     veor        q3, q3, q0
0106     vrev32.16   q3, q3
0107 
0108     // x2 += x3, x1 = rotl32(x1 ^ x2, 12)
0109     vadd.i32    q2, q2, q3
0110     veor        q4, q1, q2
0111     vshl.u32    q1, q4, #12
0112     vsri.u32    q1, q4, #20
0113 
0114     // x0 += x1, x3 = rotl32(x3 ^ x0, 8)
0115     vadd.i32    q0, q0, q1
0116     veor        q3, q3, q0
0117     vtbl.8      d6, {d6}, d10
0118     vtbl.8      d7, {d7}, d10
0119 
0120     // x2 += x3, x1 = rotl32(x1 ^ x2, 7)
0121     vadd.i32    q2, q2, q3
0122     veor        q4, q1, q2
0123     vshl.u32    q1, q4, #7
0124     vsri.u32    q1, q4, #25
0125 
0126     // x1 = shuffle32(x1, MASK(2, 1, 0, 3))
0127     vext.8      q1, q1, q1, #12
0128     // x2 = shuffle32(x2, MASK(1, 0, 3, 2))
0129     vext.8      q2, q2, q2, #8
0130     // x3 = shuffle32(x3, MASK(0, 3, 2, 1))
0131     vext.8      q3, q3, q3, #4
0132 
0133     subs        r3, r3, #2
0134     bne     .Ldoubleround
0135 
0136     bx      lr
0137 ENDPROC(chacha_permute)
0138 
0139 ENTRY(chacha_block_xor_neon)
0140     // r0: Input state matrix, s
0141     // r1: 1 data block output, o
0142     // r2: 1 data block input, i
0143     // r3: nrounds
0144     push        {lr}
0145 
0146     // x0..3 = s0..3
0147     add     ip, r0, #0x20
0148     vld1.32     {q0-q1}, [r0]
0149     vld1.32     {q2-q3}, [ip]
0150 
0151     vmov        q8, q0
0152     vmov        q9, q1
0153     vmov        q10, q2
0154     vmov        q11, q3
0155 
0156     bl      chacha_permute
0157 
0158     add     ip, r2, #0x20
0159     vld1.8      {q4-q5}, [r2]
0160     vld1.8      {q6-q7}, [ip]
0161 
0162     // o0 = i0 ^ (x0 + s0)
0163     vadd.i32    q0, q0, q8
0164     veor        q0, q0, q4
0165 
0166     // o1 = i1 ^ (x1 + s1)
0167     vadd.i32    q1, q1, q9
0168     veor        q1, q1, q5
0169 
0170     // o2 = i2 ^ (x2 + s2)
0171     vadd.i32    q2, q2, q10
0172     veor        q2, q2, q6
0173 
0174     // o3 = i3 ^ (x3 + s3)
0175     vadd.i32    q3, q3, q11
0176     veor        q3, q3, q7
0177 
0178     add     ip, r1, #0x20
0179     vst1.8      {q0-q1}, [r1]
0180     vst1.8      {q2-q3}, [ip]
0181 
0182     pop     {pc}
0183 ENDPROC(chacha_block_xor_neon)
0184 
0185 ENTRY(hchacha_block_neon)
0186     // r0: Input state matrix, s
0187     // r1: output (8 32-bit words)
0188     // r2: nrounds
0189     push        {lr}
0190 
0191     vld1.32     {q0-q1}, [r0]!
0192     vld1.32     {q2-q3}, [r0]
0193 
0194     mov     r3, r2
0195     bl      chacha_permute
0196 
0197     vst1.32     {q0}, [r1]!
0198     vst1.32     {q3}, [r1]
0199 
0200     pop     {pc}
0201 ENDPROC(hchacha_block_neon)
0202 
0203     .align      4
0204 .Lctrinc:   .word   0, 1, 2, 3
0205 .Lrol8_table:   .byte   3, 0, 1, 2, 7, 4, 5, 6
0206 
0207     .align      5
0208 ENTRY(chacha_4block_xor_neon)
0209     push        {r4, lr}
0210     mov     r4, sp          // preserve the stack pointer
0211     sub     ip, sp, #0x20       // allocate a 32 byte buffer
0212     bic     ip, ip, #0x1f       // aligned to 32 bytes
0213     mov     sp, ip
0214 
0215     // r0: Input state matrix, s
0216     // r1: 4 data blocks output, o
0217     // r2: 4 data blocks input, i
0218     // r3: nrounds
0219 
0220     //
0221     // This function encrypts four consecutive ChaCha blocks by loading
0222     // the state matrix in NEON registers four times. The algorithm performs
0223     // each operation on the corresponding word of each state matrix, hence
0224     // requires no word shuffling. The words are re-interleaved before the
0225     // final addition of the original state and the XORing step.
0226     //
0227 
0228     // x0..15[0-3] = s0..15[0-3]
0229     add     ip, r0, #0x20
0230     vld1.32     {q0-q1}, [r0]
0231     vld1.32     {q2-q3}, [ip]
0232 
0233     adr     lr, .Lctrinc
0234     vdup.32     q15, d7[1]
0235     vdup.32     q14, d7[0]
0236     vld1.32     {q4}, [lr, :128]
0237     vdup.32     q13, d6[1]
0238     vdup.32     q12, d6[0]
0239     vdup.32     q11, d5[1]
0240     vdup.32     q10, d5[0]
0241     vadd.u32    q12, q12, q4        // x12 += counter values 0-3
0242     vdup.32     q9, d4[1]
0243     vdup.32     q8, d4[0]
0244     vdup.32     q7, d3[1]
0245     vdup.32     q6, d3[0]
0246     vdup.32     q5, d2[1]
0247     vdup.32     q4, d2[0]
0248     vdup.32     q3, d1[1]
0249     vdup.32     q2, d1[0]
0250     vdup.32     q1, d0[1]
0251     vdup.32     q0, d0[0]
0252 
0253     adr     ip, .Lrol8_table
0254     b       1f
0255 
0256 .Ldoubleround4:
0257     vld1.32     {q8-q9}, [sp, :256]
0258 1:
0259     // x0 += x4, x12 = rotl32(x12 ^ x0, 16)
0260     // x1 += x5, x13 = rotl32(x13 ^ x1, 16)
0261     // x2 += x6, x14 = rotl32(x14 ^ x2, 16)
0262     // x3 += x7, x15 = rotl32(x15 ^ x3, 16)
0263     vadd.i32    q0, q0, q4
0264     vadd.i32    q1, q1, q5
0265     vadd.i32    q2, q2, q6
0266     vadd.i32    q3, q3, q7
0267 
0268     veor        q12, q12, q0
0269     veor        q13, q13, q1
0270     veor        q14, q14, q2
0271     veor        q15, q15, q3
0272 
0273     vrev32.16   q12, q12
0274     vrev32.16   q13, q13
0275     vrev32.16   q14, q14
0276     vrev32.16   q15, q15
0277 
0278     // x8 += x12, x4 = rotl32(x4 ^ x8, 12)
0279     // x9 += x13, x5 = rotl32(x5 ^ x9, 12)
0280     // x10 += x14, x6 = rotl32(x6 ^ x10, 12)
0281     // x11 += x15, x7 = rotl32(x7 ^ x11, 12)
0282     vadd.i32    q8, q8, q12
0283     vadd.i32    q9, q9, q13
0284     vadd.i32    q10, q10, q14
0285     vadd.i32    q11, q11, q15
0286 
0287     vst1.32     {q8-q9}, [sp, :256]
0288 
0289     veor        q8, q4, q8
0290     veor        q9, q5, q9
0291     vshl.u32    q4, q8, #12
0292     vshl.u32    q5, q9, #12
0293     vsri.u32    q4, q8, #20
0294     vsri.u32    q5, q9, #20
0295 
0296     veor        q8, q6, q10
0297     veor        q9, q7, q11
0298     vshl.u32    q6, q8, #12
0299     vshl.u32    q7, q9, #12
0300     vsri.u32    q6, q8, #20
0301     vsri.u32    q7, q9, #20
0302 
0303     // x0 += x4, x12 = rotl32(x12 ^ x0, 8)
0304     // x1 += x5, x13 = rotl32(x13 ^ x1, 8)
0305     // x2 += x6, x14 = rotl32(x14 ^ x2, 8)
0306     // x3 += x7, x15 = rotl32(x15 ^ x3, 8)
0307     vld1.8      {d16}, [ip, :64]
0308     vadd.i32    q0, q0, q4
0309     vadd.i32    q1, q1, q5
0310     vadd.i32    q2, q2, q6
0311     vadd.i32    q3, q3, q7
0312 
0313     veor        q12, q12, q0
0314     veor        q13, q13, q1
0315     veor        q14, q14, q2
0316     veor        q15, q15, q3
0317 
0318     vtbl.8      d24, {d24}, d16
0319     vtbl.8      d25, {d25}, d16
0320     vtbl.8      d26, {d26}, d16
0321     vtbl.8      d27, {d27}, d16
0322     vtbl.8      d28, {d28}, d16
0323     vtbl.8      d29, {d29}, d16
0324     vtbl.8      d30, {d30}, d16
0325     vtbl.8      d31, {d31}, d16
0326 
0327     vld1.32     {q8-q9}, [sp, :256]
0328 
0329     // x8 += x12, x4 = rotl32(x4 ^ x8, 7)
0330     // x9 += x13, x5 = rotl32(x5 ^ x9, 7)
0331     // x10 += x14, x6 = rotl32(x6 ^ x10, 7)
0332     // x11 += x15, x7 = rotl32(x7 ^ x11, 7)
0333     vadd.i32    q8, q8, q12
0334     vadd.i32    q9, q9, q13
0335     vadd.i32    q10, q10, q14
0336     vadd.i32    q11, q11, q15
0337 
0338     vst1.32     {q8-q9}, [sp, :256]
0339 
0340     veor        q8, q4, q8
0341     veor        q9, q5, q9
0342     vshl.u32    q4, q8, #7
0343     vshl.u32    q5, q9, #7
0344     vsri.u32    q4, q8, #25
0345     vsri.u32    q5, q9, #25
0346 
0347     veor        q8, q6, q10
0348     veor        q9, q7, q11
0349     vshl.u32    q6, q8, #7
0350     vshl.u32    q7, q9, #7
0351     vsri.u32    q6, q8, #25
0352     vsri.u32    q7, q9, #25
0353 
0354     vld1.32     {q8-q9}, [sp, :256]
0355 
0356     // x0 += x5, x15 = rotl32(x15 ^ x0, 16)
0357     // x1 += x6, x12 = rotl32(x12 ^ x1, 16)
0358     // x2 += x7, x13 = rotl32(x13 ^ x2, 16)
0359     // x3 += x4, x14 = rotl32(x14 ^ x3, 16)
0360     vadd.i32    q0, q0, q5
0361     vadd.i32    q1, q1, q6
0362     vadd.i32    q2, q2, q7
0363     vadd.i32    q3, q3, q4
0364 
0365     veor        q15, q15, q0
0366     veor        q12, q12, q1
0367     veor        q13, q13, q2
0368     veor        q14, q14, q3
0369 
0370     vrev32.16   q15, q15
0371     vrev32.16   q12, q12
0372     vrev32.16   q13, q13
0373     vrev32.16   q14, q14
0374 
0375     // x10 += x15, x5 = rotl32(x5 ^ x10, 12)
0376     // x11 += x12, x6 = rotl32(x6 ^ x11, 12)
0377     // x8 += x13, x7 = rotl32(x7 ^ x8, 12)
0378     // x9 += x14, x4 = rotl32(x4 ^ x9, 12)
0379     vadd.i32    q10, q10, q15
0380     vadd.i32    q11, q11, q12
0381     vadd.i32    q8, q8, q13
0382     vadd.i32    q9, q9, q14
0383 
0384     vst1.32     {q8-q9}, [sp, :256]
0385 
0386     veor        q8, q7, q8
0387     veor        q9, q4, q9
0388     vshl.u32    q7, q8, #12
0389     vshl.u32    q4, q9, #12
0390     vsri.u32    q7, q8, #20
0391     vsri.u32    q4, q9, #20
0392 
0393     veor        q8, q5, q10
0394     veor        q9, q6, q11
0395     vshl.u32    q5, q8, #12
0396     vshl.u32    q6, q9, #12
0397     vsri.u32    q5, q8, #20
0398     vsri.u32    q6, q9, #20
0399 
0400     // x0 += x5, x15 = rotl32(x15 ^ x0, 8)
0401     // x1 += x6, x12 = rotl32(x12 ^ x1, 8)
0402     // x2 += x7, x13 = rotl32(x13 ^ x2, 8)
0403     // x3 += x4, x14 = rotl32(x14 ^ x3, 8)
0404     vld1.8      {d16}, [ip, :64]
0405     vadd.i32    q0, q0, q5
0406     vadd.i32    q1, q1, q6
0407     vadd.i32    q2, q2, q7
0408     vadd.i32    q3, q3, q4
0409 
0410     veor        q15, q15, q0
0411     veor        q12, q12, q1
0412     veor        q13, q13, q2
0413     veor        q14, q14, q3
0414 
0415     vtbl.8      d30, {d30}, d16
0416     vtbl.8      d31, {d31}, d16
0417     vtbl.8      d24, {d24}, d16
0418     vtbl.8      d25, {d25}, d16
0419     vtbl.8      d26, {d26}, d16
0420     vtbl.8      d27, {d27}, d16
0421     vtbl.8      d28, {d28}, d16
0422     vtbl.8      d29, {d29}, d16
0423 
0424     vld1.32     {q8-q9}, [sp, :256]
0425 
0426     // x10 += x15, x5 = rotl32(x5 ^ x10, 7)
0427     // x11 += x12, x6 = rotl32(x6 ^ x11, 7)
0428     // x8 += x13, x7 = rotl32(x7 ^ x8, 7)
0429     // x9 += x14, x4 = rotl32(x4 ^ x9, 7)
0430     vadd.i32    q10, q10, q15
0431     vadd.i32    q11, q11, q12
0432     vadd.i32    q8, q8, q13
0433     vadd.i32    q9, q9, q14
0434 
0435     vst1.32     {q8-q9}, [sp, :256]
0436 
0437     veor        q8, q7, q8
0438     veor        q9, q4, q9
0439     vshl.u32    q7, q8, #7
0440     vshl.u32    q4, q9, #7
0441     vsri.u32    q7, q8, #25
0442     vsri.u32    q4, q9, #25
0443 
0444     veor        q8, q5, q10
0445     veor        q9, q6, q11
0446     vshl.u32    q5, q8, #7
0447     vshl.u32    q6, q9, #7
0448     vsri.u32    q5, q8, #25
0449     vsri.u32    q6, q9, #25
0450 
0451     subs        r3, r3, #2
0452     bne     .Ldoubleround4
0453 
0454     // x0..7[0-3] are in q0-q7, x10..15[0-3] are in q10-q15.
0455     // x8..9[0-3] are on the stack.
0456 
0457     // Re-interleave the words in the first two rows of each block (x0..7).
0458     // Also add the counter values 0-3 to x12[0-3].
0459       vld1.32   {q8}, [lr, :128]    // load counter values 0-3
0460     vzip.32     q0, q1          // => (0 1 0 1) (0 1 0 1)
0461     vzip.32     q2, q3          // => (2 3 2 3) (2 3 2 3)
0462     vzip.32     q4, q5          // => (4 5 4 5) (4 5 4 5)
0463     vzip.32     q6, q7          // => (6 7 6 7) (6 7 6 7)
0464       vadd.u32  q12, q8         // x12 += counter values 0-3
0465     vswp        d1, d4
0466     vswp        d3, d6
0467       vld1.32   {q8-q9}, [r0]!      // load s0..7
0468     vswp        d9, d12
0469     vswp        d11, d14
0470 
0471     // Swap q1 and q4 so that we'll free up consecutive registers (q0-q1)
0472     // after XORing the first 32 bytes.
0473     vswp        q1, q4
0474 
0475     // First two rows of each block are (q0 q1) (q2 q6) (q4 q5) (q3 q7)
0476 
0477     // x0..3[0-3] += s0..3[0-3] (add orig state to 1st row of each block)
0478     vadd.u32    q0, q0, q8
0479     vadd.u32    q2, q2, q8
0480     vadd.u32    q4, q4, q8
0481     vadd.u32    q3, q3, q8
0482 
0483     // x4..7[0-3] += s4..7[0-3] (add orig state to 2nd row of each block)
0484     vadd.u32    q1, q1, q9
0485     vadd.u32    q6, q6, q9
0486     vadd.u32    q5, q5, q9
0487     vadd.u32    q7, q7, q9
0488 
0489     // XOR first 32 bytes using keystream from first two rows of first block
0490     vld1.8      {q8-q9}, [r2]!
0491     veor        q8, q8, q0
0492     veor        q9, q9, q1
0493     vst1.8      {q8-q9}, [r1]!
0494 
0495     // Re-interleave the words in the last two rows of each block (x8..15).
0496     vld1.32     {q8-q9}, [sp, :256]
0497       mov       sp, r4      // restore original stack pointer
0498       ldr       r4, [r4, #8]    // load number of bytes
0499     vzip.32     q12, q13    // => (12 13 12 13) (12 13 12 13)
0500     vzip.32     q14, q15    // => (14 15 14 15) (14 15 14 15)
0501     vzip.32     q8, q9      // => (8 9 8 9) (8 9 8 9)
0502     vzip.32     q10, q11    // => (10 11 10 11) (10 11 10 11)
0503       vld1.32   {q0-q1}, [r0]   // load s8..15
0504     vswp        d25, d28
0505     vswp        d27, d30
0506     vswp        d17, d20
0507     vswp        d19, d22
0508 
0509     // Last two rows of each block are (q8 q12) (q10 q14) (q9 q13) (q11 q15)
0510 
0511     // x8..11[0-3] += s8..11[0-3]   (add orig state to 3rd row of each block)
0512     vadd.u32    q8,  q8,  q0
0513     vadd.u32    q10, q10, q0
0514     vadd.u32    q9,  q9,  q0
0515     vadd.u32    q11, q11, q0
0516 
0517     // x12..15[0-3] += s12..15[0-3] (add orig state to 4th row of each block)
0518     vadd.u32    q12, q12, q1
0519     vadd.u32    q14, q14, q1
0520     vadd.u32    q13, q13, q1
0521     vadd.u32    q15, q15, q1
0522 
0523     // XOR the rest of the data with the keystream
0524 
0525     vld1.8      {q0-q1}, [r2]!
0526     subs        r4, r4, #96
0527     veor        q0, q0, q8
0528     veor        q1, q1, q12
0529     ble     .Lle96
0530     vst1.8      {q0-q1}, [r1]!
0531 
0532     vld1.8      {q0-q1}, [r2]!
0533     subs        r4, r4, #32
0534     veor        q0, q0, q2
0535     veor        q1, q1, q6
0536     ble     .Lle128
0537     vst1.8      {q0-q1}, [r1]!
0538 
0539     vld1.8      {q0-q1}, [r2]!
0540     subs        r4, r4, #32
0541     veor        q0, q0, q10
0542     veor        q1, q1, q14
0543     ble     .Lle160
0544     vst1.8      {q0-q1}, [r1]!
0545 
0546     vld1.8      {q0-q1}, [r2]!
0547     subs        r4, r4, #32
0548     veor        q0, q0, q4
0549     veor        q1, q1, q5
0550     ble     .Lle192
0551     vst1.8      {q0-q1}, [r1]!
0552 
0553     vld1.8      {q0-q1}, [r2]!
0554     subs        r4, r4, #32
0555     veor        q0, q0, q9
0556     veor        q1, q1, q13
0557     ble     .Lle224
0558     vst1.8      {q0-q1}, [r1]!
0559 
0560     vld1.8      {q0-q1}, [r2]!
0561     subs        r4, r4, #32
0562     veor        q0, q0, q3
0563     veor        q1, q1, q7
0564     blt     .Llt256
0565 .Lout:
0566     vst1.8      {q0-q1}, [r1]!
0567 
0568     vld1.8      {q0-q1}, [r2]
0569     veor        q0, q0, q11
0570     veor        q1, q1, q15
0571     vst1.8      {q0-q1}, [r1]
0572 
0573     pop     {r4, pc}
0574 
0575 .Lle192:
0576     vmov        q4, q9
0577     vmov        q5, q13
0578 
0579 .Lle160:
0580     // nothing to do
0581 
0582 .Lfinalblock:
0583     // Process the final block if processing less than 4 full blocks.
0584     // Entered with 32 bytes of ChaCha cipher stream in q4-q5, and the
0585     // previous 32 byte output block that still needs to be written at
0586     // [r1] in q0-q1.
0587     beq     .Lfullblock
0588 
0589 .Lpartialblock:
0590     adr     lr, .Lpermute + 32
0591     add     r2, r2, r4
0592     add     lr, lr, r4
0593     add     r4, r4, r1
0594 
0595     vld1.8      {q2-q3}, [lr]
0596     vld1.8      {q6-q7}, [r2]
0597 
0598     add     r4, r4, #32
0599 
0600     vtbl.8      d4, {q4-q5}, d4
0601     vtbl.8      d5, {q4-q5}, d5
0602     vtbl.8      d6, {q4-q5}, d6
0603     vtbl.8      d7, {q4-q5}, d7
0604 
0605     veor        q6, q6, q2
0606     veor        q7, q7, q3
0607 
0608     vst1.8      {q6-q7}, [r4]   // overlapping stores
0609     vst1.8      {q0-q1}, [r1]
0610     pop     {r4, pc}
0611 
0612 .Lfullblock:
0613     vmov        q11, q4
0614     vmov        q15, q5
0615     b       .Lout
0616 .Lle96:
0617     vmov        q4, q2
0618     vmov        q5, q6
0619     b       .Lfinalblock
0620 .Lle128:
0621     vmov        q4, q10
0622     vmov        q5, q14
0623     b       .Lfinalblock
0624 .Lle224:
0625     vmov        q4, q3
0626     vmov        q5, q7
0627     b       .Lfinalblock
0628 .Llt256:
0629     vmov        q4, q11
0630     vmov        q5, q15
0631     b       .Lpartialblock
0632 ENDPROC(chacha_4block_xor_neon)
0633 
0634     .align      L1_CACHE_SHIFT
0635 .Lpermute:
0636     .byte       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
0637     .byte       0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
0638     .byte       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
0639     .byte       0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
0640     .byte       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
0641     .byte       0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
0642     .byte       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
0643     .byte       0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f