xref: /linux/arch/arm/crypto/sha256-armv4.pl (revision 962fad301c33dec69324dc2d9320fd84a119a24c)
1#!/usr/bin/env perl
2# SPDX-License-Identifier: GPL-2.0
3
4# This code is taken from the OpenSSL project but the author (Andy Polyakov)
5# has relicensed it under the GPLv2. Therefore this program is free software;
6# you can redistribute it and/or modify it under the terms of the GNU General
7# Public License version 2 as published by the Free Software Foundation.
8#
9# The original headers, including the original license headers, are
10# included below for completeness.
11
12# ====================================================================
13# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
14# project. The module is, however, dual licensed under OpenSSL and
15# CRYPTOGAMS licenses depending on where you obtain it. For further
16# details see https://www.openssl.org/~appro/cryptogams/.
17# ====================================================================
18
19# SHA256 block procedure for ARMv4. May 2007.
20
21# Performance is ~2x better than gcc 3.4 generated code and in "abso-
22# lute" terms is ~2250 cycles per 64-byte block or ~35 cycles per
23# byte [on single-issue Xscale PXA250 core].
24
25# July 2010.
26#
27# Rescheduling for dual-issue pipeline resulted in 22% improvement on
28# Cortex A8 core and ~20 cycles per processed byte.
29
30# February 2011.
31#
32# Profiler-assisted and platform-specific optimization resulted in 16%
33# improvement on Cortex A8 core and ~15.4 cycles per processed byte.
34
35# September 2013.
36#
37# Add NEON implementation. On Cortex A8 it was measured to process one
38# byte in 12.5 cycles or 23% faster than integer-only code. Snapdragon
39# S4 does it in 12.5 cycles too, but it's 50% faster than integer-only
40# code (meaning that latter performs sub-optimally, nothing was done
41# about it).
42
43# May 2014.
44#
45# Add ARMv8 code path performing at 2.0 cpb on Apple A7.
46
47while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {}
48open STDOUT,">$output";
49
50$ctx="r0";	$t0="r0";
51$inp="r1";	$t4="r1";
52$len="r2";	$t1="r2";
53$T1="r3";	$t3="r3";
54$A="r4";
55$B="r5";
56$C="r6";
57$D="r7";
58$E="r8";
59$F="r9";
60$G="r10";
61$H="r11";
62@V=($A,$B,$C,$D,$E,$F,$G,$H);
63$t2="r12";
64$Ktbl="r14";
65
66@Sigma0=( 2,13,22);
67@Sigma1=( 6,11,25);
68@sigma0=( 7,18, 3);
69@sigma1=(17,19,10);
70
71sub BODY_00_15 {
72my ($i,$a,$b,$c,$d,$e,$f,$g,$h) = @_;
73
74$code.=<<___ if ($i<16);
75#if __ARM_ARCH__>=7
76	@ ldr	$t1,[$inp],#4			@ $i
77# if $i==15
78	str	$inp,[sp,#17*4]			@ make room for $t4
79# endif
80	eor	$t0,$e,$e,ror#`$Sigma1[1]-$Sigma1[0]`
81	add	$a,$a,$t2			@ h+=Maj(a,b,c) from the past
82	eor	$t0,$t0,$e,ror#`$Sigma1[2]-$Sigma1[0]`	@ Sigma1(e)
83# ifndef __ARMEB__
84	rev	$t1,$t1
85# endif
86#else
87	@ ldrb	$t1,[$inp,#3]			@ $i
88	add	$a,$a,$t2			@ h+=Maj(a,b,c) from the past
89	ldrb	$t2,[$inp,#2]
90	ldrb	$t0,[$inp,#1]
91	orr	$t1,$t1,$t2,lsl#8
92	ldrb	$t2,[$inp],#4
93	orr	$t1,$t1,$t0,lsl#16
94# if $i==15
95	str	$inp,[sp,#17*4]			@ make room for $t4
96# endif
97	eor	$t0,$e,$e,ror#`$Sigma1[1]-$Sigma1[0]`
98	orr	$t1,$t1,$t2,lsl#24
99	eor	$t0,$t0,$e,ror#`$Sigma1[2]-$Sigma1[0]`	@ Sigma1(e)
100#endif
101___
102$code.=<<___;
103	ldr	$t2,[$Ktbl],#4			@ *K256++
104	add	$h,$h,$t1			@ h+=X[i]
105	str	$t1,[sp,#`$i%16`*4]
106	eor	$t1,$f,$g
107	add	$h,$h,$t0,ror#$Sigma1[0]	@ h+=Sigma1(e)
108	and	$t1,$t1,$e
109	add	$h,$h,$t2			@ h+=K256[i]
110	eor	$t1,$t1,$g			@ Ch(e,f,g)
111	eor	$t0,$a,$a,ror#`$Sigma0[1]-$Sigma0[0]`
112	add	$h,$h,$t1			@ h+=Ch(e,f,g)
113#if $i==31
114	and	$t2,$t2,#0xff
115	cmp	$t2,#0xf2			@ done?
116#endif
117#if $i<15
118# if __ARM_ARCH__>=7
119	ldr	$t1,[$inp],#4			@ prefetch
120# else
121	ldrb	$t1,[$inp,#3]
122# endif
123	eor	$t2,$a,$b			@ a^b, b^c in next round
124#else
125	ldr	$t1,[sp,#`($i+2)%16`*4]		@ from future BODY_16_xx
126	eor	$t2,$a,$b			@ a^b, b^c in next round
127	ldr	$t4,[sp,#`($i+15)%16`*4]	@ from future BODY_16_xx
128#endif
129	eor	$t0,$t0,$a,ror#`$Sigma0[2]-$Sigma0[0]`	@ Sigma0(a)
130	and	$t3,$t3,$t2			@ (b^c)&=(a^b)
131	add	$d,$d,$h			@ d+=h
132	eor	$t3,$t3,$b			@ Maj(a,b,c)
133	add	$h,$h,$t0,ror#$Sigma0[0]	@ h+=Sigma0(a)
134	@ add	$h,$h,$t3			@ h+=Maj(a,b,c)
135___
136	($t2,$t3)=($t3,$t2);
137}
138
139sub BODY_16_XX {
140my ($i,$a,$b,$c,$d,$e,$f,$g,$h) = @_;
141
142$code.=<<___;
143	@ ldr	$t1,[sp,#`($i+1)%16`*4]		@ $i
144	@ ldr	$t4,[sp,#`($i+14)%16`*4]
145	mov	$t0,$t1,ror#$sigma0[0]
146	add	$a,$a,$t2			@ h+=Maj(a,b,c) from the past
147	mov	$t2,$t4,ror#$sigma1[0]
148	eor	$t0,$t0,$t1,ror#$sigma0[1]
149	eor	$t2,$t2,$t4,ror#$sigma1[1]
150	eor	$t0,$t0,$t1,lsr#$sigma0[2]	@ sigma0(X[i+1])
151	ldr	$t1,[sp,#`($i+0)%16`*4]
152	eor	$t2,$t2,$t4,lsr#$sigma1[2]	@ sigma1(X[i+14])
153	ldr	$t4,[sp,#`($i+9)%16`*4]
154
155	add	$t2,$t2,$t0
156	eor	$t0,$e,$e,ror#`$Sigma1[1]-$Sigma1[0]`	@ from BODY_00_15
157	add	$t1,$t1,$t2
158	eor	$t0,$t0,$e,ror#`$Sigma1[2]-$Sigma1[0]`	@ Sigma1(e)
159	add	$t1,$t1,$t4			@ X[i]
160___
161	&BODY_00_15(@_);
162}
163
164$code=<<___;
165#ifndef __KERNEL__
166# include "arm_arch.h"
167#else
168# define __ARM_ARCH__ __LINUX_ARM_ARCH__
169# define __ARM_MAX_ARCH__ 7
170#endif
171
172.text
173#if __ARM_ARCH__<7
174.code	32
175#else
176.syntax unified
177# ifdef __thumb2__
178#  define adrl adr
179.thumb
180# else
181.code   32
182# endif
183#endif
184
185.type	K256,%object
186.align	5
187K256:
188.word	0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
189.word	0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
190.word	0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
191.word	0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
192.word	0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
193.word	0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
194.word	0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
195.word	0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
196.word	0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
197.word	0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
198.word	0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
199.word	0xd192e819,0xd6990624,0xf40e3585,0x106aa070
200.word	0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
201.word	0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
202.word	0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
203.word	0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
204.size	K256,.-K256
205.word	0				@ terminator
206#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
207.LOPENSSL_armcap:
208.word	OPENSSL_armcap_P-sha256_block_data_order
209#endif
210.align	5
211
212.global	sha256_block_data_order
213.type	sha256_block_data_order,%function
214sha256_block_data_order:
215.Lsha256_block_data_order:
216#if __ARM_ARCH__<7
217	sub	r3,pc,#8		@ sha256_block_data_order
218#else
219	adr	r3,.Lsha256_block_data_order
220#endif
221#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
222	ldr	r12,.LOPENSSL_armcap
223	ldr	r12,[r3,r12]		@ OPENSSL_armcap_P
224	tst	r12,#ARMV8_SHA256
225	bne	.LARMv8
226	tst	r12,#ARMV7_NEON
227	bne	.LNEON
228#endif
229	add	$len,$inp,$len,lsl#6	@ len to point at the end of inp
230	stmdb	sp!,{$ctx,$inp,$len,r4-r11,lr}
231	ldmia	$ctx,{$A,$B,$C,$D,$E,$F,$G,$H}
232	sub	$Ktbl,r3,#256+32	@ K256
233	sub	sp,sp,#16*4		@ alloca(X[16])
234.Loop:
235# if __ARM_ARCH__>=7
236	ldr	$t1,[$inp],#4
237# else
238	ldrb	$t1,[$inp,#3]
239# endif
240	eor	$t3,$B,$C		@ magic
241	eor	$t2,$t2,$t2
242___
243for($i=0;$i<16;$i++)	{ &BODY_00_15($i,@V); unshift(@V,pop(@V)); }
244$code.=".Lrounds_16_xx:\n";
245for (;$i<32;$i++)	{ &BODY_16_XX($i,@V); unshift(@V,pop(@V)); }
246$code.=<<___;
247#if __ARM_ARCH__>=7
248	ite	eq			@ Thumb2 thing, sanity check in ARM
249#endif
250	ldreq	$t3,[sp,#16*4]		@ pull ctx
251	bne	.Lrounds_16_xx
252
253	add	$A,$A,$t2		@ h+=Maj(a,b,c) from the past
254	ldr	$t0,[$t3,#0]
255	ldr	$t1,[$t3,#4]
256	ldr	$t2,[$t3,#8]
257	add	$A,$A,$t0
258	ldr	$t0,[$t3,#12]
259	add	$B,$B,$t1
260	ldr	$t1,[$t3,#16]
261	add	$C,$C,$t2
262	ldr	$t2,[$t3,#20]
263	add	$D,$D,$t0
264	ldr	$t0,[$t3,#24]
265	add	$E,$E,$t1
266	ldr	$t1,[$t3,#28]
267	add	$F,$F,$t2
268	ldr	$inp,[sp,#17*4]		@ pull inp
269	ldr	$t2,[sp,#18*4]		@ pull inp+len
270	add	$G,$G,$t0
271	add	$H,$H,$t1
272	stmia	$t3,{$A,$B,$C,$D,$E,$F,$G,$H}
273	cmp	$inp,$t2
274	sub	$Ktbl,$Ktbl,#256	@ rewind Ktbl
275	bne	.Loop
276
277	add	sp,sp,#`16+3`*4	@ destroy frame
278#if __ARM_ARCH__>=5
279	ldmia	sp!,{r4-r11,pc}
280#else
281	ldmia	sp!,{r4-r11,lr}
282	tst	lr,#1
283	moveq	pc,lr			@ be binary compatible with V4, yet
284	bx	lr			@ interoperable with Thumb ISA:-)
285#endif
286.size	sha256_block_data_order,.-sha256_block_data_order
287___
288######################################################################
289# NEON stuff
290#
291{{{
292my @X=map("q$_",(0..3));
293my ($T0,$T1,$T2,$T3,$T4,$T5)=("q8","q9","q10","q11","d24","d25");
294my $Xfer=$t4;
295my $j=0;
296
297sub Dlo()   { shift=~m|q([1]?[0-9])|?"d".($1*2):"";     }
298sub Dhi()   { shift=~m|q([1]?[0-9])|?"d".($1*2+1):"";   }
299
300sub AUTOLOAD()          # thunk [simplified] x86-style perlasm
301{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://; $opcode =~ s/_/\./;
302  my $arg = pop;
303    $arg = "#$arg" if ($arg*1 eq $arg);
304    $code .= "\t$opcode\t".join(',',@_,$arg)."\n";
305}
306
307sub Xupdate()
308{ use integer;
309  my $body = shift;
310  my @insns = (&$body,&$body,&$body,&$body);
311  my ($a,$b,$c,$d,$e,$f,$g,$h);
312
313	&vext_8		($T0,@X[0],@X[1],4);	# X[1..4]
314	 eval(shift(@insns));
315	 eval(shift(@insns));
316	 eval(shift(@insns));
317	&vext_8		($T1,@X[2],@X[3],4);	# X[9..12]
318	 eval(shift(@insns));
319	 eval(shift(@insns));
320	 eval(shift(@insns));
321	&vshr_u32	($T2,$T0,$sigma0[0]);
322	 eval(shift(@insns));
323	 eval(shift(@insns));
324	&vadd_i32	(@X[0],@X[0],$T1);	# X[0..3] += X[9..12]
325	 eval(shift(@insns));
326	 eval(shift(@insns));
327	&vshr_u32	($T1,$T0,$sigma0[2]);
328	 eval(shift(@insns));
329	 eval(shift(@insns));
330	&vsli_32	($T2,$T0,32-$sigma0[0]);
331	 eval(shift(@insns));
332	 eval(shift(@insns));
333	&vshr_u32	($T3,$T0,$sigma0[1]);
334	 eval(shift(@insns));
335	 eval(shift(@insns));
336	&veor		($T1,$T1,$T2);
337	 eval(shift(@insns));
338	 eval(shift(@insns));
339	&vsli_32	($T3,$T0,32-$sigma0[1]);
340	 eval(shift(@insns));
341	 eval(shift(@insns));
342	  &vshr_u32	($T4,&Dhi(@X[3]),$sigma1[0]);
343	 eval(shift(@insns));
344	 eval(shift(@insns));
345	&veor		($T1,$T1,$T3);		# sigma0(X[1..4])
346	 eval(shift(@insns));
347	 eval(shift(@insns));
348	  &vsli_32	($T4,&Dhi(@X[3]),32-$sigma1[0]);
349	 eval(shift(@insns));
350	 eval(shift(@insns));
351	  &vshr_u32	($T5,&Dhi(@X[3]),$sigma1[2]);
352	 eval(shift(@insns));
353	 eval(shift(@insns));
354	&vadd_i32	(@X[0],@X[0],$T1);	# X[0..3] += sigma0(X[1..4])
355	 eval(shift(@insns));
356	 eval(shift(@insns));
357	  &veor		($T5,$T5,$T4);
358	 eval(shift(@insns));
359	 eval(shift(@insns));
360	  &vshr_u32	($T4,&Dhi(@X[3]),$sigma1[1]);
361	 eval(shift(@insns));
362	 eval(shift(@insns));
363	  &vsli_32	($T4,&Dhi(@X[3]),32-$sigma1[1]);
364	 eval(shift(@insns));
365	 eval(shift(@insns));
366	  &veor		($T5,$T5,$T4);		# sigma1(X[14..15])
367	 eval(shift(@insns));
368	 eval(shift(@insns));
369	&vadd_i32	(&Dlo(@X[0]),&Dlo(@X[0]),$T5);# X[0..1] += sigma1(X[14..15])
370	 eval(shift(@insns));
371	 eval(shift(@insns));
372	  &vshr_u32	($T4,&Dlo(@X[0]),$sigma1[0]);
373	 eval(shift(@insns));
374	 eval(shift(@insns));
375	  &vsli_32	($T4,&Dlo(@X[0]),32-$sigma1[0]);
376	 eval(shift(@insns));
377	 eval(shift(@insns));
378	  &vshr_u32	($T5,&Dlo(@X[0]),$sigma1[2]);
379	 eval(shift(@insns));
380	 eval(shift(@insns));
381	  &veor		($T5,$T5,$T4);
382	 eval(shift(@insns));
383	 eval(shift(@insns));
384	  &vshr_u32	($T4,&Dlo(@X[0]),$sigma1[1]);
385	 eval(shift(@insns));
386	 eval(shift(@insns));
387	&vld1_32	("{$T0}","[$Ktbl,:128]!");
388	 eval(shift(@insns));
389	 eval(shift(@insns));
390	  &vsli_32	($T4,&Dlo(@X[0]),32-$sigma1[1]);
391	 eval(shift(@insns));
392	 eval(shift(@insns));
393	  &veor		($T5,$T5,$T4);		# sigma1(X[16..17])
394	 eval(shift(@insns));
395	 eval(shift(@insns));
396	&vadd_i32	(&Dhi(@X[0]),&Dhi(@X[0]),$T5);# X[2..3] += sigma1(X[16..17])
397	 eval(shift(@insns));
398	 eval(shift(@insns));
399	&vadd_i32	($T0,$T0,@X[0]);
400	 while($#insns>=2) { eval(shift(@insns)); }
401	&vst1_32	("{$T0}","[$Xfer,:128]!");
402	 eval(shift(@insns));
403	 eval(shift(@insns));
404
405	push(@X,shift(@X));		# "rotate" X[]
406}
407
408sub Xpreload()
409{ use integer;
410  my $body = shift;
411  my @insns = (&$body,&$body,&$body,&$body);
412  my ($a,$b,$c,$d,$e,$f,$g,$h);
413
414	 eval(shift(@insns));
415	 eval(shift(@insns));
416	 eval(shift(@insns));
417	 eval(shift(@insns));
418	&vld1_32	("{$T0}","[$Ktbl,:128]!");
419	 eval(shift(@insns));
420	 eval(shift(@insns));
421	 eval(shift(@insns));
422	 eval(shift(@insns));
423	&vrev32_8	(@X[0],@X[0]);
424	 eval(shift(@insns));
425	 eval(shift(@insns));
426	 eval(shift(@insns));
427	 eval(shift(@insns));
428	&vadd_i32	($T0,$T0,@X[0]);
429	 foreach (@insns) { eval; }	# remaining instructions
430	&vst1_32	("{$T0}","[$Xfer,:128]!");
431
432	push(@X,shift(@X));		# "rotate" X[]
433}
434
435sub body_00_15 () {
436	(
437	'($a,$b,$c,$d,$e,$f,$g,$h)=@V;'.
438	'&add	($h,$h,$t1)',			# h+=X[i]+K[i]
439	'&eor	($t1,$f,$g)',
440	'&eor	($t0,$e,$e,"ror#".($Sigma1[1]-$Sigma1[0]))',
441	'&add	($a,$a,$t2)',			# h+=Maj(a,b,c) from the past
442	'&and	($t1,$t1,$e)',
443	'&eor	($t2,$t0,$e,"ror#".($Sigma1[2]-$Sigma1[0]))',	# Sigma1(e)
444	'&eor	($t0,$a,$a,"ror#".($Sigma0[1]-$Sigma0[0]))',
445	'&eor	($t1,$t1,$g)',			# Ch(e,f,g)
446	'&add	($h,$h,$t2,"ror#$Sigma1[0]")',	# h+=Sigma1(e)
447	'&eor	($t2,$a,$b)',			# a^b, b^c in next round
448	'&eor	($t0,$t0,$a,"ror#".($Sigma0[2]-$Sigma0[0]))',	# Sigma0(a)
449	'&add	($h,$h,$t1)',			# h+=Ch(e,f,g)
450	'&ldr	($t1,sprintf "[sp,#%d]",4*(($j+1)&15))	if (($j&15)!=15);'.
451	'&ldr	($t1,"[$Ktbl]")				if ($j==15);'.
452	'&ldr	($t1,"[sp,#64]")			if ($j==31)',
453	'&and	($t3,$t3,$t2)',			# (b^c)&=(a^b)
454	'&add	($d,$d,$h)',			# d+=h
455	'&add	($h,$h,$t0,"ror#$Sigma0[0]");'.	# h+=Sigma0(a)
456	'&eor	($t3,$t3,$b)',			# Maj(a,b,c)
457	'$j++;	unshift(@V,pop(@V)); ($t2,$t3)=($t3,$t2);'
458	)
459}
460
461$code.=<<___;
462#if __ARM_MAX_ARCH__>=7
463.arch	armv7-a
464.fpu	neon
465
466.global	sha256_block_data_order_neon
467.type	sha256_block_data_order_neon,%function
468.align	4
469sha256_block_data_order_neon:
470.LNEON:
471	stmdb	sp!,{r4-r12,lr}
472
473	sub	$H,sp,#16*4+16
474	adrl	$Ktbl,K256
475	bic	$H,$H,#15		@ align for 128-bit stores
476	mov	$t2,sp
477	mov	sp,$H			@ alloca
478	add	$len,$inp,$len,lsl#6	@ len to point at the end of inp
479
480	vld1.8		{@X[0]},[$inp]!
481	vld1.8		{@X[1]},[$inp]!
482	vld1.8		{@X[2]},[$inp]!
483	vld1.8		{@X[3]},[$inp]!
484	vld1.32		{$T0},[$Ktbl,:128]!
485	vld1.32		{$T1},[$Ktbl,:128]!
486	vld1.32		{$T2},[$Ktbl,:128]!
487	vld1.32		{$T3},[$Ktbl,:128]!
488	vrev32.8	@X[0],@X[0]		@ yes, even on
489	str		$ctx,[sp,#64]
490	vrev32.8	@X[1],@X[1]		@ big-endian
491	str		$inp,[sp,#68]
492	mov		$Xfer,sp
493	vrev32.8	@X[2],@X[2]
494	str		$len,[sp,#72]
495	vrev32.8	@X[3],@X[3]
496	str		$t2,[sp,#76]		@ save original sp
497	vadd.i32	$T0,$T0,@X[0]
498	vadd.i32	$T1,$T1,@X[1]
499	vst1.32		{$T0},[$Xfer,:128]!
500	vadd.i32	$T2,$T2,@X[2]
501	vst1.32		{$T1},[$Xfer,:128]!
502	vadd.i32	$T3,$T3,@X[3]
503	vst1.32		{$T2},[$Xfer,:128]!
504	vst1.32		{$T3},[$Xfer,:128]!
505
506	ldmia		$ctx,{$A-$H}
507	sub		$Xfer,$Xfer,#64
508	ldr		$t1,[sp,#0]
509	eor		$t2,$t2,$t2
510	eor		$t3,$B,$C
511	b		.L_00_48
512
513.align	4
514.L_00_48:
515___
516	&Xupdate(\&body_00_15);
517	&Xupdate(\&body_00_15);
518	&Xupdate(\&body_00_15);
519	&Xupdate(\&body_00_15);
520$code.=<<___;
521	teq	$t1,#0				@ check for K256 terminator
522	ldr	$t1,[sp,#0]
523	sub	$Xfer,$Xfer,#64
524	bne	.L_00_48
525
526	ldr		$inp,[sp,#68]
527	ldr		$t0,[sp,#72]
528	sub		$Ktbl,$Ktbl,#256	@ rewind $Ktbl
529	teq		$inp,$t0
530	it		eq
531	subeq		$inp,$inp,#64		@ avoid SEGV
532	vld1.8		{@X[0]},[$inp]!		@ load next input block
533	vld1.8		{@X[1]},[$inp]!
534	vld1.8		{@X[2]},[$inp]!
535	vld1.8		{@X[3]},[$inp]!
536	it		ne
537	strne		$inp,[sp,#68]
538	mov		$Xfer,sp
539___
540	&Xpreload(\&body_00_15);
541	&Xpreload(\&body_00_15);
542	&Xpreload(\&body_00_15);
543	&Xpreload(\&body_00_15);
544$code.=<<___;
545	ldr	$t0,[$t1,#0]
546	add	$A,$A,$t2			@ h+=Maj(a,b,c) from the past
547	ldr	$t2,[$t1,#4]
548	ldr	$t3,[$t1,#8]
549	ldr	$t4,[$t1,#12]
550	add	$A,$A,$t0			@ accumulate
551	ldr	$t0,[$t1,#16]
552	add	$B,$B,$t2
553	ldr	$t2,[$t1,#20]
554	add	$C,$C,$t3
555	ldr	$t3,[$t1,#24]
556	add	$D,$D,$t4
557	ldr	$t4,[$t1,#28]
558	add	$E,$E,$t0
559	str	$A,[$t1],#4
560	add	$F,$F,$t2
561	str	$B,[$t1],#4
562	add	$G,$G,$t3
563	str	$C,[$t1],#4
564	add	$H,$H,$t4
565	str	$D,[$t1],#4
566	stmia	$t1,{$E-$H}
567
568	ittte	ne
569	movne	$Xfer,sp
570	ldrne	$t1,[sp,#0]
571	eorne	$t2,$t2,$t2
572	ldreq	sp,[sp,#76]			@ restore original sp
573	itt	ne
574	eorne	$t3,$B,$C
575	bne	.L_00_48
576
577	ldmia	sp!,{r4-r12,pc}
578.size	sha256_block_data_order_neon,.-sha256_block_data_order_neon
579#endif
580___
581}}}
582######################################################################
583# ARMv8 stuff
584#
585{{{
586my ($ABCD,$EFGH,$abcd)=map("q$_",(0..2));
587my @MSG=map("q$_",(8..11));
588my ($W0,$W1,$ABCD_SAVE,$EFGH_SAVE)=map("q$_",(12..15));
589my $Ktbl="r3";
590
591$code.=<<___;
592#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
593
594# ifdef __thumb2__
595#  define INST(a,b,c,d)	.byte	c,d|0xc,a,b
596# else
597#  define INST(a,b,c,d)	.byte	a,b,c,d
598# endif
599
600.type	sha256_block_data_order_armv8,%function
601.align	5
602sha256_block_data_order_armv8:
603.LARMv8:
604	vld1.32	{$ABCD,$EFGH},[$ctx]
605# ifdef __thumb2__
606	adr	$Ktbl,.LARMv8
607	sub	$Ktbl,$Ktbl,#.LARMv8-K256
608# else
609	adrl	$Ktbl,K256
610# endif
611	add	$len,$inp,$len,lsl#6	@ len to point at the end of inp
612
613.Loop_v8:
614	vld1.8		{@MSG[0]-@MSG[1]},[$inp]!
615	vld1.8		{@MSG[2]-@MSG[3]},[$inp]!
616	vld1.32		{$W0},[$Ktbl]!
617	vrev32.8	@MSG[0],@MSG[0]
618	vrev32.8	@MSG[1],@MSG[1]
619	vrev32.8	@MSG[2],@MSG[2]
620	vrev32.8	@MSG[3],@MSG[3]
621	vmov		$ABCD_SAVE,$ABCD	@ offload
622	vmov		$EFGH_SAVE,$EFGH
623	teq		$inp,$len
624___
625for($i=0;$i<12;$i++) {
626$code.=<<___;
627	vld1.32		{$W1},[$Ktbl]!
628	vadd.i32	$W0,$W0,@MSG[0]
629	sha256su0	@MSG[0],@MSG[1]
630	vmov		$abcd,$ABCD
631	sha256h		$ABCD,$EFGH,$W0
632	sha256h2	$EFGH,$abcd,$W0
633	sha256su1	@MSG[0],@MSG[2],@MSG[3]
634___
635	($W0,$W1)=($W1,$W0);	push(@MSG,shift(@MSG));
636}
637$code.=<<___;
638	vld1.32		{$W1},[$Ktbl]!
639	vadd.i32	$W0,$W0,@MSG[0]
640	vmov		$abcd,$ABCD
641	sha256h		$ABCD,$EFGH,$W0
642	sha256h2	$EFGH,$abcd,$W0
643
644	vld1.32		{$W0},[$Ktbl]!
645	vadd.i32	$W1,$W1,@MSG[1]
646	vmov		$abcd,$ABCD
647	sha256h		$ABCD,$EFGH,$W1
648	sha256h2	$EFGH,$abcd,$W1
649
650	vld1.32		{$W1},[$Ktbl]
651	vadd.i32	$W0,$W0,@MSG[2]
652	sub		$Ktbl,$Ktbl,#256-16	@ rewind
653	vmov		$abcd,$ABCD
654	sha256h		$ABCD,$EFGH,$W0
655	sha256h2	$EFGH,$abcd,$W0
656
657	vadd.i32	$W1,$W1,@MSG[3]
658	vmov		$abcd,$ABCD
659	sha256h		$ABCD,$EFGH,$W1
660	sha256h2	$EFGH,$abcd,$W1
661
662	vadd.i32	$ABCD,$ABCD,$ABCD_SAVE
663	vadd.i32	$EFGH,$EFGH,$EFGH_SAVE
664	it		ne
665	bne		.Loop_v8
666
667	vst1.32		{$ABCD,$EFGH},[$ctx]
668
669	ret		@ bx lr
670.size	sha256_block_data_order_armv8,.-sha256_block_data_order_armv8
671#endif
672___
673}}}
674$code.=<<___;
675.asciz  "SHA256 block transform for ARMv4/NEON/ARMv8, CRYPTOGAMS by <appro\@openssl.org>"
676.align	2
677#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
678.comm   OPENSSL_armcap_P,4,4
679#endif
680___
681
682open SELF,$0;
683while(<SELF>) {
684	next if (/^#!/);
685	last if (!s/^#/@/ and !/^$/);
686	print;
687}
688close SELF;
689
690{   my  %opcode = (
691	"sha256h"	=> 0xf3000c40,	"sha256h2"	=> 0xf3100c40,
692	"sha256su0"	=> 0xf3ba03c0,	"sha256su1"	=> 0xf3200c40	);
693
694    sub unsha256 {
695	my ($mnemonic,$arg)=@_;
696
697	if ($arg =~ m/q([0-9]+)(?:,\s*q([0-9]+))?,\s*q([0-9]+)/o) {
698	    my $word = $opcode{$mnemonic}|(($1&7)<<13)|(($1&8)<<19)
699					 |(($2&7)<<17)|(($2&8)<<4)
700					 |(($3&7)<<1) |(($3&8)<<2);
701	    # since ARMv7 instructions are always encoded little-endian.
702	    # correct solution is to use .inst directive, but older
703	    # assemblers don't implement it:-(
704	    sprintf "INST(0x%02x,0x%02x,0x%02x,0x%02x)\t@ %s %s",
705			$word&0xff,($word>>8)&0xff,
706			($word>>16)&0xff,($word>>24)&0xff,
707			$mnemonic,$arg;
708	}
709    }
710}
711
712foreach (split($/,$code)) {
713
714	s/\`([^\`]*)\`/eval $1/geo;
715
716	s/\b(sha256\w+)\s+(q.*)/unsha256($1,$2)/geo;
717
718	s/\bret\b/bx	lr/go		or
719	s/\bbx\s+lr\b/.word\t0xe12fff1e/go;	# make it possible to compile with -march=armv4
720
721	print $_,"\n";
722}
723
724close STDOUT; # enforce flush
725