Fix BSD license name
[platform/upstream/libgcrypt.git] / cipher / blowfish-arm.S
1 /* blowfish-arm.S  -  ARM assembly implementation of Blowfish cipher
2  *
3  * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
4  *
5  * This file is part of Libgcrypt.
6  *
7  * Libgcrypt is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU Lesser General Public License as
9  * published by the Free Software Foundation; either version 2.1 of
10  * the License, or (at your option) any later version.
11  *
12  * Libgcrypt is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22
23 #if defined(__ARMEL__)
24 #ifdef HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS
25
26 .text
27
28 .syntax unified
29 .arm
30
31 /* structure of crypto context */
32 #define s0      0
33 #define s1      (s0 + (1 * 256) * 4)
34 #define s2      (s0 + (2 * 256) * 4)
35 #define s3      (s0 + (3 * 256) * 4)
36 #define p       (s3 + (1 * 256) * 4)
37
38 /* register macros */
39 #define CTXs0 %r0
40 #define CTXs1 %r9
41 #define CTXs2 %r8
42 #define CTXs3 %r10
43 #define RMASK %lr
44 #define RKEYL %r2
45 #define RKEYR %ip
46
47 #define RL0 %r3
48 #define RR0 %r4
49
50 #define RL1 %r9
51 #define RR1 %r10
52
53 #define RT0 %r11
54 #define RT1 %r7
55 #define RT2 %r5
56 #define RT3 %r6
57
58 /* helper macros */
59 #define ldr_unaligned_le(rout, rsrc, offs, rtmp) \
60         ldrb rout, [rsrc, #((offs) + 0)]; \
61         ldrb rtmp, [rsrc, #((offs) + 1)]; \
62         orr rout, rout, rtmp, lsl #8; \
63         ldrb rtmp, [rsrc, #((offs) + 2)]; \
64         orr rout, rout, rtmp, lsl #16; \
65         ldrb rtmp, [rsrc, #((offs) + 3)]; \
66         orr rout, rout, rtmp, lsl #24;
67
68 #define str_unaligned_le(rin, rdst, offs, rtmp0, rtmp1) \
69         mov rtmp0, rin, lsr #8; \
70         strb rin, [rdst, #((offs) + 0)]; \
71         mov rtmp1, rin, lsr #16; \
72         strb rtmp0, [rdst, #((offs) + 1)]; \
73         mov rtmp0, rin, lsr #24; \
74         strb rtmp1, [rdst, #((offs) + 2)]; \
75         strb rtmp0, [rdst, #((offs) + 3)];
76
77 #define ldr_unaligned_be(rout, rsrc, offs, rtmp) \
78         ldrb rout, [rsrc, #((offs) + 3)]; \
79         ldrb rtmp, [rsrc, #((offs) + 2)]; \
80         orr rout, rout, rtmp, lsl #8; \
81         ldrb rtmp, [rsrc, #((offs) + 1)]; \
82         orr rout, rout, rtmp, lsl #16; \
83         ldrb rtmp, [rsrc, #((offs) + 0)]; \
84         orr rout, rout, rtmp, lsl #24;
85
86 #define str_unaligned_be(rin, rdst, offs, rtmp0, rtmp1) \
87         mov rtmp0, rin, lsr #8; \
88         strb rin, [rdst, #((offs) + 3)]; \
89         mov rtmp1, rin, lsr #16; \
90         strb rtmp0, [rdst, #((offs) + 2)]; \
91         mov rtmp0, rin, lsr #24; \
92         strb rtmp1, [rdst, #((offs) + 1)]; \
93         strb rtmp0, [rdst, #((offs) + 0)];
94
95 #ifdef __ARMEL__
96         #define ldr_unaligned_host ldr_unaligned_le
97         #define str_unaligned_host str_unaligned_le
98
99         /* bswap on little-endian */
100 #ifdef HAVE_ARM_ARCH_V6
101         #define host_to_be(reg, rtmp) \
102                 rev reg, reg;
103         #define be_to_host(reg, rtmp) \
104                 rev reg, reg;
105 #else
106         #define host_to_be(reg, rtmp) \
107                 eor     rtmp, reg, reg, ror #16; \
108                 mov     rtmp, rtmp, lsr #8; \
109                 bic     rtmp, rtmp, #65280; \
110                 eor     reg, rtmp, reg, ror #8;
111         #define be_to_host(reg, rtmp) \
112                 eor     rtmp, reg, reg, ror #16; \
113                 mov     rtmp, rtmp, lsr #8; \
114                 bic     rtmp, rtmp, #65280; \
115                 eor     reg, rtmp, reg, ror #8;
116 #endif
117 #else
118         #define ldr_unaligned_host ldr_unaligned_be
119         #define str_unaligned_host str_unaligned_be
120
121         /* nop on big-endian */
122         #define host_to_be(reg, rtmp) /*_*/
123         #define be_to_host(reg, rtmp) /*_*/
124 #endif
125
126 #define host_to_host(x, y) /*_*/
127
128 /***********************************************************************
129  * 1-way blowfish
130  ***********************************************************************/
131 #define F(l, r) \
132         and RT0, RMASK, l, lsr#(24 - 2); \
133         and RT1, RMASK, l, lsr#(16 - 2); \
134         ldr RT0, [CTXs0, RT0]; \
135         and RT2, RMASK, l, lsr#(8 - 2); \
136         ldr RT1, [CTXs1, RT1]; \
137         and RT3, RMASK, l, lsl#2; \
138         ldr RT2, [CTXs2, RT2]; \
139         add RT0, RT1; \
140         ldr RT3, [CTXs3, RT3]; \
141         eor RT0, RT2; \
142         add RT0, RT3; \
143         eor r, RT0;
144
145 #define load_roundkey_enc(n) \
146         ldr RKEYL, [CTXs2, #((p - s2) + (4 * (n) + 0))]; \
147         ldr RKEYR, [CTXs2, #((p - s2) + (4 * (n) + 4))];
148
149 #define add_roundkey_enc() \
150         eor RL0, RKEYL; \
151         eor RR0, RKEYR;
152
153 #define round_enc(n) \
154         add_roundkey_enc(); \
155         load_roundkey_enc(n); \
156         \
157         F(RL0, RR0); \
158         F(RR0, RL0);
159
160 #define load_roundkey_dec(n) \
161         ldr RKEYL, [CTXs2, #((p - s2) + (4 * ((n) - 1) + 4))]; \
162         ldr RKEYR, [CTXs2, #((p - s2) + (4 * ((n) - 1) + 0))];
163
164 #define add_roundkey_dec() \
165         eor RL0, RKEYL; \
166         eor RR0, RKEYR;
167
168 #define round_dec(n) \
169         add_roundkey_dec(); \
170         load_roundkey_dec(n); \
171         \
172         F(RL0, RR0); \
173         F(RR0, RL0);
174
175 #define read_block_aligned(rin, offs, l0, r0, convert, rtmp) \
176         ldr l0, [rin, #((offs) + 0)]; \
177         ldr r0, [rin, #((offs) + 4)]; \
178         convert(l0, rtmp); \
179         convert(r0, rtmp);
180
181 #define write_block_aligned(rout, offs, l0, r0, convert, rtmp) \
182         convert(l0, rtmp); \
183         convert(r0, rtmp); \
184         str l0, [rout, #((offs) + 0)]; \
185         str r0, [rout, #((offs) + 4)];
186
187 #ifdef __ARM_FEATURE_UNALIGNED
188         /* unaligned word reads allowed */
189         #define read_block(rin, offs, l0, r0, rtmp0) \
190                 read_block_aligned(rin, offs, l0, r0, host_to_be, rtmp0)
191
192         #define write_block(rout, offs, r0, l0, rtmp0, rtmp1) \
193                 write_block_aligned(rout, offs, r0, l0, be_to_host, rtmp0)
194
195         #define read_block_host(rin, offs, l0, r0, rtmp0) \
196                 read_block_aligned(rin, offs, l0, r0, host_to_host, rtmp0)
197
198         #define write_block_host(rout, offs, r0, l0, rtmp0, rtmp1) \
199                 write_block_aligned(rout, offs, r0, l0, host_to_host, rtmp0)
200 #else
201         /* need to handle unaligned reads by byte reads */
202         #define read_block(rin, offs, l0, r0, rtmp0) \
203                 tst rin, #3; \
204                 beq 1f; \
205                         ldr_unaligned_be(l0, rin, (offs) + 0, rtmp0); \
206                         ldr_unaligned_be(r0, rin, (offs) + 4, rtmp0); \
207                         b 2f; \
208                 1:;\
209                         read_block_aligned(rin, offs, l0, r0, host_to_be, rtmp0); \
210                 2:;
211
212         #define write_block(rout, offs, l0, r0, rtmp0, rtmp1) \
213                 tst rout, #3; \
214                 beq 1f; \
215                         str_unaligned_be(l0, rout, (offs) + 0, rtmp0, rtmp1); \
216                         str_unaligned_be(r0, rout, (offs) + 4, rtmp0, rtmp1); \
217                         b 2f; \
218                 1:;\
219                         write_block_aligned(rout, offs, l0, r0, be_to_host, rtmp0); \
220                 2:;
221
222         #define read_block_host(rin, offs, l0, r0, rtmp0) \
223                 tst rin, #3; \
224                 beq 1f; \
225                         ldr_unaligned_host(l0, rin, (offs) + 0, rtmp0); \
226                         ldr_unaligned_host(r0, rin, (offs) + 4, rtmp0); \
227                         b 2f; \
228                 1:;\
229                         read_block_aligned(rin, offs, l0, r0, host_to_host, rtmp0); \
230                 2:;
231
232         #define write_block_host(rout, offs, l0, r0, rtmp0, rtmp1) \
233                 tst rout, #3; \
234                 beq 1f; \
235                         str_unaligned_host(l0, rout, (offs) + 0, rtmp0, rtmp1); \
236                         str_unaligned_host(r0, rout, (offs) + 4, rtmp0, rtmp1); \
237                         b 2f; \
238                 1:;\
239                         write_block_aligned(rout, offs, l0, r0, host_to_host); \
240                 2:;
241 #endif
242
243 .align 3
244 .type  __blowfish_enc_blk1,%function;
245
246 __blowfish_enc_blk1:
247         /* input:
248          *      preloaded: CTX
249          *      [RL0, RR0]: src
250          * output:
251          *      [RR0, RL0]: dst
252          */
253         push {%lr};
254
255         add CTXs1, CTXs0, #(s1 - s0);
256         add CTXs2, CTXs0, #(s2 - s0);
257         mov RMASK, #(0xff << 2); /* byte mask */
258         add CTXs3, CTXs1, #(s3 - s1);
259
260         load_roundkey_enc(0);
261         round_enc(2);
262         round_enc(4);
263         round_enc(6);
264         round_enc(8);
265         round_enc(10);
266         round_enc(12);
267         round_enc(14);
268         round_enc(16);
269         add_roundkey_enc();
270
271         pop {%pc};
272 .size __blowfish_enc_blk1,.-__blowfish_enc_blk1;
273
274 .align 8
275 .globl  _gcry_blowfish_arm_do_encrypt
276 .type   _gcry_blowfish_arm_do_encrypt,%function;
277
278 _gcry_blowfish_arm_do_encrypt:
279         /* input:
280          *      %r0: ctx, CTX
281          *      %r1: u32 *ret_xl
282          *      %r2: u32 *ret_xr
283          */
284         push {%r2, %r4-%r11, %ip, %lr};
285
286         ldr RL0, [%r1];
287         ldr RR0, [%r2];
288
289         bl __blowfish_enc_blk1;
290
291         pop {%r2};
292         str RR0, [%r1];
293         str RL0, [%r2];
294
295         pop {%r4-%r11, %ip, %pc};
296 .size _gcry_blowfish_arm_do_encrypt,.-_gcry_blowfish_arm_do_encrypt;
297
298 .align 3
299 .globl _gcry_blowfish_arm_encrypt_block
300 .type   _gcry_blowfish_arm_encrypt_block,%function;
301
302 _gcry_blowfish_arm_encrypt_block:
303         /* input:
304          *      %r0: ctx, CTX
305          *      %r1: dst
306          *      %r2: src
307          */
308         push {%r4-%r11, %ip, %lr};
309
310         read_block(%r2, 0, RL0, RR0, RT0);
311
312         bl __blowfish_enc_blk1;
313
314         write_block(%r1, 0, RR0, RL0, RT0, RT1);
315
316         pop {%r4-%r11, %ip, %pc};
317 .size _gcry_blowfish_arm_encrypt_block,.-_gcry_blowfish_arm_encrypt_block;
318
319 .align 3
320 .globl _gcry_blowfish_arm_decrypt_block
321 .type   _gcry_blowfish_arm_decrypt_block,%function;
322
323 _gcry_blowfish_arm_decrypt_block:
324         /* input:
325          *      %r0: ctx, CTX
326          *      %r1: dst
327          *      %r2: src
328          */
329         push {%r4-%r11, %ip, %lr};
330
331         add CTXs1, CTXs0, #(s1 - s0);
332         add CTXs2, CTXs0, #(s2 - s0);
333         mov RMASK, #(0xff << 2); /* byte mask */
334         add CTXs3, CTXs1, #(s3 - s1);
335
336         read_block(%r2, 0, RL0, RR0, RT0);
337
338         load_roundkey_dec(17);
339         round_dec(15);
340         round_dec(13);
341         round_dec(11);
342         round_dec(9);
343         round_dec(7);
344         round_dec(5);
345         round_dec(3);
346         round_dec(1);
347         add_roundkey_dec();
348
349         write_block(%r1, 0, RR0, RL0, RT0, RT1);
350
351         pop {%r4-%r11, %ip, %pc};
352 .size _gcry_blowfish_arm_decrypt_block,.-_gcry_blowfish_arm_decrypt_block;
353
354 /***********************************************************************
355  * 2-way blowfish
356  ***********************************************************************/
357 #define F2(n, l0, r0, l1, r1, set_nextk, dec) \
358         \
359         and RT0, RMASK, l0, lsr#(24 - 2); \
360         and RT1, RMASK, l0, lsr#(16 - 2); \
361         and RT2, RMASK, l0, lsr#(8 - 2); \
362         add RT1, #(s1 - s0); \
363         \
364         ldr RT0, [CTXs0, RT0]; \
365         and RT3, RMASK, l0, lsl#2; \
366         ldr RT1, [CTXs0, RT1]; \
367         add RT3, #(s3 - s2); \
368         ldr RT2, [CTXs2, RT2]; \
369         add RT0, RT1; \
370         ldr RT3, [CTXs2, RT3]; \
371         \
372         and RT1, RMASK, l1, lsr#(24 - 2); \
373         eor RT0, RT2; \
374         and RT2, RMASK, l1, lsr#(16 - 2); \
375         add RT0, RT3; \
376         add RT2, #(s1 - s0); \
377         and RT3, RMASK, l1, lsr#(8 - 2); \
378         eor r0, RT0; \
379         \
380         ldr RT1, [CTXs0, RT1]; \
381         and RT0, RMASK, l1, lsl#2; \
382         ldr RT2, [CTXs0, RT2]; \
383         add RT0, #(s3 - s2); \
384         ldr RT3, [CTXs2, RT3]; \
385         add RT1, RT2; \
386         ldr RT0, [CTXs2, RT0]; \
387         \
388         and RT2, RMASK, r0, lsr#(24 - 2); \
389         eor RT1, RT3; \
390         and RT3, RMASK, r0, lsr#(16 - 2); \
391         add RT1, RT0; \
392         add RT3, #(s1 - s0); \
393         and RT0, RMASK, r0, lsr#(8 - 2); \
394         eor r1, RT1; \
395         \
396         ldr RT2, [CTXs0, RT2]; \
397         and RT1, RMASK, r0, lsl#2; \
398         ldr RT3, [CTXs0, RT3]; \
399         add RT1, #(s3 - s2); \
400         ldr RT0, [CTXs2, RT0]; \
401         add RT2, RT3; \
402         ldr RT1, [CTXs2, RT1]; \
403         \
404         and RT3, RMASK, r1, lsr#(24 - 2); \
405         eor RT2, RT0; \
406         and RT0, RMASK, r1, lsr#(16 - 2); \
407         add RT2, RT1; \
408         add RT0, #(s1 - s0); \
409         and RT1, RMASK, r1, lsr#(8 - 2); \
410         eor l0, RT2; \
411         \
412         ldr RT3, [CTXs0, RT3]; \
413         and RT2, RMASK, r1, lsl#2; \
414         ldr RT0, [CTXs0, RT0]; \
415         add RT2, #(s3 - s2); \
416         ldr RT1, [CTXs2, RT1]; \
417         eor l1, RKEYL; \
418         ldr RT2, [CTXs2, RT2]; \
419         \
420         eor r0, RKEYR; \
421         add RT3, RT0; \
422         eor r1, RKEYR; \
423         eor RT3, RT1; \
424         eor l0, RKEYL; \
425         add RT3, RT2; \
426         set_nextk(RKEYL, (p - s2) + (4 * (n) + ((dec) * 4))); \
427         eor l1, RT3; \
428         set_nextk(RKEYR, (p - s2) + (4 * (n) + (!(dec) * 4)));
429
430 #define load_n_add_roundkey_enc2(n) \
431         load_roundkey_enc(n); \
432         eor RL0, RKEYL; \
433         eor RR0, RKEYR; \
434         eor RL1, RKEYL; \
435         eor RR1, RKEYR; \
436         load_roundkey_enc((n) + 2);
437
438 #define next_key(reg, offs) \
439         ldr reg, [CTXs2, #(offs)];
440
441 #define dummy(x, y) /* do nothing */
442
443 #define round_enc2(n, load_next_key) \
444         F2((n) + 2, RL0, RR0, RL1, RR1, load_next_key, 0);
445
446 #define load_n_add_roundkey_dec2(n) \
447         load_roundkey_dec(n); \
448         eor RL0, RKEYL; \
449         eor RR0, RKEYR; \
450         eor RL1, RKEYL; \
451         eor RR1, RKEYR; \
452         load_roundkey_dec((n) - 2);
453
454 #define round_dec2(n, load_next_key) \
455         F2((n) - 3, RL0, RR0, RL1, RR1, load_next_key, 1);
456
457 #define read_block2_aligned(rin, l0, r0, l1, r1, convert, rtmp) \
458         ldr l0, [rin, #(0)]; \
459         ldr r0, [rin, #(4)]; \
460         convert(l0, rtmp); \
461         ldr l1, [rin, #(8)]; \
462         convert(r0, rtmp); \
463         ldr r1, [rin, #(12)]; \
464         convert(l1, rtmp); \
465         convert(r1, rtmp);
466
467 #define write_block2_aligned(rout, l0, r0, l1, r1, convert, rtmp) \
468         convert(l0, rtmp); \
469         convert(r0, rtmp); \
470         convert(l1, rtmp); \
471         str l0, [rout, #(0)]; \
472         convert(r1, rtmp); \
473         str r0, [rout, #(4)]; \
474         str l1, [rout, #(8)]; \
475         str r1, [rout, #(12)];
476
477 #ifdef __ARM_FEATURE_UNALIGNED
478         /* unaligned word reads allowed */
479         #define read_block2(rin, l0, r0, l1, r1, rtmp0) \
480                 read_block2_aligned(rin, l0, r0, l1, r1, host_to_be, rtmp0)
481
482         #define write_block2(rout, l0, r0, l1, r1, rtmp0, rtmp1) \
483                 write_block2_aligned(rout, l0, r0, l1, r1, be_to_host, rtmp0)
484
485         #define read_block2_host(rin, l0, r0, l1, r1, rtmp0) \
486                 read_block2_aligned(rin, l0, r0, l1, r1, host_to_host, rtmp0)
487
488         #define write_block2_host(rout, l0, r0, l1, r1, rtmp0, rtmp1) \
489                 write_block2_aligned(rout, l0, r0, l1, r1, host_to_host, rtmp0)
490 #else
491         /* need to handle unaligned reads by byte reads */
492         #define read_block2(rin, l0, r0, l1, r1, rtmp0) \
493                 tst rin, #3; \
494                 beq 1f; \
495                         ldr_unaligned_be(l0, rin, 0, rtmp0); \
496                         ldr_unaligned_be(r0, rin, 4, rtmp0); \
497                         ldr_unaligned_be(l1, rin, 8, rtmp0); \
498                         ldr_unaligned_be(r1, rin, 12, rtmp0); \
499                         b 2f; \
500                 1:;\
501                         read_block2_aligned(rin, l0, r0, l1, r1, host_to_be, rtmp0); \
502                 2:;
503
504         #define write_block2(rout, l0, r0, l1, r1, rtmp0, rtmp1) \
505                 tst rout, #3; \
506                 beq 1f; \
507                         str_unaligned_be(l0, rout, 0, rtmp0, rtmp1); \
508                         str_unaligned_be(r0, rout, 4, rtmp0, rtmp1); \
509                         str_unaligned_be(l1, rout, 8, rtmp0, rtmp1); \
510                         str_unaligned_be(r1, rout, 12, rtmp0, rtmp1); \
511                         b 2f; \
512                 1:;\
513                         write_block2_aligned(rout, l0, r0, l1, r1, be_to_host, rtmp0); \
514                 2:;
515
516         #define read_block2_host(rin, l0, r0, l1, r1, rtmp0) \
517                 tst rin, #3; \
518                 beq 1f; \
519                         ldr_unaligned_host(l0, rin, 0, rtmp0); \
520                         ldr_unaligned_host(r0, rin, 4, rtmp0); \
521                         ldr_unaligned_host(l1, rin, 8, rtmp0); \
522                         ldr_unaligned_host(r1, rin, 12, rtmp0); \
523                         b 2f; \
524                 1:;\
525                         read_block2_aligned(rin, l0, r0, l1, r1, host_to_host, rtmp0); \
526                 2:;
527
528         #define write_block2_host(rout, l0, r0, l1, r1, rtmp0, rtmp1) \
529                 tst rout, #3; \
530                 beq 1f; \
531                         str_unaligned_host(l0, rout, 0, rtmp0, rtmp1); \
532                         str_unaligned_host(r0, rout, 4, rtmp0, rtmp1); \
533                         str_unaligned_host(l1, rout, 8, rtmp0, rtmp1); \
534                         str_unaligned_host(r1, rout, 12, rtmp0, rtmp1); \
535                         b 2f; \
536                 1:;\
537                         write_block2_aligned(rout, l0, r0, l1, r1, host_to_host, rtmp0); \
538                 2:;
539 #endif
540
541 .align 3
542 .type  _gcry_blowfish_arm_enc_blk2,%function;
543
544 _gcry_blowfish_arm_enc_blk2:
545         /* input:
546          *      preloaded: CTX
547          *      [RL0, RR0], [RL1, RR1]: src
548          * output:
549          *      [RR0, RL0], [RR1, RL1]: dst
550          */
551         push {RT0,%lr};
552
553         add CTXs2, CTXs0, #(s2 - s0);
554         mov RMASK, #(0xff << 2); /* byte mask */
555
556         load_n_add_roundkey_enc2(0);
557         round_enc2(2, next_key);
558         round_enc2(4, next_key);
559         round_enc2(6, next_key);
560         round_enc2(8, next_key);
561         round_enc2(10, next_key);
562         round_enc2(12, next_key);
563         round_enc2(14, next_key);
564         round_enc2(16, dummy);
565
566         host_to_be(RR0, RT0);
567         host_to_be(RL0, RT0);
568         host_to_be(RR1, RT0);
569         host_to_be(RL1, RT0);
570
571         pop {RT0,%pc};
572 .size _gcry_blowfish_arm_enc_blk2,.-_gcry_blowfish_arm_enc_blk2;
573
574 .align 3
575 .globl _gcry_blowfish_arm_cfb_dec;
576 .type  _gcry_blowfish_arm_cfb_dec,%function;
577
578 _gcry_blowfish_arm_cfb_dec:
579         /* input:
580          *      %r0: CTX
581          *      %r1: dst (2 blocks)
582          *      %r2: src (2 blocks)
583          *      %r3: iv (64bit)
584          */
585         push {%r2, %r4-%r11, %ip, %lr};
586
587         mov %lr, %r3;
588
589         /* Load input (iv/%r3 is aligned, src/%r2 might not be) */
590         ldm %r3, {RL0, RR0};
591         host_to_be(RL0, RT0);
592         host_to_be(RR0, RT0);
593         read_block(%r2, 0, RL1, RR1, RT0);
594
595         /* Update IV, load src[1] and save to iv[0] */
596         read_block_host(%r2, 8, %r5, %r6, RT0);
597         stm %lr, {%r5, %r6};
598
599         bl _gcry_blowfish_arm_enc_blk2;
600         /* result in RR0:RL0, RR1:RL1 = %r4:%r3, %r10:%r9 */
601
602         /* %r1: dst, %r0: %src */
603         pop {%r0};
604
605         /* dst = src ^ result */
606         read_block2_host(%r0, %r5, %r6, %r7, %r8, %lr);
607         eor %r5, %r4;
608         eor %r6, %r3;
609         eor %r7, %r10;
610         eor %r8, %r9;
611         write_block2_host(%r1, %r5, %r6, %r7, %r8, %r9, %r10);
612
613         pop {%r4-%r11, %ip, %pc};
614 .ltorg
615 .size _gcry_blowfish_arm_cfb_dec,.-_gcry_blowfish_arm_cfb_dec;
616
617 .align 3
618 .globl _gcry_blowfish_arm_ctr_enc;
619 .type  _gcry_blowfish_arm_ctr_enc,%function;
620
621 _gcry_blowfish_arm_ctr_enc:
622         /* input:
623          *      %r0: CTX
624          *      %r1: dst (2 blocks)
625          *      %r2: src (2 blocks)
626          *      %r3: iv (64bit, big-endian)
627          */
628         push {%r2, %r4-%r11, %ip, %lr};
629
630         mov %lr, %r3;
631
632         /* Load IV (big => host endian) */
633         read_block_aligned(%lr, 0, RL0, RR0, be_to_host, RT0);
634
635         /* Construct IVs */
636         adds RR1, RR0, #1; /* +1 */
637         adc RL1, RL0, #0;
638         adds %r6, RR1, #1; /* +2 */
639         adc %r5, RL1, #0;
640
641         /* Store new IV (host => big-endian) */
642         write_block_aligned(%lr, 0, %r5, %r6, host_to_be, RT0);
643
644         bl _gcry_blowfish_arm_enc_blk2;
645         /* result in RR0:RL0, RR1:RL1 = %r4:%r3, %r10:%r9 */
646
647         /* %r1: dst, %r0: %src */
648         pop {%r0};
649
650         /* XOR key-stream with plaintext */
651         read_block2_host(%r0, %r5, %r6, %r7, %r8, %lr);
652         eor %r5, %r4;
653         eor %r6, %r3;
654         eor %r7, %r10;
655         eor %r8, %r9;
656         write_block2_host(%r1, %r5, %r6, %r7, %r8, %r9, %r10);
657
658         pop {%r4-%r11, %ip, %pc};
659 .ltorg
660 .size _gcry_blowfish_arm_ctr_enc,.-_gcry_blowfish_arm_ctr_enc;
661
662 .align 3
663 .type  _gcry_blowfish_arm_dec_blk2,%function;
664
665 _gcry_blowfish_arm_dec_blk2:
666         /* input:
667          *      preloaded: CTX
668          *      [RL0, RR0], [RL1, RR1]: src
669          * output:
670          *      [RR0, RL0], [RR1, RL1]: dst
671          */
672         add CTXs2, CTXs0, #(s2 - s0);
673         mov RMASK, #(0xff << 2); /* byte mask */
674
675         load_n_add_roundkey_dec2(17);
676         round_dec2(15, next_key);
677         round_dec2(13, next_key);
678         round_dec2(11, next_key);
679         round_dec2(9, next_key);
680         round_dec2(7, next_key);
681         round_dec2(5, next_key);
682         round_dec2(3, next_key);
683         round_dec2(1, dummy);
684
685         host_to_be(RR0, RT0);
686         host_to_be(RL0, RT0);
687         host_to_be(RR1, RT0);
688         host_to_be(RL1, RT0);
689
690         b .Ldec_cbc_tail;
691 .ltorg
692 .size _gcry_blowfish_arm_dec_blk2,.-_gcry_blowfish_arm_dec_blk2;
693
694 .align 3
695 .globl _gcry_blowfish_arm_cbc_dec;
696 .type  _gcry_blowfish_arm_cbc_dec,%function;
697
698 _gcry_blowfish_arm_cbc_dec:
699         /* input:
700          *      %r0: CTX
701          *      %r1: dst (2 blocks)
702          *      %r2: src (2 blocks)
703          *      %r3: iv (64bit)
704          */
705         push {%r2-%r11, %ip, %lr};
706
707         read_block2(%r2, RL0, RR0, RL1, RR1, RT0);
708
709         /* dec_blk2 is only used by cbc_dec, jump directly in/out instead
710          * of function call. */
711         b _gcry_blowfish_arm_dec_blk2;
712 .Ldec_cbc_tail:
713         /* result in RR0:RL0, RR1:RL1 = %r4:%r3, %r10:%r9 */
714
715         /* %r0: %src, %r1: dst, %r2: iv */
716         pop {%r0, %r2};
717
718         /* load IV+1 (src[0]) to %r7:%r8. Might be unaligned. */
719         read_block_host(%r0, 0, %r7, %r8, %r5);
720         /* load IV (iv[0]) to %r5:%r6. 'iv' is aligned. */
721         ldm %r2, {%r5, %r6};
722
723         /* out[1] ^= IV+1 */
724         eor %r10, %r7;
725         eor %r9, %r8;
726         /* out[0] ^= IV */
727         eor %r4, %r5;
728         eor %r3, %r6;
729
730         /* load IV+2 (src[1]) to %r7:%r8. Might be unaligned. */
731         read_block_host(%r0, 8, %r7, %r8, %r5);
732         /* store IV+2 to iv[0] (aligned). */
733         stm %r2, {%r7, %r8};
734
735         /* store result to dst[0-3]. Might be unaligned. */
736         write_block2_host(%r1, %r4, %r3, %r10, %r9, %r5, %r6);
737
738         pop {%r4-%r11, %ip, %pc};
739 .ltorg
740 .size _gcry_blowfish_arm_cbc_dec,.-_gcry_blowfish_arm_cbc_dec;
741
742 #endif /*HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS*/
743 #endif /*__ARM_ARCH >= 6*/