bufhelp: use one-byte aligned type for unaligned memory accesses
[libgcrypt.git] / cipher / cast5-arm.S
1 /* cast5-arm.S  -  ARM assembly implementation of CAST5 cipher
2  *
3  * Copyright (C) 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 .extern _gcry_cast5_s1to4;
32
33 #ifdef __PIC__
34 #  define GET_DATA_POINTER(reg, name, rtmp) \
35                 ldr reg, 1f; \
36                 ldr rtmp, 2f; \
37                 b 3f; \
38         1:      .word _GLOBAL_OFFSET_TABLE_-(3f+8); \
39         2:      .word name(GOT); \
40         3:      add reg, pc, reg; \
41                 ldr reg, [reg, rtmp];
42 #else
43 #  define GET_DATA_POINTER(reg, name, rtmp) ldr reg, =name
44 #endif
45
46 /* structure of crypto context */
47 #define Km 0
48 #define Kr (Km + (16 * 4))
49 #define Kr_arm_enc (Kr + (16))
50 #define Kr_arm_dec (Kr_arm_enc + (16))
51
52 /* register macros */
53 #define CTX %r0
54 #define Rs1 %r7
55 #define Rs2 %r8
56 #define Rs3 %r9
57 #define Rs4 %r10
58 #define RMASK %r11
59 #define RKM %r1
60 #define RKR %r2
61
62 #define RL0 %r3
63 #define RR0 %r4
64
65 #define RL1 %r9
66 #define RR1 %r10
67
68 #define RT0 %lr
69 #define RT1 %ip
70 #define RT2 %r5
71 #define RT3 %r6
72
73 /* helper macros */
74 #define ldr_unaligned_le(rout, rsrc, offs, rtmp) \
75         ldrb rout, [rsrc, #((offs) + 0)]; \
76         ldrb rtmp, [rsrc, #((offs) + 1)]; \
77         orr rout, rout, rtmp, lsl #8; \
78         ldrb rtmp, [rsrc, #((offs) + 2)]; \
79         orr rout, rout, rtmp, lsl #16; \
80         ldrb rtmp, [rsrc, #((offs) + 3)]; \
81         orr rout, rout, rtmp, lsl #24;
82
83 #define str_unaligned_le(rin, rdst, offs, rtmp0, rtmp1) \
84         mov rtmp0, rin, lsr #8; \
85         strb rin, [rdst, #((offs) + 0)]; \
86         mov rtmp1, rin, lsr #16; \
87         strb rtmp0, [rdst, #((offs) + 1)]; \
88         mov rtmp0, rin, lsr #24; \
89         strb rtmp1, [rdst, #((offs) + 2)]; \
90         strb rtmp0, [rdst, #((offs) + 3)];
91
92 #define ldr_unaligned_be(rout, rsrc, offs, rtmp) \
93         ldrb rout, [rsrc, #((offs) + 3)]; \
94         ldrb rtmp, [rsrc, #((offs) + 2)]; \
95         orr rout, rout, rtmp, lsl #8; \
96         ldrb rtmp, [rsrc, #((offs) + 1)]; \
97         orr rout, rout, rtmp, lsl #16; \
98         ldrb rtmp, [rsrc, #((offs) + 0)]; \
99         orr rout, rout, rtmp, lsl #24;
100
101 #define str_unaligned_be(rin, rdst, offs, rtmp0, rtmp1) \
102         mov rtmp0, rin, lsr #8; \
103         strb rin, [rdst, #((offs) + 3)]; \
104         mov rtmp1, rin, lsr #16; \
105         strb rtmp0, [rdst, #((offs) + 2)]; \
106         mov rtmp0, rin, lsr #24; \
107         strb rtmp1, [rdst, #((offs) + 1)]; \
108         strb rtmp0, [rdst, #((offs) + 0)];
109
110 #ifdef __ARMEL__
111         #define ldr_unaligned_host ldr_unaligned_le
112         #define str_unaligned_host str_unaligned_le
113
114         /* bswap on little-endian */
115 #ifdef HAVE_ARM_ARCH_V6
116         #define host_to_be(reg, rtmp) \
117                 rev reg, reg;
118         #define be_to_host(reg, rtmp) \
119                 rev reg, reg;
120 #else
121         #define host_to_be(reg, rtmp) \
122                 eor     rtmp, reg, reg, ror #16; \
123                 mov     rtmp, rtmp, lsr #8; \
124                 bic     rtmp, rtmp, #65280; \
125                 eor     reg, rtmp, reg, ror #8;
126         #define be_to_host(reg, rtmp) \
127                 eor     rtmp, reg, reg, ror #16; \
128                 mov     rtmp, rtmp, lsr #8; \
129                 bic     rtmp, rtmp, #65280; \
130                 eor     reg, rtmp, reg, ror #8;
131 #endif
132 #else
133         #define ldr_unaligned_host ldr_unaligned_be
134         #define str_unaligned_host str_unaligned_be
135
136         /* nop on big-endian */
137         #define host_to_be(reg, rtmp) /*_*/
138         #define be_to_host(reg, rtmp) /*_*/
139 #endif
140
141 #define host_to_host(x, y) /*_*/
142
143 /**********************************************************************
144   1-way cast5
145  **********************************************************************/
146
147 #define dummy(n) /*_*/
148
149 #define load_kr(n) \
150         ldr RKR, [CTX, #(Kr_arm_enc + (n))]; /* Kr[n] */
151
152 #define load_dec_kr(n) \
153         ldr RKR, [CTX, #(Kr_arm_dec + (n) - 3)]; /* Kr[n] */
154
155 #define load_km(n) \
156         ldr RKM, [CTX, #(Km + (n) * 4)]; /* Km[n] */
157
158 #define shift_kr(dummy) \
159         mov RKR, RKR, lsr #8;
160
161 #define F(n, rl, rr, op1, op2, op3, op4, dec, loadkm, shiftkr, loadkr) \
162         op1 RKM, rr; \
163         mov RKM, RKM, ror RKR; \
164         \
165         and RT0, RMASK, RKM, ror #(24); \
166         and RT1, RMASK, RKM, lsr #(16); \
167         and RT2, RMASK, RKM, lsr #(8); \
168         ldr RT0, [Rs1, RT0]; \
169         and RT3, RMASK, RKM; \
170         ldr RT1, [Rs2, RT1]; \
171         shiftkr(RKR); \
172         \
173         ldr RT2, [Rs3, RT2]; \
174         \
175         op2 RT0, RT1; \
176         ldr RT3, [Rs4, RT3]; \
177         op3 RT0, RT2; \
178         loadkm((n) + (1 - ((dec) * 2))); \
179         op4 RT0, RT3; \
180         loadkr((n) + (1 - ((dec) * 2))); \
181         eor rl, RT0;
182
183 #define F1(n, rl, rr, dec, loadkm, shiftkr, loadkr) \
184         F(n, rl, rr, add, eor, sub, add, dec, loadkm, shiftkr, loadkr)
185 #define F2(n, rl, rr, dec, loadkm, shiftkr, loadkr) \
186         F(n, rl, rr, eor, sub, add, eor, dec, loadkm, shiftkr, loadkr)
187 #define F3(n, rl, rr, dec, loadkm, shiftkr, loadkr) \
188         F(n, rl, rr, sub, add, eor, sub, dec, loadkm, shiftkr, loadkr)
189
190 #define enc_round(n, Fx, rl, rr, loadkm, shiftkr, loadkr) \
191         Fx(n, rl, rr, 0, loadkm, shiftkr, loadkr)
192
193 #define dec_round(n, Fx, rl, rr, loadkm, shiftkr, loadkr) \
194         Fx(n, rl, rr, 1, loadkm, shiftkr, loadkr)
195
196 #define read_block_aligned(rin, offs, l0, r0, convert, rtmp) \
197         ldr l0, [rin, #((offs) + 0)]; \
198         ldr r0, [rin, #((offs) + 4)]; \
199         convert(l0, rtmp); \
200         convert(r0, rtmp);
201
202 #define write_block_aligned(rout, offs, l0, r0, convert, rtmp) \
203         convert(l0, rtmp); \
204         convert(r0, rtmp); \
205         str l0, [rout, #((offs) + 0)]; \
206         str r0, [rout, #((offs) + 4)];
207
208 #ifdef __ARM_FEATURE_UNALIGNED
209         /* unaligned word reads allowed */
210         #define read_block(rin, offs, l0, r0, rtmp0) \
211                 read_block_aligned(rin, offs, l0, r0, host_to_be, rtmp0)
212
213         #define write_block(rout, offs, r0, l0, rtmp0, rtmp1) \
214                 write_block_aligned(rout, offs, r0, l0, be_to_host, rtmp0)
215
216         #define read_block_host(rin, offs, l0, r0, rtmp0) \
217                 read_block_aligned(rin, offs, l0, r0, host_to_host, rtmp0)
218
219         #define write_block_host(rout, offs, r0, l0, rtmp0, rtmp1) \
220                 write_block_aligned(rout, offs, r0, l0, host_to_host, rtmp0)
221 #else
222         /* need to handle unaligned reads by byte reads */
223         #define read_block(rin, offs, l0, r0, rtmp0) \
224                 tst rin, #3; \
225                 beq 1f; \
226                         ldr_unaligned_be(l0, rin, (offs) + 0, rtmp0); \
227                         ldr_unaligned_be(r0, rin, (offs) + 4, rtmp0); \
228                         b 2f; \
229                 1:;\
230                         read_block_aligned(rin, offs, l0, r0, host_to_be, rtmp0); \
231                 2:;
232
233         #define write_block(rout, offs, l0, r0, rtmp0, rtmp1) \
234                 tst rout, #3; \
235                 beq 1f; \
236                         str_unaligned_be(l0, rout, (offs) + 0, rtmp0, rtmp1); \
237                         str_unaligned_be(r0, rout, (offs) + 4, rtmp0, rtmp1); \
238                         b 2f; \
239                 1:;\
240                         write_block_aligned(rout, offs, l0, r0, be_to_host, rtmp0); \
241                 2:;
242
243         #define read_block_host(rin, offs, l0, r0, rtmp0) \
244                 tst rin, #3; \
245                 beq 1f; \
246                         ldr_unaligned_host(l0, rin, (offs) + 0, rtmp0); \
247                         ldr_unaligned_host(r0, rin, (offs) + 4, rtmp0); \
248                         b 2f; \
249                 1:;\
250                         read_block_aligned(rin, offs, l0, r0, host_to_host, rtmp0); \
251                 2:;
252
253         #define write_block_host(rout, offs, l0, r0, rtmp0, rtmp1) \
254                 tst rout, #3; \
255                 beq 1f; \
256                         str_unaligned_host(l0, rout, (offs) + 0, rtmp0, rtmp1); \
257                         str_unaligned_host(r0, rout, (offs) + 4, rtmp0, rtmp1); \
258                         b 2f; \
259                 1:;\
260                         write_block_aligned(rout, offs, l0, r0, host_to_host, rtmp0); \
261                 2:;
262 #endif
263
264 .align 3
265 .globl _gcry_cast5_arm_encrypt_block
266 .type  _gcry_cast5_arm_encrypt_block,%function;
267
268 _gcry_cast5_arm_encrypt_block:
269         /* input:
270          *      %r0: CTX
271          *      %r1: dst
272          *      %r2: src
273          */
274         push {%r1, %r4-%r11, %ip, %lr};
275
276         GET_DATA_POINTER(Rs1, _gcry_cast5_s1to4, Rs2);
277         mov RMASK, #(0xff << 2);
278         add Rs2, Rs1, #(0x100*4);
279         add Rs3, Rs1, #(0x100*4*2);
280         add Rs4, Rs1, #(0x100*4*3);
281
282         read_block(%r2, 0, RL0, RR0, RT0);
283
284         load_km(0);
285         load_kr(0);
286         enc_round(0, F1, RL0, RR0, load_km, shift_kr, dummy);
287         enc_round(1, F2, RR0, RL0, load_km, shift_kr, dummy);
288         enc_round(2, F3, RL0, RR0, load_km, shift_kr, dummy);
289         enc_round(3, F1, RR0, RL0, load_km, dummy, load_kr);
290         enc_round(4, F2, RL0, RR0, load_km, shift_kr, dummy);
291         enc_round(5, F3, RR0, RL0, load_km, shift_kr, dummy);
292         enc_round(6, F1, RL0, RR0, load_km, shift_kr, dummy);
293         enc_round(7, F2, RR0, RL0, load_km, dummy, load_kr);
294         enc_round(8, F3, RL0, RR0, load_km, shift_kr, dummy);
295         enc_round(9, F1, RR0, RL0, load_km, shift_kr, dummy);
296         enc_round(10, F2, RL0, RR0, load_km, shift_kr, dummy);
297         enc_round(11, F3, RR0, RL0, load_km, dummy, load_kr);
298         enc_round(12, F1, RL0, RR0, load_km, shift_kr, dummy);
299         enc_round(13, F2, RR0, RL0, load_km, shift_kr, dummy);
300         enc_round(14, F3, RL0, RR0, load_km, shift_kr, dummy);
301         enc_round(15, F1, RR0, RL0, dummy, dummy, dummy);
302
303         ldr %r1, [%sp], #4;
304         write_block(%r1, 0, RR0, RL0, RT0, RT1);
305
306         pop {%r4-%r11, %ip, %pc};
307 .ltorg
308 .size _gcry_cast5_arm_encrypt_block,.-_gcry_cast5_arm_encrypt_block;
309
310 .align 3
311 .globl _gcry_cast5_arm_decrypt_block
312 .type  _gcry_cast5_arm_decrypt_block,%function;
313
314 _gcry_cast5_arm_decrypt_block:
315         /* input:
316          *      %r0: CTX
317          *      %r1: dst
318          *      %r2: src
319          */
320         push {%r1, %r4-%r11, %ip, %lr};
321
322         GET_DATA_POINTER(Rs1, _gcry_cast5_s1to4, Rs2);
323         mov RMASK, #(0xff << 2);
324         add Rs2, Rs1, #(0x100 * 4);
325         add Rs3, Rs1, #(0x100 * 4 * 2);
326         add Rs4, Rs1, #(0x100 * 4 * 3);
327
328         read_block(%r2, 0, RL0, RR0, RT0);
329
330         load_km(15);
331         load_dec_kr(15);
332         dec_round(15, F1, RL0, RR0, load_km, shift_kr, dummy);
333         dec_round(14, F3, RR0, RL0, load_km, shift_kr, dummy);
334         dec_round(13, F2, RL0, RR0, load_km, shift_kr, dummy);
335         dec_round(12, F1, RR0, RL0, load_km, dummy, load_dec_kr);
336         dec_round(11, F3, RL0, RR0, load_km, shift_kr, dummy);
337         dec_round(10, F2, RR0, RL0, load_km, shift_kr, dummy);
338         dec_round(9, F1, RL0, RR0, load_km, shift_kr, dummy);
339         dec_round(8, F3, RR0, RL0, load_km, dummy, load_dec_kr);
340         dec_round(7, F2, RL0, RR0, load_km, shift_kr, dummy);
341         dec_round(6, F1, RR0, RL0, load_km, shift_kr, dummy);
342         dec_round(5, F3, RL0, RR0, load_km, shift_kr, dummy);
343         dec_round(4, F2, RR0, RL0, load_km, dummy, load_dec_kr);
344         dec_round(3, F1, RL0, RR0, load_km, shift_kr, dummy);
345         dec_round(2, F3, RR0, RL0, load_km, shift_kr, dummy);
346         dec_round(1, F2, RL0, RR0, load_km, shift_kr, dummy);
347         dec_round(0, F1, RR0, RL0, dummy, dummy, dummy);
348
349         ldr %r1, [%sp], #4;
350         write_block(%r1, 0, RR0, RL0, RT0, RT1);
351
352         pop {%r4-%r11, %ip, %pc};
353 .ltorg
354 .size _gcry_cast5_arm_decrypt_block,.-_gcry_cast5_arm_decrypt_block;
355
356 /**********************************************************************
357   2-way cast5
358  **********************************************************************/
359
360 #define F_2w(n, rl0, rr0, rl1, rr1, op1, op2, op3, op4, dec, loadkm, shiftkr, \
361              loadkr) \
362         op1 RT3, RKM, rr0; \
363         op1 RKM, RKM, rr1; \
364         mov RT3, RT3, ror RKR; \
365         mov RKM, RKM, ror RKR; \
366         \
367         and RT0, RMASK, RT3, ror #(24); \
368         and RT1, RMASK, RT3, lsr #(16); \
369         and RT2, RMASK, RT3, lsr #(8); \
370         and RT3, RMASK, RT3; \
371         \
372         ldr RT0, [Rs1, RT0]; \
373         add RT2, #(0x100 * 4); \
374         ldr RT1, [Rs2, RT1]; \
375         add RT3, #(0x100 * 4 * 2); \
376         \
377         ldr RT2, [Rs2, RT2]; \
378         \
379         op2 RT0, RT1; \
380         ldr RT3, [Rs2, RT3]; \
381         and RT1, RMASK, RKM, ror #(24); \
382         op3 RT0, RT2; \
383         and RT2, RMASK, RKM, lsr #(16); \
384         op4 RT0, RT3; \
385         and RT3, RMASK, RKM, lsr #(8); \
386         eor rl0, RT0; \
387         add RT3, #(0x100 * 4); \
388         ldr RT1, [Rs1, RT1]; \
389         and RT0, RMASK, RKM; \
390         ldr RT2, [Rs2, RT2]; \
391         add RT0, #(0x100 * 4 * 2); \
392         \
393         ldr RT3, [Rs2, RT3]; \
394         \
395         op2 RT1, RT2; \
396         ldr RT0, [Rs2, RT0]; \
397         op3 RT1, RT3; \
398         loadkm((n) + (1 - ((dec) * 2))); \
399         op4 RT1, RT0; \
400         loadkr((n) + (1 - ((dec) * 2))); \
401         shiftkr(RKR); \
402         eor rl1, RT1;
403
404 #define F1_2w(n, rl0, rr0, rl1, rr1, dec, loadkm, shiftkr, loadkr) \
405         F_2w(n, rl0, rr0, rl1, rr1, add, eor, sub, add, dec, \
406              loadkm, shiftkr, loadkr)
407 #define F2_2w(n, rl0, rr0, rl1, rr1, dec, loadkm, shiftkr, loadkr) \
408         F_2w(n, rl0, rr0, rl1, rr1, eor, sub, add, eor, dec, \
409              loadkm, shiftkr, loadkr)
410 #define F3_2w(n, rl0, rr0, rl1, rr1, dec, loadkm, shiftkr, loadkr) \
411         F_2w(n, rl0, rr0, rl1, rr1, sub, add, eor, sub, dec, \
412              loadkm, shiftkr, loadkr)
413
414 #define enc_round2(n, Fx, rl, rr, loadkm, shiftkr, loadkr) \
415         Fx##_2w(n, rl##0, rr##0, rl##1, rr##1, 0, loadkm, shiftkr, loadkr)
416
417 #define dec_round2(n, Fx, rl, rr, loadkm, shiftkr, loadkr) \
418         Fx##_2w(n, rl##0, rr##0, rl##1, rr##1, 1, loadkm, shiftkr, loadkr)
419
420 #define read_block2_aligned(rin, l0, r0, l1, r1, convert, rtmp) \
421         ldr l0, [rin, #(0)]; \
422         ldr r0, [rin, #(4)]; \
423         convert(l0, rtmp); \
424         ldr l1, [rin, #(8)]; \
425         convert(r0, rtmp); \
426         ldr r1, [rin, #(12)]; \
427         convert(l1, rtmp); \
428         convert(r1, rtmp);
429
430 #define write_block2_aligned(rout, l0, r0, l1, r1, convert, rtmp) \
431         convert(l0, rtmp); \
432         convert(r0, rtmp); \
433         convert(l1, rtmp); \
434         str l0, [rout, #(0)]; \
435         convert(r1, rtmp); \
436         str r0, [rout, #(4)]; \
437         str l1, [rout, #(8)]; \
438         str r1, [rout, #(12)];
439
440 #ifdef __ARM_FEATURE_UNALIGNED
441         /* unaligned word reads allowed */
442         #define read_block2(rin, l0, r0, l1, r1, rtmp0) \
443                 read_block2_aligned(rin, l0, r0, l1, r1, host_to_be, rtmp0)
444
445         #define write_block2(rout, l0, r0, l1, r1, rtmp0, rtmp1) \
446                 write_block2_aligned(rout, l0, r0, l1, r1, be_to_host, rtmp0)
447
448         #define read_block2_host(rin, l0, r0, l1, r1, rtmp0) \
449                 read_block2_aligned(rin, l0, r0, l1, r1, host_to_host, rtmp0)
450
451         #define write_block2_host(rout, l0, r0, l1, r1, rtmp0, rtmp1) \
452                 write_block2_aligned(rout, l0, r0, l1, r1, host_to_host, rtmp0)
453 #else
454         /* need to handle unaligned reads by byte reads */
455         #define read_block2(rin, l0, r0, l1, r1, rtmp0) \
456                 tst rin, #3; \
457                 beq 1f; \
458                         ldr_unaligned_be(l0, rin, 0, rtmp0); \
459                         ldr_unaligned_be(r0, rin, 4, rtmp0); \
460                         ldr_unaligned_be(l1, rin, 8, rtmp0); \
461                         ldr_unaligned_be(r1, rin, 12, rtmp0); \
462                         b 2f; \
463                 1:;\
464                         read_block2_aligned(rin, l0, r0, l1, r1, host_to_be, rtmp0); \
465                 2:;
466
467         #define write_block2(rout, l0, r0, l1, r1, rtmp0, rtmp1) \
468                 tst rout, #3; \
469                 beq 1f; \
470                         str_unaligned_be(l0, rout, 0, rtmp0, rtmp1); \
471                         str_unaligned_be(r0, rout, 4, rtmp0, rtmp1); \
472                         str_unaligned_be(l1, rout, 8, rtmp0, rtmp1); \
473                         str_unaligned_be(r1, rout, 12, rtmp0, rtmp1); \
474                         b 2f; \
475                 1:;\
476                         write_block2_aligned(rout, l0, r0, l1, r1, be_to_host, rtmp0); \
477                 2:;
478
479         #define read_block2_host(rin, l0, r0, l1, r1, rtmp0) \
480                 tst rin, #3; \
481                 beq 1f; \
482                         ldr_unaligned_host(l0, rin, 0, rtmp0); \
483                         ldr_unaligned_host(r0, rin, 4, rtmp0); \
484                         ldr_unaligned_host(l1, rin, 8, rtmp0); \
485                         ldr_unaligned_host(r1, rin, 12, rtmp0); \
486                         b 2f; \
487                 1:;\
488                         read_block2_aligned(rin, l0, r0, l1, r1, host_to_host, rtmp0); \
489                 2:;
490
491         #define write_block2_host(rout, l0, r0, l1, r1, rtmp0, rtmp1) \
492                 tst rout, #3; \
493                 beq 1f; \
494                         str_unaligned_host(l0, rout, 0, rtmp0, rtmp1); \
495                         str_unaligned_host(r0, rout, 4, rtmp0, rtmp1); \
496                         str_unaligned_host(l1, rout, 8, rtmp0, rtmp1); \
497                         str_unaligned_host(r1, rout, 12, rtmp0, rtmp1); \
498                         b 2f; \
499                 1:;\
500                         write_block2_aligned(rout, l0, r0, l1, r1, host_to_host, rtmp0); \
501                 2:;
502 #endif
503
504 .align 3
505 .type  _gcry_cast5_arm_enc_blk2,%function;
506
507 _gcry_cast5_arm_enc_blk2:
508         /* input:
509          *      preloaded: CTX
510          *      [RL0, RR0], [RL1, RR1]: src
511          * output:
512          *      [RR0, RL0], [RR1, RL1]: dst
513          */
514         push {%lr};
515
516         GET_DATA_POINTER(Rs1, _gcry_cast5_s1to4, Rs2);
517         mov RMASK, #(0xff << 2);
518         add Rs2, Rs1, #(0x100 * 4);
519
520         load_km(0);
521         load_kr(0);
522         enc_round2(0, F1, RL, RR, load_km, shift_kr, dummy);
523         enc_round2(1, F2, RR, RL, load_km, shift_kr, dummy);
524         enc_round2(2, F3, RL, RR, load_km, shift_kr, dummy);
525         enc_round2(3, F1, RR, RL, load_km, dummy, load_kr);
526         enc_round2(4, F2, RL, RR, load_km, shift_kr, dummy);
527         enc_round2(5, F3, RR, RL, load_km, shift_kr, dummy);
528         enc_round2(6, F1, RL, RR, load_km, shift_kr, dummy);
529         enc_round2(7, F2, RR, RL, load_km, dummy, load_kr);
530         enc_round2(8, F3, RL, RR, load_km, shift_kr, dummy);
531         enc_round2(9, F1, RR, RL, load_km, shift_kr, dummy);
532         enc_round2(10, F2, RL, RR, load_km, shift_kr, dummy);
533         enc_round2(11, F3, RR, RL, load_km, dummy, load_kr);
534         enc_round2(12, F1, RL, RR, load_km, shift_kr, dummy);
535         enc_round2(13, F2, RR, RL, load_km, shift_kr, dummy);
536         enc_round2(14, F3, RL, RR, load_km, shift_kr, dummy);
537         enc_round2(15, F1, RR, RL, dummy, dummy, dummy);
538
539         host_to_be(RR0, RT0);
540         host_to_be(RL0, RT0);
541         host_to_be(RR1, RT0);
542         host_to_be(RL1, RT0);
543
544         pop {%pc};
545 .ltorg
546 .size _gcry_cast5_arm_enc_blk2,.-_gcry_cast5_arm_enc_blk2;
547
548 .align 3
549 .globl _gcry_cast5_arm_cfb_dec;
550 .type  _gcry_cast5_arm_cfb_dec,%function;
551
552 _gcry_cast5_arm_cfb_dec:
553         /* input:
554          *      %r0: CTX
555          *      %r1: dst (2 blocks)
556          *      %r2: src (2 blocks)
557          *      %r3: iv (64bit)
558          */
559         push {%r1, %r2, %r4-%r11, %ip, %lr};
560
561         mov %lr, %r3;
562
563         /* Load input (iv/%r3 is aligned, src/%r2 might not be) */
564         ldm %r3, {RL0, RR0};
565         host_to_be(RL0, RT1);
566         host_to_be(RR0, RT1);
567         read_block(%r2, 0, RL1, RR1, %ip);
568
569         /* Update IV, load src[1] and save to iv[0] */
570         read_block_host(%r2, 8, %r5, %r6, %r7);
571         stm %lr, {%r5, %r6};
572
573         bl _gcry_cast5_arm_enc_blk2;
574         /* result in RR0:RL0, RR1:RL1 = %r4:%r3, %r10:%r9 */
575
576         /* %r0: dst, %r1: %src */
577         pop {%r0, %r1};
578
579         /* dst = src ^ result */
580         read_block2_host(%r1, %r5, %r6, %r7, %r8, %lr);
581         eor %r5, %r4;
582         eor %r6, %r3;
583         eor %r7, %r10;
584         eor %r8, %r9;
585         write_block2_host(%r0, %r5, %r6, %r7, %r8, %r1, %r2);
586
587         pop {%r4-%r11, %ip, %pc};
588 .ltorg
589 .size _gcry_cast5_arm_cfb_dec,.-_gcry_cast5_arm_cfb_dec;
590
591 .align 3
592 .globl _gcry_cast5_arm_ctr_enc;
593 .type  _gcry_cast5_arm_ctr_enc,%function;
594
595 _gcry_cast5_arm_ctr_enc:
596         /* input:
597          *      %r0: CTX
598          *      %r1: dst (2 blocks)
599          *      %r2: src (2 blocks)
600          *      %r3: iv (64bit, big-endian)
601          */
602         push {%r1, %r2, %r4-%r11, %ip, %lr};
603
604         mov %lr, %r3;
605
606         /* Load IV (big => host endian) */
607         read_block_aligned(%lr, 0, RL0, RR0, be_to_host, RT1);
608
609         /* Construct IVs */
610         adds RR1, RR0, #1; /* +1 */
611         adc RL1, RL0, #0;
612         adds %r6, RR1, #1; /* +2 */
613         adc %r5, RL1, #0;
614
615         /* Store new IV (host => big-endian) */
616         write_block_aligned(%lr, 0, %r5, %r6, host_to_be, RT1);
617
618         bl _gcry_cast5_arm_enc_blk2;
619         /* result in RR0:RL0, RR1:RL1 = %r4:%r3, %r10:%r9 */
620
621         /* %r0: dst, %r1: %src */
622         pop {%r0, %r1};
623
624         /* XOR key-stream with plaintext */
625         read_block2_host(%r1, %r5, %r6, %r7, %r8, %lr);
626         eor %r5, %r4;
627         eor %r6, %r3;
628         eor %r7, %r10;
629         eor %r8, %r9;
630         write_block2_host(%r0, %r5, %r6, %r7, %r8, %r1, %r2);
631
632         pop {%r4-%r11, %ip, %pc};
633 .ltorg
634 .size _gcry_cast5_arm_ctr_enc,.-_gcry_cast5_arm_ctr_enc;
635
636 .align 3
637 .type  _gcry_cast5_arm_dec_blk2,%function;
638
639 _gcry_cast5_arm_dec_blk2:
640         /* input:
641          *      preloaded: CTX
642          *      [RL0, RR0], [RL1, RR1]: src
643          * output:
644          *      [RR0, RL0], [RR1, RL1]: dst
645          */
646
647         GET_DATA_POINTER(Rs1, _gcry_cast5_s1to4, Rs2);
648         mov RMASK, #(0xff << 2);
649         add Rs2, Rs1, #(0x100 * 4);
650
651         load_km(15);
652         load_dec_kr(15);
653         dec_round2(15, F1, RL, RR, load_km, shift_kr, dummy);
654         dec_round2(14, F3, RR, RL, load_km, shift_kr, dummy);
655         dec_round2(13, F2, RL, RR, load_km, shift_kr, dummy);
656         dec_round2(12, F1, RR, RL, load_km, dummy, load_dec_kr);
657         dec_round2(11, F3, RL, RR, load_km, shift_kr, dummy);
658         dec_round2(10, F2, RR, RL, load_km, shift_kr, dummy);
659         dec_round2(9, F1, RL, RR, load_km, shift_kr, dummy);
660         dec_round2(8, F3, RR, RL, load_km, dummy, load_dec_kr);
661         dec_round2(7, F2, RL, RR, load_km, shift_kr, dummy);
662         dec_round2(6, F1, RR, RL, load_km, shift_kr, dummy);
663         dec_round2(5, F3, RL, RR, load_km, shift_kr, dummy);
664         dec_round2(4, F2, RR, RL, load_km, dummy, load_dec_kr);
665         dec_round2(3, F1, RL, RR, load_km, shift_kr, dummy);
666         dec_round2(2, F3, RR, RL, load_km, shift_kr, dummy);
667         dec_round2(1, F2, RL, RR, load_km, shift_kr, dummy);
668         dec_round2(0, F1, RR, RL, dummy, dummy, dummy);
669
670         host_to_be(RR0, RT0);
671         host_to_be(RL0, RT0);
672         host_to_be(RR1, RT0);
673         host_to_be(RL1, RT0);
674
675         b .Ldec_cbc_tail;
676 .ltorg
677 .size _gcry_cast5_arm_dec_blk2,.-_gcry_cast5_arm_dec_blk2;
678
679 .align 3
680 .globl _gcry_cast5_arm_cbc_dec;
681 .type  _gcry_cast5_arm_cbc_dec,%function;
682
683 _gcry_cast5_arm_cbc_dec:
684         /* input:
685          *      %r0: CTX
686          *      %r1: dst (2 blocks)
687          *      %r2: src (2 blocks)
688          *      %r3: iv (64bit)
689          */
690         push {%r1-%r11, %ip, %lr};
691
692         read_block2(%r2, RL0, RR0, RL1, RR1, RT0);
693
694         /* dec_blk2 is only used by cbc_dec, jump directly in/out instead
695          * of function call. */
696         b _gcry_cast5_arm_dec_blk2;
697 .Ldec_cbc_tail:
698         /* result in RR0:RL0, RR1:RL1 = %r4:%r3, %r10:%r9 */
699
700         /* %r0: dst, %r1: %src, %r2: iv */
701         pop {%r0-%r2};
702
703         /* load IV+1 (src[0]) to %r7:%r8. Might be unaligned. */
704         read_block_host(%r1, 0, %r7, %r8, %r5);
705         /* load IV (iv[0]) to %r5:%r6. 'iv' is aligned. */
706         ldm %r2, {%r5, %r6};
707
708         /* out[1] ^= IV+1 */
709         eor %r10, %r7;
710         eor %r9, %r8;
711         /* out[0] ^= IV */
712         eor %r4, %r5;
713         eor %r3, %r6;
714
715         /* load IV+2 (src[1]) to %r7:%r8. Might be unaligned. */
716         read_block_host(%r1, 8, %r7, %r8, %r5);
717         /* store IV+2 to iv[0] (aligned). */
718         stm %r2, {%r7, %r8};
719
720         /* store result to dst[0-3]. Might be unaligned. */
721         write_block2_host(%r0, %r4, %r3, %r10, %r9, %r5, %r6);
722
723         pop {%r4-%r11, %ip, %pc};
724 .ltorg
725 .size _gcry_cast5_arm_cbc_dec,.-_gcry_cast5_arm_cbc_dec;
726
727 #endif /*HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS*/
728 #endif /*__ARM_ARCH >= 6*/