1289848Sjkim#!/usr/bin/env perl
2289848Sjkim
3289848Sjkim# Specific modes implementations for SPARC Architecture 2011. There
4289848Sjkim# is T4 dependency though, an ASI value that is not specified in the
5289848Sjkim# Architecture Manual. But as SPARC universe is rather monocultural,
6289848Sjkim# we imply that processor capable of executing crypto instructions
7289848Sjkim# can handle the ASI in question as well. This means that we ought to
8289848Sjkim# keep eyes open when new processors emerge...
9289848Sjkim#
10289848Sjkim# As for above mentioned ASI. It's so called "block initializing
11289848Sjkim# store" which cancels "read" in "read-update-write" on cache lines.
12289848Sjkim# This is "cooperative" optimization, as it reduces overall pressure
13289848Sjkim# on memory interface. Benefits can't be observed/quantified with
14289848Sjkim# usual benchmarks, on the contrary you can notice that single-thread
15289848Sjkim# performance for parallelizable modes is ~1.5% worse for largest
16289848Sjkim# block sizes [though few percent better for not so long ones]. All
17289848Sjkim# this based on suggestions from David Miller.
18289848Sjkim
19289848Sjkimsub asm_init {		# to be called with @ARGV as argument
20289848Sjkim    for (@_)		{ $::abibits=64 if (/\-m64/ || /\-xarch\=v9/); }
21289848Sjkim    if ($::abibits==64)	{ $::bias=2047; $::frame=192; $::size_t_cc="%xcc"; }
22289848Sjkim    else		{ $::bias=0;    $::frame=112; $::size_t_cc="%icc"; }
23289848Sjkim}
24289848Sjkim
25289848Sjkim# unified interface
26289848Sjkimmy ($inp,$out,$len,$key,$ivec)=map("%i$_",(0..5));
27289848Sjkim# local variables
28289848Sjkimmy ($ileft,$iright,$ooff,$omask,$ivoff,$blk_init)=map("%l$_",(0..7));
29289848Sjkim
30289848Sjkimsub alg_cbc_encrypt_implement {
31289848Sjkimmy ($alg,$bits) = @_;
32289848Sjkim
33289848Sjkim$::code.=<<___;
34289848Sjkim.globl	${alg}${bits}_t4_cbc_encrypt
35289848Sjkim.align	32
36289848Sjkim${alg}${bits}_t4_cbc_encrypt:
37289848Sjkim	save		%sp, -$::frame, %sp
38289848Sjkim	cmp		$len, 0
39289848Sjkim	be,pn		$::size_t_cc, .L${bits}_cbc_enc_abort
40306195Sjkim	srln		$len, 0, $len		! needed on v8+, "nop" on v9
41289848Sjkim	sub		$inp, $out, $blk_init	! $inp!=$out
42289848Sjkim___
43289848Sjkim$::code.=<<___ if (!$::evp);
44289848Sjkim	andcc		$ivec, 7, $ivoff
45289848Sjkim	alignaddr	$ivec, %g0, $ivec
46289848Sjkim
47289848Sjkim	ldd		[$ivec + 0], %f0	! load ivec
48289848Sjkim	bz,pt		%icc, 1f
49289848Sjkim	ldd		[$ivec + 8], %f2
50289848Sjkim	ldd		[$ivec + 16], %f4
51289848Sjkim	faligndata	%f0, %f2, %f0
52289848Sjkim	faligndata	%f2, %f4, %f2
53289848Sjkim1:
54289848Sjkim___
55289848Sjkim$::code.=<<___ if ($::evp);
56289848Sjkim	ld		[$ivec + 0], %f0
57289848Sjkim	ld		[$ivec + 4], %f1
58289848Sjkim	ld		[$ivec + 8], %f2
59289848Sjkim	ld		[$ivec + 12], %f3
60289848Sjkim___
61289848Sjkim$::code.=<<___;
62289848Sjkim	prefetch	[$inp], 20
63289848Sjkim	prefetch	[$inp + 63], 20
64289848Sjkim	call		_${alg}${bits}_load_enckey
65289848Sjkim	and		$inp, 7, $ileft
66289848Sjkim	andn		$inp, 7, $inp
67289848Sjkim	sll		$ileft, 3, $ileft
68289848Sjkim	mov		64, $iright
69289848Sjkim	mov		0xff, $omask
70289848Sjkim	sub		$iright, $ileft, $iright
71289848Sjkim	and		$out, 7, $ooff
72289848Sjkim	cmp		$len, 127
73289848Sjkim	movrnz		$ooff, 0, $blk_init		! if (	$out&7 ||
74289848Sjkim	movleu		$::size_t_cc, 0, $blk_init	!	$len<128 ||
75289848Sjkim	brnz,pn		$blk_init, .L${bits}cbc_enc_blk	!	$inp==$out)
76289848Sjkim	srl		$omask, $ooff, $omask
77289848Sjkim
78289848Sjkim	alignaddrl	$out, %g0, $out
79289848Sjkim	srlx		$len, 4, $len
80289848Sjkim	prefetch	[$out], 22
81289848Sjkim
82289848Sjkim.L${bits}_cbc_enc_loop:
83289848Sjkim	ldx		[$inp + 0], %o0
84289848Sjkim	brz,pt		$ileft, 4f
85289848Sjkim	ldx		[$inp + 8], %o1
86289848Sjkim
87289848Sjkim	ldx		[$inp + 16], %o2
88289848Sjkim	sllx		%o0, $ileft, %o0
89289848Sjkim	srlx		%o1, $iright, %g1
90289848Sjkim	sllx		%o1, $ileft, %o1
91289848Sjkim	or		%g1, %o0, %o0
92289848Sjkim	srlx		%o2, $iright, %o2
93289848Sjkim	or		%o2, %o1, %o1
94289848Sjkim4:
95289848Sjkim	xor		%g4, %o0, %o0		! ^= rk[0]
96289848Sjkim	xor		%g5, %o1, %o1
97289848Sjkim	movxtod		%o0, %f12
98289848Sjkim	movxtod		%o1, %f14
99289848Sjkim
100289848Sjkim	fxor		%f12, %f0, %f0		! ^= ivec
101289848Sjkim	fxor		%f14, %f2, %f2
102289848Sjkim	prefetch	[$out + 63], 22
103289848Sjkim	prefetch	[$inp + 16+63], 20
104289848Sjkim	call		_${alg}${bits}_encrypt_1x
105289848Sjkim	add		$inp, 16, $inp
106289848Sjkim
107289848Sjkim	brnz,pn		$ooff, 2f
108289848Sjkim	sub		$len, 1, $len
109289848Sjkim
110289848Sjkim	std		%f0, [$out + 0]
111289848Sjkim	std		%f2, [$out + 8]
112289848Sjkim	brnz,pt		$len, .L${bits}_cbc_enc_loop
113289848Sjkim	add		$out, 16, $out
114289848Sjkim___
115289848Sjkim$::code.=<<___ if ($::evp);
116289848Sjkim	st		%f0, [$ivec + 0]
117289848Sjkim	st		%f1, [$ivec + 4]
118289848Sjkim	st		%f2, [$ivec + 8]
119289848Sjkim	st		%f3, [$ivec + 12]
120289848Sjkim___
121289848Sjkim$::code.=<<___ if (!$::evp);
122289848Sjkim	brnz,pn		$ivoff, 3f
123289848Sjkim	nop
124289848Sjkim
125289848Sjkim	std		%f0, [$ivec + 0]	! write out ivec
126289848Sjkim	std		%f2, [$ivec + 8]
127289848Sjkim___
128289848Sjkim$::code.=<<___;
129289848Sjkim.L${bits}_cbc_enc_abort:
130289848Sjkim	ret
131289848Sjkim	restore
132289848Sjkim
133289848Sjkim.align	16
134289848Sjkim2:	ldxa		[$inp]0x82, %o0		! avoid read-after-write hazard
135289848Sjkim						! and ~3x deterioration
136289848Sjkim						! in inp==out case
137289848Sjkim	faligndata	%f0, %f0, %f4		! handle unaligned output
138289848Sjkim	faligndata	%f0, %f2, %f6
139289848Sjkim	faligndata	%f2, %f2, %f8
140289848Sjkim
141289848Sjkim	stda		%f4, [$out + $omask]0xc0	! partial store
142289848Sjkim	std		%f6, [$out + 8]
143289848Sjkim	add		$out, 16, $out
144289848Sjkim	orn		%g0, $omask, $omask
145289848Sjkim	stda		%f8, [$out + $omask]0xc0	! partial store
146289848Sjkim
147289848Sjkim	brnz,pt		$len, .L${bits}_cbc_enc_loop+4
148289848Sjkim	orn		%g0, $omask, $omask
149289848Sjkim___
150289848Sjkim$::code.=<<___ if ($::evp);
151289848Sjkim	st		%f0, [$ivec + 0]
152289848Sjkim	st		%f1, [$ivec + 4]
153289848Sjkim	st		%f2, [$ivec + 8]
154289848Sjkim	st		%f3, [$ivec + 12]
155289848Sjkim___
156289848Sjkim$::code.=<<___ if (!$::evp);
157289848Sjkim	brnz,pn		$ivoff, 3f
158289848Sjkim	nop
159289848Sjkim
160289848Sjkim	std		%f0, [$ivec + 0]	! write out ivec
161289848Sjkim	std		%f2, [$ivec + 8]
162289848Sjkim	ret
163289848Sjkim	restore
164289848Sjkim
165289848Sjkim.align	16
166289848Sjkim3:	alignaddrl	$ivec, $ivoff, %g0	! handle unaligned ivec
167289848Sjkim	mov		0xff, $omask
168289848Sjkim	srl		$omask, $ivoff, $omask
169289848Sjkim	faligndata	%f0, %f0, %f4
170289848Sjkim	faligndata	%f0, %f2, %f6
171289848Sjkim	faligndata	%f2, %f2, %f8
172289848Sjkim	stda		%f4, [$ivec + $omask]0xc0
173289848Sjkim	std		%f6, [$ivec + 8]
174289848Sjkim	add		$ivec, 16, $ivec
175289848Sjkim	orn		%g0, $omask, $omask
176289848Sjkim	stda		%f8, [$ivec + $omask]0xc0
177289848Sjkim___
178289848Sjkim$::code.=<<___;
179289848Sjkim	ret
180289848Sjkim	restore
181289848Sjkim
182289848Sjkim!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
183289848Sjkim.align	32
184289848Sjkim.L${bits}cbc_enc_blk:
185289848Sjkim	add	$out, $len, $blk_init
186289848Sjkim	and	$blk_init, 63, $blk_init	! tail
187289848Sjkim	sub	$len, $blk_init, $len
188289848Sjkim	add	$blk_init, 15, $blk_init	! round up to 16n
189289848Sjkim	srlx	$len, 4, $len
190289848Sjkim	srl	$blk_init, 4, $blk_init
191289848Sjkim
192289848Sjkim.L${bits}_cbc_enc_blk_loop:
193289848Sjkim	ldx		[$inp + 0], %o0
194289848Sjkim	brz,pt		$ileft, 5f
195289848Sjkim	ldx		[$inp + 8], %o1
196289848Sjkim
197289848Sjkim	ldx		[$inp + 16], %o2
198289848Sjkim	sllx		%o0, $ileft, %o0
199289848Sjkim	srlx		%o1, $iright, %g1
200289848Sjkim	sllx		%o1, $ileft, %o1
201289848Sjkim	or		%g1, %o0, %o0
202289848Sjkim	srlx		%o2, $iright, %o2
203289848Sjkim	or		%o2, %o1, %o1
204289848Sjkim5:
205289848Sjkim	xor		%g4, %o0, %o0		! ^= rk[0]
206289848Sjkim	xor		%g5, %o1, %o1
207289848Sjkim	movxtod		%o0, %f12
208289848Sjkim	movxtod		%o1, %f14
209289848Sjkim
210289848Sjkim	fxor		%f12, %f0, %f0		! ^= ivec
211289848Sjkim	fxor		%f14, %f2, %f2
212289848Sjkim	prefetch	[$inp + 16+63], 20
213289848Sjkim	call		_${alg}${bits}_encrypt_1x
214289848Sjkim	add		$inp, 16, $inp
215289848Sjkim	sub		$len, 1, $len
216289848Sjkim
217289848Sjkim	stda		%f0, [$out]0xe2		! ASI_BLK_INIT, T4-specific
218289848Sjkim	add		$out, 8, $out
219289848Sjkim	stda		%f2, [$out]0xe2		! ASI_BLK_INIT, T4-specific
220289848Sjkim	brnz,pt		$len, .L${bits}_cbc_enc_blk_loop
221289848Sjkim	add		$out, 8, $out
222289848Sjkim
223289848Sjkim	membar		#StoreLoad|#StoreStore
224289848Sjkim	brnz,pt		$blk_init, .L${bits}_cbc_enc_loop
225289848Sjkim	mov		$blk_init, $len
226289848Sjkim___
227289848Sjkim$::code.=<<___ if ($::evp);
228289848Sjkim	st		%f0, [$ivec + 0]
229289848Sjkim	st		%f1, [$ivec + 4]
230289848Sjkim	st		%f2, [$ivec + 8]
231289848Sjkim	st		%f3, [$ivec + 12]
232289848Sjkim___
233289848Sjkim$::code.=<<___ if (!$::evp);
234289848Sjkim	brnz,pn		$ivoff, 3b
235289848Sjkim	nop
236289848Sjkim
237289848Sjkim	std		%f0, [$ivec + 0]	! write out ivec
238289848Sjkim	std		%f2, [$ivec + 8]
239289848Sjkim___
240289848Sjkim$::code.=<<___;
241289848Sjkim	ret
242289848Sjkim	restore
243289848Sjkim.type	${alg}${bits}_t4_cbc_encrypt,#function
244289848Sjkim.size	${alg}${bits}_t4_cbc_encrypt,.-${alg}${bits}_t4_cbc_encrypt
245289848Sjkim___
246289848Sjkim}
247289848Sjkim
248289848Sjkimsub alg_cbc_decrypt_implement {
249289848Sjkimmy ($alg,$bits) = @_;
250289848Sjkim
251289848Sjkim$::code.=<<___;
252289848Sjkim.globl	${alg}${bits}_t4_cbc_decrypt
253289848Sjkim.align	32
254289848Sjkim${alg}${bits}_t4_cbc_decrypt:
255289848Sjkim	save		%sp, -$::frame, %sp
256289848Sjkim	cmp		$len, 0
257289848Sjkim	be,pn		$::size_t_cc, .L${bits}_cbc_dec_abort
258306195Sjkim	srln		$len, 0, $len		! needed on v8+, "nop" on v9
259289848Sjkim	sub		$inp, $out, $blk_init	! $inp!=$out
260289848Sjkim___
261289848Sjkim$::code.=<<___ if (!$::evp);
262289848Sjkim	andcc		$ivec, 7, $ivoff
263289848Sjkim	alignaddr	$ivec, %g0, $ivec
264289848Sjkim
265289848Sjkim	ldd		[$ivec + 0], %f12	! load ivec
266289848Sjkim	bz,pt		%icc, 1f
267289848Sjkim	ldd		[$ivec + 8], %f14
268289848Sjkim	ldd		[$ivec + 16], %f0
269289848Sjkim	faligndata	%f12, %f14, %f12
270289848Sjkim	faligndata	%f14, %f0, %f14
271289848Sjkim1:
272289848Sjkim___
273289848Sjkim$::code.=<<___ if ($::evp);
274289848Sjkim	ld		[$ivec + 0], %f12	! load ivec
275289848Sjkim	ld		[$ivec + 4], %f13
276289848Sjkim	ld		[$ivec + 8], %f14
277289848Sjkim	ld		[$ivec + 12], %f15
278289848Sjkim___
279289848Sjkim$::code.=<<___;
280289848Sjkim	prefetch	[$inp], 20
281289848Sjkim	prefetch	[$inp + 63], 20
282289848Sjkim	call		_${alg}${bits}_load_deckey
283289848Sjkim	and		$inp, 7, $ileft
284289848Sjkim	andn		$inp, 7, $inp
285289848Sjkim	sll		$ileft, 3, $ileft
286289848Sjkim	mov		64, $iright
287289848Sjkim	mov		0xff, $omask
288289848Sjkim	sub		$iright, $ileft, $iright
289289848Sjkim	and		$out, 7, $ooff
290289848Sjkim	cmp		$len, 255
291289848Sjkim	movrnz		$ooff, 0, $blk_init		! if (	$out&7 ||
292289848Sjkim	movleu		$::size_t_cc, 0, $blk_init	!	$len<256 ||
293289848Sjkim	brnz,pn		$blk_init, .L${bits}cbc_dec_blk	!	$inp==$out)
294289848Sjkim	srl		$omask, $ooff, $omask
295289848Sjkim
296289848Sjkim	andcc		$len, 16, %g0		! is number of blocks even?
297289848Sjkim	srlx		$len, 4, $len
298289848Sjkim	alignaddrl	$out, %g0, $out
299289848Sjkim	bz		%icc, .L${bits}_cbc_dec_loop2x
300289848Sjkim	prefetch	[$out], 22
301289848Sjkim.L${bits}_cbc_dec_loop:
302289848Sjkim	ldx		[$inp + 0], %o0
303289848Sjkim	brz,pt		$ileft, 4f
304289848Sjkim	ldx		[$inp + 8], %o1
305289848Sjkim
306289848Sjkim	ldx		[$inp + 16], %o2
307289848Sjkim	sllx		%o0, $ileft, %o0
308289848Sjkim	srlx		%o1, $iright, %g1
309289848Sjkim	sllx		%o1, $ileft, %o1
310289848Sjkim	or		%g1, %o0, %o0
311289848Sjkim	srlx		%o2, $iright, %o2
312289848Sjkim	or		%o2, %o1, %o1
313289848Sjkim4:
314289848Sjkim	xor		%g4, %o0, %o2		! ^= rk[0]
315289848Sjkim	xor		%g5, %o1, %o3
316289848Sjkim	movxtod		%o2, %f0
317289848Sjkim	movxtod		%o3, %f2
318289848Sjkim
319289848Sjkim	prefetch	[$out + 63], 22
320289848Sjkim	prefetch	[$inp + 16+63], 20
321289848Sjkim	call		_${alg}${bits}_decrypt_1x
322289848Sjkim	add		$inp, 16, $inp
323289848Sjkim
324289848Sjkim	fxor		%f12, %f0, %f0		! ^= ivec
325289848Sjkim	fxor		%f14, %f2, %f2
326289848Sjkim	movxtod		%o0, %f12
327289848Sjkim	movxtod		%o1, %f14
328289848Sjkim
329289848Sjkim	brnz,pn		$ooff, 2f
330289848Sjkim	sub		$len, 1, $len
331289848Sjkim
332289848Sjkim	std		%f0, [$out + 0]
333289848Sjkim	std		%f2, [$out + 8]
334289848Sjkim	brnz,pt		$len, .L${bits}_cbc_dec_loop2x
335289848Sjkim	add		$out, 16, $out
336289848Sjkim___
337289848Sjkim$::code.=<<___ if ($::evp);
338289848Sjkim	st		%f12, [$ivec + 0]
339289848Sjkim	st		%f13, [$ivec + 4]
340289848Sjkim	st		%f14, [$ivec + 8]
341289848Sjkim	st		%f15, [$ivec + 12]
342289848Sjkim___
343289848Sjkim$::code.=<<___ if (!$::evp);
344289848Sjkim	brnz,pn		$ivoff, .L${bits}_cbc_dec_unaligned_ivec
345289848Sjkim	nop
346289848Sjkim
347289848Sjkim	std		%f12, [$ivec + 0]	! write out ivec
348289848Sjkim	std		%f14, [$ivec + 8]
349289848Sjkim___
350289848Sjkim$::code.=<<___;
351289848Sjkim.L${bits}_cbc_dec_abort:
352289848Sjkim	ret
353289848Sjkim	restore
354289848Sjkim
355289848Sjkim.align	16
356289848Sjkim2:	ldxa		[$inp]0x82, %o0		! avoid read-after-write hazard
357289848Sjkim						! and ~3x deterioration
358289848Sjkim						! in inp==out case
359289848Sjkim	faligndata	%f0, %f0, %f4		! handle unaligned output
360289848Sjkim	faligndata	%f0, %f2, %f6
361289848Sjkim	faligndata	%f2, %f2, %f8
362289848Sjkim
363289848Sjkim	stda		%f4, [$out + $omask]0xc0	! partial store
364289848Sjkim	std		%f6, [$out + 8]
365289848Sjkim	add		$out, 16, $out
366289848Sjkim	orn		%g0, $omask, $omask
367289848Sjkim	stda		%f8, [$out + $omask]0xc0	! partial store
368289848Sjkim
369289848Sjkim	brnz,pt		$len, .L${bits}_cbc_dec_loop2x+4
370289848Sjkim	orn		%g0, $omask, $omask
371289848Sjkim___
372289848Sjkim$::code.=<<___ if ($::evp);
373289848Sjkim	st		%f12, [$ivec + 0]
374289848Sjkim	st		%f13, [$ivec + 4]
375289848Sjkim	st		%f14, [$ivec + 8]
376289848Sjkim	st		%f15, [$ivec + 12]
377289848Sjkim___
378289848Sjkim$::code.=<<___ if (!$::evp);
379289848Sjkim	brnz,pn		$ivoff, .L${bits}_cbc_dec_unaligned_ivec
380289848Sjkim	nop
381289848Sjkim
382289848Sjkim	std		%f12, [$ivec + 0]	! write out ivec
383289848Sjkim	std		%f14, [$ivec + 8]
384289848Sjkim___
385289848Sjkim$::code.=<<___;
386289848Sjkim	ret
387289848Sjkim	restore
388289848Sjkim
389289848Sjkim!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
390289848Sjkim.align	32
391289848Sjkim.L${bits}_cbc_dec_loop2x:
392289848Sjkim	ldx		[$inp + 0], %o0
393289848Sjkim	ldx		[$inp + 8], %o1
394289848Sjkim	ldx		[$inp + 16], %o2
395289848Sjkim	brz,pt		$ileft, 4f
396289848Sjkim	ldx		[$inp + 24], %o3
397289848Sjkim
398289848Sjkim	ldx		[$inp + 32], %o4
399289848Sjkim	sllx		%o0, $ileft, %o0
400289848Sjkim	srlx		%o1, $iright, %g1
401289848Sjkim	or		%g1, %o0, %o0
402289848Sjkim	sllx		%o1, $ileft, %o1
403289848Sjkim	srlx		%o2, $iright, %g1
404289848Sjkim	or		%g1, %o1, %o1
405289848Sjkim	sllx		%o2, $ileft, %o2
406289848Sjkim	srlx		%o3, $iright, %g1
407289848Sjkim	or		%g1, %o2, %o2
408289848Sjkim	sllx		%o3, $ileft, %o3
409289848Sjkim	srlx		%o4, $iright, %o4
410289848Sjkim	or		%o4, %o3, %o3
411289848Sjkim4:
412289848Sjkim	xor		%g4, %o0, %o4		! ^= rk[0]
413289848Sjkim	xor		%g5, %o1, %o5
414289848Sjkim	movxtod		%o4, %f0
415289848Sjkim	movxtod		%o5, %f2
416289848Sjkim	xor		%g4, %o2, %o4
417289848Sjkim	xor		%g5, %o3, %o5
418289848Sjkim	movxtod		%o4, %f4
419289848Sjkim	movxtod		%o5, %f6
420289848Sjkim
421289848Sjkim	prefetch	[$out + 63], 22
422289848Sjkim	prefetch	[$inp + 32+63], 20
423289848Sjkim	call		_${alg}${bits}_decrypt_2x
424289848Sjkim	add		$inp, 32, $inp
425289848Sjkim
426289848Sjkim	movxtod		%o0, %f8
427289848Sjkim	movxtod		%o1, %f10
428289848Sjkim	fxor		%f12, %f0, %f0		! ^= ivec
429289848Sjkim	fxor		%f14, %f2, %f2
430289848Sjkim	movxtod		%o2, %f12
431289848Sjkim	movxtod		%o3, %f14
432289848Sjkim	fxor		%f8, %f4, %f4
433289848Sjkim	fxor		%f10, %f6, %f6
434289848Sjkim
435289848Sjkim	brnz,pn		$ooff, 2f
436289848Sjkim	sub		$len, 2, $len
437289848Sjkim
438289848Sjkim	std		%f0, [$out + 0]
439289848Sjkim	std		%f2, [$out + 8]
440289848Sjkim	std		%f4, [$out + 16]
441289848Sjkim	std		%f6, [$out + 24]
442289848Sjkim	brnz,pt		$len, .L${bits}_cbc_dec_loop2x
443289848Sjkim	add		$out, 32, $out
444289848Sjkim___
445289848Sjkim$::code.=<<___ if ($::evp);
446289848Sjkim	st		%f12, [$ivec + 0]
447289848Sjkim	st		%f13, [$ivec + 4]
448289848Sjkim	st		%f14, [$ivec + 8]
449289848Sjkim	st		%f15, [$ivec + 12]
450289848Sjkim___
451289848Sjkim$::code.=<<___ if (!$::evp);
452289848Sjkim	brnz,pn		$ivoff, .L${bits}_cbc_dec_unaligned_ivec
453289848Sjkim	nop
454289848Sjkim
455289848Sjkim	std		%f12, [$ivec + 0]	! write out ivec
456289848Sjkim	std		%f14, [$ivec + 8]
457289848Sjkim___
458289848Sjkim$::code.=<<___;
459289848Sjkim	ret
460289848Sjkim	restore
461289848Sjkim
462289848Sjkim.align	16
463289848Sjkim2:	ldxa		[$inp]0x82, %o0		! avoid read-after-write hazard
464289848Sjkim						! and ~3x deterioration
465289848Sjkim						! in inp==out case
466289848Sjkim	faligndata	%f0, %f0, %f8		! handle unaligned output
467289848Sjkim	faligndata	%f0, %f2, %f0
468289848Sjkim	faligndata	%f2, %f4, %f2
469289848Sjkim	faligndata	%f4, %f6, %f4
470289848Sjkim	faligndata	%f6, %f6, %f6
471289848Sjkim	stda		%f8, [$out + $omask]0xc0	! partial store
472289848Sjkim	std		%f0, [$out + 8]
473289848Sjkim	std		%f2, [$out + 16]
474289848Sjkim	std		%f4, [$out + 24]
475289848Sjkim	add		$out, 32, $out
476289848Sjkim	orn		%g0, $omask, $omask
477289848Sjkim	stda		%f6, [$out + $omask]0xc0	! partial store
478289848Sjkim
479289848Sjkim	brnz,pt		$len, .L${bits}_cbc_dec_loop2x+4
480289848Sjkim	orn		%g0, $omask, $omask
481289848Sjkim___
482289848Sjkim$::code.=<<___ if ($::evp);
483289848Sjkim	st		%f12, [$ivec + 0]
484289848Sjkim	st		%f13, [$ivec + 4]
485289848Sjkim	st		%f14, [$ivec + 8]
486289848Sjkim	st		%f15, [$ivec + 12]
487289848Sjkim___
488289848Sjkim$::code.=<<___ if (!$::evp);
489289848Sjkim	brnz,pn		$ivoff, .L${bits}_cbc_dec_unaligned_ivec
490289848Sjkim	nop
491289848Sjkim
492289848Sjkim	std		%f12, [$ivec + 0]	! write out ivec
493289848Sjkim	std		%f14, [$ivec + 8]
494289848Sjkim	ret
495289848Sjkim	restore
496289848Sjkim
497289848Sjkim.align	16
498289848Sjkim.L${bits}_cbc_dec_unaligned_ivec:
499289848Sjkim	alignaddrl	$ivec, $ivoff, %g0	! handle unaligned ivec
500289848Sjkim	mov		0xff, $omask
501289848Sjkim	srl		$omask, $ivoff, $omask
502289848Sjkim	faligndata	%f12, %f12, %f0
503289848Sjkim	faligndata	%f12, %f14, %f2
504289848Sjkim	faligndata	%f14, %f14, %f4
505289848Sjkim	stda		%f0, [$ivec + $omask]0xc0
506289848Sjkim	std		%f2, [$ivec + 8]
507289848Sjkim	add		$ivec, 16, $ivec
508289848Sjkim	orn		%g0, $omask, $omask
509289848Sjkim	stda		%f4, [$ivec + $omask]0xc0
510289848Sjkim___
511289848Sjkim$::code.=<<___;
512289848Sjkim	ret
513289848Sjkim	restore
514289848Sjkim
515289848Sjkim!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
516289848Sjkim.align	32
517289848Sjkim.L${bits}cbc_dec_blk:
518289848Sjkim	add	$out, $len, $blk_init
519289848Sjkim	and	$blk_init, 63, $blk_init	! tail
520289848Sjkim	sub	$len, $blk_init, $len
521289848Sjkim	add	$blk_init, 15, $blk_init	! round up to 16n
522289848Sjkim	srlx	$len, 4, $len
523289848Sjkim	srl	$blk_init, 4, $blk_init
524289848Sjkim	sub	$len, 1, $len
525289848Sjkim	add	$blk_init, 1, $blk_init
526289848Sjkim
527289848Sjkim.L${bits}_cbc_dec_blk_loop2x:
528289848Sjkim	ldx		[$inp + 0], %o0
529289848Sjkim	ldx		[$inp + 8], %o1
530289848Sjkim	ldx		[$inp + 16], %o2
531289848Sjkim	brz,pt		$ileft, 5f
532289848Sjkim	ldx		[$inp + 24], %o3
533289848Sjkim
534289848Sjkim	ldx		[$inp + 32], %o4
535289848Sjkim	sllx		%o0, $ileft, %o0
536289848Sjkim	srlx		%o1, $iright, %g1
537289848Sjkim	or		%g1, %o0, %o0
538289848Sjkim	sllx		%o1, $ileft, %o1
539289848Sjkim	srlx		%o2, $iright, %g1
540289848Sjkim	or		%g1, %o1, %o1
541289848Sjkim	sllx		%o2, $ileft, %o2
542289848Sjkim	srlx		%o3, $iright, %g1
543289848Sjkim	or		%g1, %o2, %o2
544289848Sjkim	sllx		%o3, $ileft, %o3
545289848Sjkim	srlx		%o4, $iright, %o4
546289848Sjkim	or		%o4, %o3, %o3
547289848Sjkim5:
548289848Sjkim	xor		%g4, %o0, %o4		! ^= rk[0]
549289848Sjkim	xor		%g5, %o1, %o5
550289848Sjkim	movxtod		%o4, %f0
551289848Sjkim	movxtod		%o5, %f2
552289848Sjkim	xor		%g4, %o2, %o4
553289848Sjkim	xor		%g5, %o3, %o5
554289848Sjkim	movxtod		%o4, %f4
555289848Sjkim	movxtod		%o5, %f6
556289848Sjkim
557289848Sjkim	prefetch	[$inp + 32+63], 20
558289848Sjkim	call		_${alg}${bits}_decrypt_2x
559289848Sjkim	add		$inp, 32, $inp
560289848Sjkim	subcc		$len, 2, $len
561289848Sjkim
562289848Sjkim	movxtod		%o0, %f8
563289848Sjkim	movxtod		%o1, %f10
564289848Sjkim	fxor		%f12, %f0, %f0		! ^= ivec
565289848Sjkim	fxor		%f14, %f2, %f2
566289848Sjkim	movxtod		%o2, %f12
567289848Sjkim	movxtod		%o3, %f14
568289848Sjkim	fxor		%f8, %f4, %f4
569289848Sjkim	fxor		%f10, %f6, %f6
570289848Sjkim
571289848Sjkim	stda		%f0, [$out]0xe2		! ASI_BLK_INIT, T4-specific
572289848Sjkim	add		$out, 8, $out
573289848Sjkim	stda		%f2, [$out]0xe2		! ASI_BLK_INIT, T4-specific
574289848Sjkim	add		$out, 8, $out
575289848Sjkim	stda		%f4, [$out]0xe2		! ASI_BLK_INIT, T4-specific
576289848Sjkim	add		$out, 8, $out
577289848Sjkim	stda		%f6, [$out]0xe2		! ASI_BLK_INIT, T4-specific
578289848Sjkim	bgu,pt		$::size_t_cc, .L${bits}_cbc_dec_blk_loop2x
579289848Sjkim	add		$out, 8, $out
580289848Sjkim
581289848Sjkim	add		$blk_init, $len, $len
582289848Sjkim	andcc		$len, 1, %g0		! is number of blocks even?
583289848Sjkim	membar		#StoreLoad|#StoreStore
584289848Sjkim	bnz,pt		%icc, .L${bits}_cbc_dec_loop
585289848Sjkim	srl		$len, 0, $len
586289848Sjkim	brnz,pn		$len, .L${bits}_cbc_dec_loop2x
587289848Sjkim	nop
588289848Sjkim___
589289848Sjkim$::code.=<<___ if ($::evp);
590289848Sjkim	st		%f12, [$ivec + 0]	! write out ivec
591289848Sjkim	st		%f13, [$ivec + 4]
592289848Sjkim	st		%f14, [$ivec + 8]
593289848Sjkim	st		%f15, [$ivec + 12]
594289848Sjkim___
595289848Sjkim$::code.=<<___ if (!$::evp);
596289848Sjkim	brnz,pn		$ivoff, 3b
597289848Sjkim	nop
598289848Sjkim
599289848Sjkim	std		%f12, [$ivec + 0]	! write out ivec
600289848Sjkim	std		%f14, [$ivec + 8]
601289848Sjkim___
602289848Sjkim$::code.=<<___;
603289848Sjkim	ret
604289848Sjkim	restore
605289848Sjkim.type	${alg}${bits}_t4_cbc_decrypt,#function
606289848Sjkim.size	${alg}${bits}_t4_cbc_decrypt,.-${alg}${bits}_t4_cbc_decrypt
607289848Sjkim___
608289848Sjkim}
609289848Sjkim
610289848Sjkimsub alg_ctr32_implement {
611289848Sjkimmy ($alg,$bits) = @_;
612289848Sjkim
613289848Sjkim$::code.=<<___;
614289848Sjkim.globl	${alg}${bits}_t4_ctr32_encrypt
615289848Sjkim.align	32
616289848Sjkim${alg}${bits}_t4_ctr32_encrypt:
617289848Sjkim	save		%sp, -$::frame, %sp
618306195Sjkim	srln		$len, 0, $len		! needed on v8+, "nop" on v9
619289848Sjkim
620289848Sjkim	prefetch	[$inp], 20
621289848Sjkim	prefetch	[$inp + 63], 20
622289848Sjkim	call		_${alg}${bits}_load_enckey
623289848Sjkim	sllx		$len, 4, $len
624289848Sjkim
625289848Sjkim	ld		[$ivec + 0], %l4	! counter
626289848Sjkim	ld		[$ivec + 4], %l5
627289848Sjkim	ld		[$ivec + 8], %l6
628289848Sjkim	ld		[$ivec + 12], %l7
629289848Sjkim
630289848Sjkim	sllx		%l4, 32, %o5
631289848Sjkim	or		%l5, %o5, %o5
632289848Sjkim	sllx		%l6, 32, %g1
633289848Sjkim	xor		%o5, %g4, %g4		! ^= rk[0]
634289848Sjkim	xor		%g1, %g5, %g5
635289848Sjkim	movxtod		%g4, %f14		! most significant 64 bits
636289848Sjkim
637289848Sjkim	sub		$inp, $out, $blk_init	! $inp!=$out
638289848Sjkim	and		$inp, 7, $ileft
639289848Sjkim	andn		$inp, 7, $inp
640289848Sjkim	sll		$ileft, 3, $ileft
641289848Sjkim	mov		64, $iright
642289848Sjkim	mov		0xff, $omask
643289848Sjkim	sub		$iright, $ileft, $iright
644289848Sjkim	and		$out, 7, $ooff
645289848Sjkim	cmp		$len, 255
646289848Sjkim	movrnz		$ooff, 0, $blk_init		! if (	$out&7 ||
647289848Sjkim	movleu		$::size_t_cc, 0, $blk_init	!	$len<256 ||
648289848Sjkim	brnz,pn		$blk_init, .L${bits}_ctr32_blk	!	$inp==$out)
649289848Sjkim	srl		$omask, $ooff, $omask
650289848Sjkim
651289848Sjkim	andcc		$len, 16, %g0		! is number of blocks even?
652289848Sjkim	alignaddrl	$out, %g0, $out
653289848Sjkim	bz		%icc, .L${bits}_ctr32_loop2x
654289848Sjkim	srlx		$len, 4, $len
655289848Sjkim.L${bits}_ctr32_loop:
656289848Sjkim	ldx		[$inp + 0], %o0
657289848Sjkim	brz,pt		$ileft, 4f
658289848Sjkim	ldx		[$inp + 8], %o1
659289848Sjkim
660289848Sjkim	ldx		[$inp + 16], %o2
661289848Sjkim	sllx		%o0, $ileft, %o0
662289848Sjkim	srlx		%o1, $iright, %g1
663289848Sjkim	sllx		%o1, $ileft, %o1
664289848Sjkim	or		%g1, %o0, %o0
665289848Sjkim	srlx		%o2, $iright, %o2
666289848Sjkim	or		%o2, %o1, %o1
667289848Sjkim4:
668289848Sjkim	xor		%g5, %l7, %g1		! ^= rk[0]
669289848Sjkim	add		%l7, 1, %l7
670289848Sjkim	movxtod		%g1, %f2
671289848Sjkim	srl		%l7, 0, %l7		! clruw
672289848Sjkim	prefetch	[$out + 63], 22
673289848Sjkim	prefetch	[$inp + 16+63], 20
674289848Sjkim___
675289848Sjkim$::code.=<<___ if ($alg eq "aes");
676289848Sjkim	aes_eround01	%f16, %f14, %f2, %f4
677289848Sjkim	aes_eround23	%f18, %f14, %f2, %f2
678289848Sjkim___
679289848Sjkim$::code.=<<___ if ($alg eq "cmll");
680289848Sjkim	camellia_f	%f16, %f2, %f14, %f2
681289848Sjkim	camellia_f	%f18, %f14, %f2, %f0
682289848Sjkim___
683289848Sjkim$::code.=<<___;
684289848Sjkim	call		_${alg}${bits}_encrypt_1x+8
685289848Sjkim	add		$inp, 16, $inp
686289848Sjkim
687289848Sjkim	movxtod		%o0, %f10
688289848Sjkim	movxtod		%o1, %f12
689289848Sjkim	fxor		%f10, %f0, %f0		! ^= inp
690289848Sjkim	fxor		%f12, %f2, %f2
691289848Sjkim
692289848Sjkim	brnz,pn		$ooff, 2f
693289848Sjkim	sub		$len, 1, $len
694289848Sjkim
695289848Sjkim	std		%f0, [$out + 0]
696289848Sjkim	std		%f2, [$out + 8]
697289848Sjkim	brnz,pt		$len, .L${bits}_ctr32_loop2x
698289848Sjkim	add		$out, 16, $out
699289848Sjkim
700289848Sjkim	ret
701289848Sjkim	restore
702289848Sjkim
703289848Sjkim.align	16
704289848Sjkim2:	ldxa		[$inp]0x82, %o0		! avoid read-after-write hazard
705289848Sjkim						! and ~3x deterioration
706289848Sjkim						! in inp==out case
707289848Sjkim	faligndata	%f0, %f0, %f4		! handle unaligned output
708289848Sjkim	faligndata	%f0, %f2, %f6
709289848Sjkim	faligndata	%f2, %f2, %f8
710289848Sjkim	stda		%f4, [$out + $omask]0xc0	! partial store
711289848Sjkim	std		%f6, [$out + 8]
712289848Sjkim	add		$out, 16, $out
713289848Sjkim	orn		%g0, $omask, $omask
714289848Sjkim	stda		%f8, [$out + $omask]0xc0	! partial store
715289848Sjkim
716289848Sjkim	brnz,pt		$len, .L${bits}_ctr32_loop2x+4
717289848Sjkim	orn		%g0, $omask, $omask
718289848Sjkim
719289848Sjkim	ret
720289848Sjkim	restore
721289848Sjkim
722289848Sjkim!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
723289848Sjkim.align	32
724289848Sjkim.L${bits}_ctr32_loop2x:
725289848Sjkim	ldx		[$inp + 0], %o0
726289848Sjkim	ldx		[$inp + 8], %o1
727289848Sjkim	ldx		[$inp + 16], %o2
728289848Sjkim	brz,pt		$ileft, 4f
729289848Sjkim	ldx		[$inp + 24], %o3
730289848Sjkim
731289848Sjkim	ldx		[$inp + 32], %o4
732289848Sjkim	sllx		%o0, $ileft, %o0
733289848Sjkim	srlx		%o1, $iright, %g1
734289848Sjkim	or		%g1, %o0, %o0
735289848Sjkim	sllx		%o1, $ileft, %o1
736289848Sjkim	srlx		%o2, $iright, %g1
737289848Sjkim	or		%g1, %o1, %o1
738289848Sjkim	sllx		%o2, $ileft, %o2
739289848Sjkim	srlx		%o3, $iright, %g1
740289848Sjkim	or		%g1, %o2, %o2
741289848Sjkim	sllx		%o3, $ileft, %o3
742289848Sjkim	srlx		%o4, $iright, %o4
743289848Sjkim	or		%o4, %o3, %o3
744289848Sjkim4:
745289848Sjkim	xor		%g5, %l7, %g1		! ^= rk[0]
746289848Sjkim	add		%l7, 1, %l7
747289848Sjkim	movxtod		%g1, %f2
748289848Sjkim	srl		%l7, 0, %l7		! clruw
749289848Sjkim	xor		%g5, %l7, %g1
750289848Sjkim	add		%l7, 1, %l7
751289848Sjkim	movxtod		%g1, %f6
752289848Sjkim	srl		%l7, 0, %l7		! clruw
753289848Sjkim	prefetch	[$out + 63], 22
754289848Sjkim	prefetch	[$inp + 32+63], 20
755289848Sjkim___
756289848Sjkim$::code.=<<___ if ($alg eq "aes");
757289848Sjkim	aes_eround01	%f16, %f14, %f2, %f8
758289848Sjkim	aes_eround23	%f18, %f14, %f2, %f2
759289848Sjkim	aes_eround01	%f16, %f14, %f6, %f10
760289848Sjkim	aes_eround23	%f18, %f14, %f6, %f6
761289848Sjkim___
762289848Sjkim$::code.=<<___ if ($alg eq "cmll");
763289848Sjkim	camellia_f	%f16, %f2, %f14, %f2
764289848Sjkim	camellia_f	%f16, %f6, %f14, %f6
765289848Sjkim	camellia_f	%f18, %f14, %f2, %f0
766289848Sjkim	camellia_f	%f18, %f14, %f6, %f4
767289848Sjkim___
768289848Sjkim$::code.=<<___;
769289848Sjkim	call		_${alg}${bits}_encrypt_2x+16
770289848Sjkim	add		$inp, 32, $inp
771289848Sjkim
772289848Sjkim	movxtod		%o0, %f8
773289848Sjkim	movxtod		%o1, %f10
774289848Sjkim	movxtod		%o2, %f12
775289848Sjkim	fxor		%f8, %f0, %f0		! ^= inp
776289848Sjkim	movxtod		%o3, %f8
777289848Sjkim	fxor		%f10, %f2, %f2
778289848Sjkim	fxor		%f12, %f4, %f4
779289848Sjkim	fxor		%f8, %f6, %f6
780289848Sjkim
781289848Sjkim	brnz,pn		$ooff, 2f
782289848Sjkim	sub		$len, 2, $len
783289848Sjkim
784289848Sjkim	std		%f0, [$out + 0]
785289848Sjkim	std		%f2, [$out + 8]
786289848Sjkim	std		%f4, [$out + 16]
787289848Sjkim	std		%f6, [$out + 24]
788289848Sjkim	brnz,pt		$len, .L${bits}_ctr32_loop2x
789289848Sjkim	add		$out, 32, $out
790289848Sjkim
791289848Sjkim	ret
792289848Sjkim	restore
793289848Sjkim
794289848Sjkim.align	16
795289848Sjkim2:	ldxa		[$inp]0x82, %o0		! avoid read-after-write hazard
796289848Sjkim						! and ~3x deterioration
797289848Sjkim						! in inp==out case
798289848Sjkim	faligndata	%f0, %f0, %f8		! handle unaligned output
799289848Sjkim	faligndata	%f0, %f2, %f0
800289848Sjkim	faligndata	%f2, %f4, %f2
801289848Sjkim	faligndata	%f4, %f6, %f4
802289848Sjkim	faligndata	%f6, %f6, %f6
803289848Sjkim
804289848Sjkim	stda		%f8, [$out + $omask]0xc0	! partial store
805289848Sjkim	std		%f0, [$out + 8]
806289848Sjkim	std		%f2, [$out + 16]
807289848Sjkim	std		%f4, [$out + 24]
808289848Sjkim	add		$out, 32, $out
809289848Sjkim	orn		%g0, $omask, $omask
810289848Sjkim	stda		%f6, [$out + $omask]0xc0	! partial store
811289848Sjkim
812289848Sjkim	brnz,pt		$len, .L${bits}_ctr32_loop2x+4
813289848Sjkim	orn		%g0, $omask, $omask
814289848Sjkim
815289848Sjkim	ret
816289848Sjkim	restore
817289848Sjkim
818289848Sjkim!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
819289848Sjkim.align	32
820289848Sjkim.L${bits}_ctr32_blk:
821289848Sjkim	add	$out, $len, $blk_init
822289848Sjkim	and	$blk_init, 63, $blk_init	! tail
823289848Sjkim	sub	$len, $blk_init, $len
824289848Sjkim	add	$blk_init, 15, $blk_init	! round up to 16n
825289848Sjkim	srlx	$len, 4, $len
826289848Sjkim	srl	$blk_init, 4, $blk_init
827289848Sjkim	sub	$len, 1, $len
828289848Sjkim	add	$blk_init, 1, $blk_init
829289848Sjkim
830289848Sjkim.L${bits}_ctr32_blk_loop2x:
831289848Sjkim	ldx		[$inp + 0], %o0
832289848Sjkim	ldx		[$inp + 8], %o1
833289848Sjkim	ldx		[$inp + 16], %o2
834289848Sjkim	brz,pt		$ileft, 5f
835289848Sjkim	ldx		[$inp + 24], %o3
836289848Sjkim
837289848Sjkim	ldx		[$inp + 32], %o4
838289848Sjkim	sllx		%o0, $ileft, %o0
839289848Sjkim	srlx		%o1, $iright, %g1
840289848Sjkim	or		%g1, %o0, %o0
841289848Sjkim	sllx		%o1, $ileft, %o1
842289848Sjkim	srlx		%o2, $iright, %g1
843289848Sjkim	or		%g1, %o1, %o1
844289848Sjkim	sllx		%o2, $ileft, %o2
845289848Sjkim	srlx		%o3, $iright, %g1
846289848Sjkim	or		%g1, %o2, %o2
847289848Sjkim	sllx		%o3, $ileft, %o3
848289848Sjkim	srlx		%o4, $iright, %o4
849289848Sjkim	or		%o4, %o3, %o3
850289848Sjkim5:
851289848Sjkim	xor		%g5, %l7, %g1		! ^= rk[0]
852289848Sjkim	add		%l7, 1, %l7
853289848Sjkim	movxtod		%g1, %f2
854289848Sjkim	srl		%l7, 0, %l7		! clruw
855289848Sjkim	xor		%g5, %l7, %g1
856289848Sjkim	add		%l7, 1, %l7
857289848Sjkim	movxtod		%g1, %f6
858289848Sjkim	srl		%l7, 0, %l7		! clruw
859289848Sjkim	prefetch	[$inp + 32+63], 20
860289848Sjkim___
861289848Sjkim$::code.=<<___ if ($alg eq "aes");
862289848Sjkim	aes_eround01	%f16, %f14, %f2, %f8
863289848Sjkim	aes_eround23	%f18, %f14, %f2, %f2
864289848Sjkim	aes_eround01	%f16, %f14, %f6, %f10
865289848Sjkim	aes_eround23	%f18, %f14, %f6, %f6
866289848Sjkim___
867289848Sjkim$::code.=<<___ if ($alg eq "cmll");
868289848Sjkim	camellia_f	%f16, %f2, %f14, %f2
869289848Sjkim	camellia_f	%f16, %f6, %f14, %f6
870289848Sjkim	camellia_f	%f18, %f14, %f2, %f0
871289848Sjkim	camellia_f	%f18, %f14, %f6, %f4
872289848Sjkim___
873289848Sjkim$::code.=<<___;
874289848Sjkim	call		_${alg}${bits}_encrypt_2x+16
875289848Sjkim	add		$inp, 32, $inp
876289848Sjkim	subcc		$len, 2, $len
877289848Sjkim
878289848Sjkim	movxtod		%o0, %f8
879289848Sjkim	movxtod		%o1, %f10
880289848Sjkim	movxtod		%o2, %f12
881289848Sjkim	fxor		%f8, %f0, %f0		! ^= inp
882289848Sjkim	movxtod		%o3, %f8
883289848Sjkim	fxor		%f10, %f2, %f2
884289848Sjkim	fxor		%f12, %f4, %f4
885289848Sjkim	fxor		%f8, %f6, %f6
886289848Sjkim
887289848Sjkim	stda		%f0, [$out]0xe2		! ASI_BLK_INIT, T4-specific
888289848Sjkim	add		$out, 8, $out
889289848Sjkim	stda		%f2, [$out]0xe2		! ASI_BLK_INIT, T4-specific
890289848Sjkim	add		$out, 8, $out
891289848Sjkim	stda		%f4, [$out]0xe2		! ASI_BLK_INIT, T4-specific
892289848Sjkim	add		$out, 8, $out
893289848Sjkim	stda		%f6, [$out]0xe2		! ASI_BLK_INIT, T4-specific
894289848Sjkim	bgu,pt		$::size_t_cc, .L${bits}_ctr32_blk_loop2x
895289848Sjkim	add		$out, 8, $out
896289848Sjkim
897289848Sjkim	add		$blk_init, $len, $len
898289848Sjkim	andcc		$len, 1, %g0		! is number of blocks even?
899289848Sjkim	membar		#StoreLoad|#StoreStore
900289848Sjkim	bnz,pt		%icc, .L${bits}_ctr32_loop
901289848Sjkim	srl		$len, 0, $len
902289848Sjkim	brnz,pn		$len, .L${bits}_ctr32_loop2x
903289848Sjkim	nop
904289848Sjkim
905289848Sjkim	ret
906289848Sjkim	restore
907289848Sjkim.type	${alg}${bits}_t4_ctr32_encrypt,#function
908289848Sjkim.size	${alg}${bits}_t4_ctr32_encrypt,.-${alg}${bits}_t4_ctr32_encrypt
909289848Sjkim___
910289848Sjkim}
911289848Sjkim
912289848Sjkimsub alg_xts_implement {
913289848Sjkimmy ($alg,$bits,$dir) = @_;
914289848Sjkimmy ($inp,$out,$len,$key1,$key2,$ivec)=map("%i$_",(0..5));
915289848Sjkimmy $rem=$ivec;
916289848Sjkim
917289848Sjkim$::code.=<<___;
918289848Sjkim.globl	${alg}${bits}_t4_xts_${dir}crypt
919289848Sjkim.align	32
920289848Sjkim${alg}${bits}_t4_xts_${dir}crypt:
921289848Sjkim	save		%sp, -$::frame-16, %sp
922306195Sjkim	srln		$len, 0, $len		! needed on v8+, "nop" on v9
923289848Sjkim
924289848Sjkim	mov		$ivec, %o0
925289848Sjkim	add		%fp, $::bias-16, %o1
926289848Sjkim	call		${alg}_t4_encrypt
927289848Sjkim	mov		$key2, %o2
928289848Sjkim
929289848Sjkim	add		%fp, $::bias-16, %l7
930289848Sjkim	ldxa		[%l7]0x88, %g2
931289848Sjkim	add		%fp, $::bias-8, %l7
932289848Sjkim	ldxa		[%l7]0x88, %g3		! %g3:%g2 is tweak
933289848Sjkim
934289848Sjkim	sethi		%hi(0x76543210), %l7
935289848Sjkim	or		%l7, %lo(0x76543210), %l7
936289848Sjkim	bmask		%l7, %g0, %g0		! byte swap mask
937289848Sjkim
938289848Sjkim	prefetch	[$inp], 20
939289848Sjkim	prefetch	[$inp + 63], 20
940289848Sjkim	call		_${alg}${bits}_load_${dir}ckey
941289848Sjkim	and		$len, 15,  $rem
942289848Sjkim	and		$len, -16, $len
943289848Sjkim___
944289848Sjkim$code.=<<___ if ($dir eq "de");
945289848Sjkim	mov		0, %l7
946289848Sjkim	movrnz		$rem, 16,  %l7
947289848Sjkim	sub		$len, %l7, $len
948289848Sjkim___
949289848Sjkim$code.=<<___;
950289848Sjkim
951289848Sjkim	sub		$inp, $out, $blk_init	! $inp!=$out
952289848Sjkim	and		$inp, 7, $ileft
953289848Sjkim	andn		$inp, 7, $inp
954289848Sjkim	sll		$ileft, 3, $ileft
955289848Sjkim	mov		64, $iright
956289848Sjkim	mov		0xff, $omask
957289848Sjkim	sub		$iright, $ileft, $iright
958289848Sjkim	and		$out, 7, $ooff
959289848Sjkim	cmp		$len, 255
960289848Sjkim	movrnz		$ooff, 0, $blk_init		! if (	$out&7 ||
961289848Sjkim	movleu		$::size_t_cc, 0, $blk_init	!	$len<256 ||
962289848Sjkim	brnz,pn		$blk_init, .L${bits}_xts_${dir}blk !	$inp==$out)
963289848Sjkim	srl		$omask, $ooff, $omask
964289848Sjkim
965289848Sjkim	andcc		$len, 16, %g0		! is number of blocks even?
966289848Sjkim___
967289848Sjkim$code.=<<___ if ($dir eq "de");
968289848Sjkim	brz,pn		$len, .L${bits}_xts_${dir}steal
969289848Sjkim___
970289848Sjkim$code.=<<___;
971289848Sjkim	alignaddrl	$out, %g0, $out
972289848Sjkim	bz		%icc, .L${bits}_xts_${dir}loop2x
973289848Sjkim	srlx		$len, 4, $len
974289848Sjkim.L${bits}_xts_${dir}loop:
975289848Sjkim	ldx		[$inp + 0], %o0
976289848Sjkim	brz,pt		$ileft, 4f
977289848Sjkim	ldx		[$inp + 8], %o1
978289848Sjkim
979289848Sjkim	ldx		[$inp + 16], %o2
980289848Sjkim	sllx		%o0, $ileft, %o0
981289848Sjkim	srlx		%o1, $iright, %g1
982289848Sjkim	sllx		%o1, $ileft, %o1
983289848Sjkim	or		%g1, %o0, %o0
984289848Sjkim	srlx		%o2, $iright, %o2
985289848Sjkim	or		%o2, %o1, %o1
986289848Sjkim4:
987289848Sjkim	movxtod		%g2, %f12
988289848Sjkim	movxtod		%g3, %f14
989289848Sjkim	bshuffle	%f12, %f12, %f12
990289848Sjkim	bshuffle	%f14, %f14, %f14
991289848Sjkim
992289848Sjkim	xor		%g4, %o0, %o0		! ^= rk[0]
993289848Sjkim	xor		%g5, %o1, %o1
994289848Sjkim	movxtod		%o0, %f0
995289848Sjkim	movxtod		%o1, %f2
996289848Sjkim
997289848Sjkim	fxor		%f12, %f0, %f0		! ^= tweak[0]
998289848Sjkim	fxor		%f14, %f2, %f2
999289848Sjkim
1000289848Sjkim	prefetch	[$out + 63], 22
1001289848Sjkim	prefetch	[$inp + 16+63], 20
1002289848Sjkim	call		_${alg}${bits}_${dir}crypt_1x
1003289848Sjkim	add		$inp, 16, $inp
1004289848Sjkim
1005289848Sjkim	fxor		%f12, %f0, %f0		! ^= tweak[0]
1006289848Sjkim	fxor		%f14, %f2, %f2
1007289848Sjkim
1008289848Sjkim	srax		%g3, 63, %l7		! next tweak value
1009289848Sjkim	addcc		%g2, %g2, %g2
1010289848Sjkim	and		%l7, 0x87, %l7
1011289848Sjkim	addxc		%g3, %g3, %g3
1012289848Sjkim	xor		%l7, %g2, %g2
1013289848Sjkim
1014289848Sjkim	brnz,pn		$ooff, 2f
1015289848Sjkim	sub		$len, 1, $len
1016289848Sjkim
1017289848Sjkim	std		%f0, [$out + 0]
1018289848Sjkim	std		%f2, [$out + 8]
1019289848Sjkim	brnz,pt		$len, .L${bits}_xts_${dir}loop2x
1020289848Sjkim	add		$out, 16, $out
1021289848Sjkim
1022289848Sjkim	brnz,pn		$rem, .L${bits}_xts_${dir}steal
1023289848Sjkim	nop
1024289848Sjkim
1025289848Sjkim	ret
1026289848Sjkim	restore
1027289848Sjkim
1028289848Sjkim.align	16
1029289848Sjkim2:	ldxa		[$inp]0x82, %o0		! avoid read-after-write hazard
1030289848Sjkim						! and ~3x deterioration
1031289848Sjkim						! in inp==out case
1032289848Sjkim	faligndata	%f0, %f0, %f4		! handle unaligned output
1033289848Sjkim	faligndata	%f0, %f2, %f6
1034289848Sjkim	faligndata	%f2, %f2, %f8
1035289848Sjkim	stda		%f4, [$out + $omask]0xc0	! partial store
1036289848Sjkim	std		%f6, [$out + 8]
1037289848Sjkim	add		$out, 16, $out
1038289848Sjkim	orn		%g0, $omask, $omask
1039289848Sjkim	stda		%f8, [$out + $omask]0xc0	! partial store
1040289848Sjkim
1041289848Sjkim	brnz,pt		$len, .L${bits}_xts_${dir}loop2x+4
1042289848Sjkim	orn		%g0, $omask, $omask
1043289848Sjkim
1044289848Sjkim	brnz,pn		$rem, .L${bits}_xts_${dir}steal
1045289848Sjkim	nop
1046289848Sjkim
1047289848Sjkim	ret
1048289848Sjkim	restore
1049289848Sjkim
1050289848Sjkim!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1051289848Sjkim.align	32
1052289848Sjkim.L${bits}_xts_${dir}loop2x:
1053289848Sjkim	ldx		[$inp + 0], %o0
1054289848Sjkim	ldx		[$inp + 8], %o1
1055289848Sjkim	ldx		[$inp + 16], %o2
1056289848Sjkim	brz,pt		$ileft, 4f
1057289848Sjkim	ldx		[$inp + 24], %o3
1058289848Sjkim
1059289848Sjkim	ldx		[$inp + 32], %o4
1060289848Sjkim	sllx		%o0, $ileft, %o0
1061289848Sjkim	srlx		%o1, $iright, %g1
1062289848Sjkim	or		%g1, %o0, %o0
1063289848Sjkim	sllx		%o1, $ileft, %o1
1064289848Sjkim	srlx		%o2, $iright, %g1
1065289848Sjkim	or		%g1, %o1, %o1
1066289848Sjkim	sllx		%o2, $ileft, %o2
1067289848Sjkim	srlx		%o3, $iright, %g1
1068289848Sjkim	or		%g1, %o2, %o2
1069289848Sjkim	sllx		%o3, $ileft, %o3
1070289848Sjkim	srlx		%o4, $iright, %o4
1071289848Sjkim	or		%o4, %o3, %o3
1072289848Sjkim4:
1073289848Sjkim	movxtod		%g2, %f12
1074289848Sjkim	movxtod		%g3, %f14
1075289848Sjkim	bshuffle	%f12, %f12, %f12
1076289848Sjkim	bshuffle	%f14, %f14, %f14
1077289848Sjkim
1078289848Sjkim	srax		%g3, 63, %l7		! next tweak value
1079289848Sjkim	addcc		%g2, %g2, %g2
1080289848Sjkim	and		%l7, 0x87, %l7
1081289848Sjkim	addxc		%g3, %g3, %g3
1082289848Sjkim	xor		%l7, %g2, %g2
1083289848Sjkim
1084289848Sjkim	movxtod		%g2, %f8
1085289848Sjkim	movxtod		%g3, %f10
1086289848Sjkim	bshuffle	%f8,  %f8,  %f8
1087289848Sjkim	bshuffle	%f10, %f10, %f10
1088289848Sjkim
1089289848Sjkim	xor		%g4, %o0, %o0		! ^= rk[0]
1090289848Sjkim	xor		%g5, %o1, %o1
1091289848Sjkim	xor		%g4, %o2, %o2		! ^= rk[0]
1092289848Sjkim	xor		%g5, %o3, %o3
1093289848Sjkim	movxtod		%o0, %f0
1094289848Sjkim	movxtod		%o1, %f2
1095289848Sjkim	movxtod		%o2, %f4
1096289848Sjkim	movxtod		%o3, %f6
1097289848Sjkim
1098289848Sjkim	fxor		%f12, %f0, %f0		! ^= tweak[0]
1099289848Sjkim	fxor		%f14, %f2, %f2
1100289848Sjkim	fxor		%f8,  %f4, %f4		! ^= tweak[0]
1101289848Sjkim	fxor		%f10, %f6, %f6
1102289848Sjkim
1103289848Sjkim	prefetch	[$out + 63], 22
1104289848Sjkim	prefetch	[$inp + 32+63], 20
1105289848Sjkim	call		_${alg}${bits}_${dir}crypt_2x
1106289848Sjkim	add		$inp, 32, $inp
1107289848Sjkim
1108289848Sjkim	movxtod		%g2, %f8
1109289848Sjkim	movxtod		%g3, %f10
1110289848Sjkim
1111289848Sjkim	srax		%g3, 63, %l7		! next tweak value
1112289848Sjkim	addcc		%g2, %g2, %g2
1113289848Sjkim	and		%l7, 0x87, %l7
1114289848Sjkim	addxc		%g3, %g3, %g3
1115289848Sjkim	xor		%l7, %g2, %g2
1116289848Sjkim
1117289848Sjkim	bshuffle	%f8,  %f8,  %f8
1118289848Sjkim	bshuffle	%f10, %f10, %f10
1119289848Sjkim
1120289848Sjkim	fxor		%f12, %f0, %f0		! ^= tweak[0]
1121289848Sjkim	fxor		%f14, %f2, %f2
1122289848Sjkim	fxor		%f8,  %f4, %f4
1123289848Sjkim	fxor		%f10, %f6, %f6
1124289848Sjkim
1125289848Sjkim	brnz,pn		$ooff, 2f
1126289848Sjkim	sub		$len, 2, $len
1127289848Sjkim
1128289848Sjkim	std		%f0, [$out + 0]
1129289848Sjkim	std		%f2, [$out + 8]
1130289848Sjkim	std		%f4, [$out + 16]
1131289848Sjkim	std		%f6, [$out + 24]
1132289848Sjkim	brnz,pt		$len, .L${bits}_xts_${dir}loop2x
1133289848Sjkim	add		$out, 32, $out
1134289848Sjkim
1135289848Sjkim	fsrc2		%f4, %f0
1136289848Sjkim	fsrc2		%f6, %f2
1137289848Sjkim	brnz,pn		$rem, .L${bits}_xts_${dir}steal
1138289848Sjkim	nop
1139289848Sjkim
1140289848Sjkim	ret
1141289848Sjkim	restore
1142289848Sjkim
1143289848Sjkim.align	16
1144289848Sjkim2:	ldxa		[$inp]0x82, %o0		! avoid read-after-write hazard
1145289848Sjkim						! and ~3x deterioration
1146289848Sjkim						! in inp==out case
1147289848Sjkim	faligndata	%f0, %f0, %f8		! handle unaligned output
1148289848Sjkim	faligndata	%f0, %f2, %f10
1149289848Sjkim	faligndata	%f2, %f4, %f12
1150289848Sjkim	faligndata	%f4, %f6, %f14
1151289848Sjkim	faligndata	%f6, %f6, %f0
1152289848Sjkim
1153289848Sjkim	stda		%f8, [$out + $omask]0xc0	! partial store
1154289848Sjkim	std		%f10, [$out + 8]
1155289848Sjkim	std		%f12, [$out + 16]
1156289848Sjkim	std		%f14, [$out + 24]
1157289848Sjkim	add		$out, 32, $out
1158289848Sjkim	orn		%g0, $omask, $omask
1159289848Sjkim	stda		%f0, [$out + $omask]0xc0	! partial store
1160289848Sjkim
1161289848Sjkim	brnz,pt		$len, .L${bits}_xts_${dir}loop2x+4
1162289848Sjkim	orn		%g0, $omask, $omask
1163289848Sjkim
1164289848Sjkim	fsrc2		%f4, %f0
1165289848Sjkim	fsrc2		%f6, %f2
1166289848Sjkim	brnz,pn		$rem, .L${bits}_xts_${dir}steal
1167289848Sjkim	nop
1168289848Sjkim
1169289848Sjkim	ret
1170289848Sjkim	restore
1171289848Sjkim
1172289848Sjkim!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1173289848Sjkim.align	32
1174289848Sjkim.L${bits}_xts_${dir}blk:
1175289848Sjkim	add	$out, $len, $blk_init
1176289848Sjkim	and	$blk_init, 63, $blk_init	! tail
1177289848Sjkim	sub	$len, $blk_init, $len
1178289848Sjkim	add	$blk_init, 15, $blk_init	! round up to 16n
1179289848Sjkim	srlx	$len, 4, $len
1180289848Sjkim	srl	$blk_init, 4, $blk_init
1181289848Sjkim	sub	$len, 1, $len
1182289848Sjkim	add	$blk_init, 1, $blk_init
1183289848Sjkim
1184289848Sjkim.L${bits}_xts_${dir}blk2x:
1185289848Sjkim	ldx		[$inp + 0], %o0
1186289848Sjkim	ldx		[$inp + 8], %o1
1187289848Sjkim	ldx		[$inp + 16], %o2
1188289848Sjkim	brz,pt		$ileft, 5f
1189289848Sjkim	ldx		[$inp + 24], %o3
1190289848Sjkim
1191289848Sjkim	ldx		[$inp + 32], %o4
1192289848Sjkim	sllx		%o0, $ileft, %o0
1193289848Sjkim	srlx		%o1, $iright, %g1
1194289848Sjkim	or		%g1, %o0, %o0
1195289848Sjkim	sllx		%o1, $ileft, %o1
1196289848Sjkim	srlx		%o2, $iright, %g1
1197289848Sjkim	or		%g1, %o1, %o1
1198289848Sjkim	sllx		%o2, $ileft, %o2
1199289848Sjkim	srlx		%o3, $iright, %g1
1200289848Sjkim	or		%g1, %o2, %o2
1201289848Sjkim	sllx		%o3, $ileft, %o3
1202289848Sjkim	srlx		%o4, $iright, %o4
1203289848Sjkim	or		%o4, %o3, %o3
1204289848Sjkim5:
1205289848Sjkim	movxtod		%g2, %f12
1206289848Sjkim	movxtod		%g3, %f14
1207289848Sjkim	bshuffle	%f12, %f12, %f12
1208289848Sjkim	bshuffle	%f14, %f14, %f14
1209289848Sjkim
1210289848Sjkim	srax		%g3, 63, %l7		! next tweak value
1211289848Sjkim	addcc		%g2, %g2, %g2
1212289848Sjkim	and		%l7, 0x87, %l7
1213289848Sjkim	addxc		%g3, %g3, %g3
1214289848Sjkim	xor		%l7, %g2, %g2
1215289848Sjkim
1216289848Sjkim	movxtod		%g2, %f8
1217289848Sjkim	movxtod		%g3, %f10
1218289848Sjkim	bshuffle	%f8,  %f8,  %f8
1219289848Sjkim	bshuffle	%f10, %f10, %f10
1220289848Sjkim
1221289848Sjkim	xor		%g4, %o0, %o0		! ^= rk[0]
1222289848Sjkim	xor		%g5, %o1, %o1
1223289848Sjkim	xor		%g4, %o2, %o2		! ^= rk[0]
1224289848Sjkim	xor		%g5, %o3, %o3
1225289848Sjkim	movxtod		%o0, %f0
1226289848Sjkim	movxtod		%o1, %f2
1227289848Sjkim	movxtod		%o2, %f4
1228289848Sjkim	movxtod		%o3, %f6
1229289848Sjkim
1230289848Sjkim	fxor		%f12, %f0, %f0		! ^= tweak[0]
1231289848Sjkim	fxor		%f14, %f2, %f2
1232289848Sjkim	fxor		%f8,  %f4, %f4		! ^= tweak[0]
1233289848Sjkim	fxor		%f10, %f6, %f6
1234289848Sjkim
1235289848Sjkim	prefetch	[$inp + 32+63], 20
1236289848Sjkim	call		_${alg}${bits}_${dir}crypt_2x
1237289848Sjkim	add		$inp, 32, $inp
1238289848Sjkim
1239289848Sjkim	movxtod		%g2, %f8
1240289848Sjkim	movxtod		%g3, %f10
1241289848Sjkim
1242289848Sjkim	srax		%g3, 63, %l7		! next tweak value
1243289848Sjkim	addcc		%g2, %g2, %g2
1244289848Sjkim	and		%l7, 0x87, %l7
1245289848Sjkim	addxc		%g3, %g3, %g3
1246289848Sjkim	xor		%l7, %g2, %g2
1247289848Sjkim
1248289848Sjkim	bshuffle	%f8,  %f8,  %f8
1249289848Sjkim	bshuffle	%f10, %f10, %f10
1250289848Sjkim
1251289848Sjkim	fxor		%f12, %f0, %f0		! ^= tweak[0]
1252289848Sjkim	fxor		%f14, %f2, %f2
1253289848Sjkim	fxor		%f8,  %f4, %f4
1254289848Sjkim	fxor		%f10, %f6, %f6
1255289848Sjkim
1256289848Sjkim	subcc		$len, 2, $len
1257289848Sjkim	stda		%f0, [$out]0xe2		! ASI_BLK_INIT, T4-specific
1258289848Sjkim	add		$out, 8, $out
1259289848Sjkim	stda		%f2, [$out]0xe2		! ASI_BLK_INIT, T4-specific
1260289848Sjkim	add		$out, 8, $out
1261289848Sjkim	stda		%f4, [$out]0xe2		! ASI_BLK_INIT, T4-specific
1262289848Sjkim	add		$out, 8, $out
1263289848Sjkim	stda		%f6, [$out]0xe2		! ASI_BLK_INIT, T4-specific
1264289848Sjkim	bgu,pt		$::size_t_cc, .L${bits}_xts_${dir}blk2x
1265289848Sjkim	add		$out, 8, $out
1266289848Sjkim
1267289848Sjkim	add		$blk_init, $len, $len
1268289848Sjkim	andcc		$len, 1, %g0		! is number of blocks even?
1269289848Sjkim	membar		#StoreLoad|#StoreStore
1270289848Sjkim	bnz,pt		%icc, .L${bits}_xts_${dir}loop
1271289848Sjkim	srl		$len, 0, $len
1272289848Sjkim	brnz,pn		$len, .L${bits}_xts_${dir}loop2x
1273289848Sjkim	nop
1274289848Sjkim
1275289848Sjkim	fsrc2		%f4, %f0
1276289848Sjkim	fsrc2		%f6, %f2
1277289848Sjkim	brnz,pn		$rem, .L${bits}_xts_${dir}steal
1278289848Sjkim	nop
1279289848Sjkim
1280289848Sjkim	ret
1281289848Sjkim	restore
1282289848Sjkim!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1283289848Sjkim___
1284289848Sjkim$code.=<<___ if ($dir eq "en");
1285289848Sjkim.align	32
1286289848Sjkim.L${bits}_xts_${dir}steal:
1287289848Sjkim	std		%f0, [%fp + $::bias-16]	! copy of output
1288289848Sjkim	std		%f2, [%fp + $::bias-8]
1289289848Sjkim
1290289848Sjkim	srl		$ileft, 3, $ileft
1291289848Sjkim	add		%fp, $::bias-16, %l7
1292289848Sjkim	add		$inp, $ileft, $inp	! original $inp+$len&-15
1293289848Sjkim	add		$out, $ooff, $out	! original $out+$len&-15
1294289848Sjkim	mov		0, $ileft
1295289848Sjkim	nop					! align
1296289848Sjkim
1297289848Sjkim.L${bits}_xts_${dir}stealing:
1298289848Sjkim	ldub		[$inp + $ileft], %o0
1299289848Sjkim	ldub		[%l7  + $ileft], %o1
1300289848Sjkim	dec		$rem
1301289848Sjkim	stb		%o0, [%l7  + $ileft]
1302289848Sjkim	stb		%o1, [$out + $ileft]
1303289848Sjkim	brnz		$rem, .L${bits}_xts_${dir}stealing
1304289848Sjkim	inc		$ileft
1305289848Sjkim
1306289848Sjkim	mov		%l7, $inp
1307289848Sjkim	sub		$out, 16, $out
1308289848Sjkim	mov		0, $ileft
1309289848Sjkim	sub		$out, $ooff, $out
1310289848Sjkim	ba		.L${bits}_xts_${dir}loop	! one more time
1311289848Sjkim	mov		1, $len				! $rem is 0
1312289848Sjkim___
1313289848Sjkim$code.=<<___ if ($dir eq "de");
1314289848Sjkim.align	32
1315289848Sjkim.L${bits}_xts_${dir}steal:
1316289848Sjkim	ldx		[$inp + 0], %o0
1317289848Sjkim	brz,pt		$ileft, 8f
1318289848Sjkim	ldx		[$inp + 8], %o1
1319289848Sjkim
1320289848Sjkim	ldx		[$inp + 16], %o2
1321289848Sjkim	sllx		%o0, $ileft, %o0
1322289848Sjkim	srlx		%o1, $iright, %g1
1323289848Sjkim	sllx		%o1, $ileft, %o1
1324289848Sjkim	or		%g1, %o0, %o0
1325289848Sjkim	srlx		%o2, $iright, %o2
1326289848Sjkim	or		%o2, %o1, %o1
1327289848Sjkim8:
1328289848Sjkim	srax		%g3, 63, %l7		! next tweak value
1329289848Sjkim	addcc		%g2, %g2, %o2
1330289848Sjkim	and		%l7, 0x87, %l7
1331289848Sjkim	addxc		%g3, %g3, %o3
1332289848Sjkim	xor		%l7, %o2, %o2
1333289848Sjkim
1334289848Sjkim	movxtod		%o2, %f12
1335289848Sjkim	movxtod		%o3, %f14
1336289848Sjkim	bshuffle	%f12, %f12, %f12
1337289848Sjkim	bshuffle	%f14, %f14, %f14
1338289848Sjkim
1339289848Sjkim	xor		%g4, %o0, %o0		! ^= rk[0]
1340289848Sjkim	xor		%g5, %o1, %o1
1341289848Sjkim	movxtod		%o0, %f0
1342289848Sjkim	movxtod		%o1, %f2
1343289848Sjkim
1344289848Sjkim	fxor		%f12, %f0, %f0		! ^= tweak[0]
1345289848Sjkim	fxor		%f14, %f2, %f2
1346289848Sjkim
1347289848Sjkim	call		_${alg}${bits}_${dir}crypt_1x
1348289848Sjkim	add		$inp, 16, $inp
1349289848Sjkim
1350289848Sjkim	fxor		%f12, %f0, %f0		! ^= tweak[0]
1351289848Sjkim	fxor		%f14, %f2, %f2
1352289848Sjkim
1353289848Sjkim	std		%f0, [%fp + $::bias-16]
1354289848Sjkim	std		%f2, [%fp + $::bias-8]
1355289848Sjkim
1356289848Sjkim	srl		$ileft, 3, $ileft
1357289848Sjkim	add		%fp, $::bias-16, %l7
1358289848Sjkim	add		$inp, $ileft, $inp	! original $inp+$len&-15
1359289848Sjkim	add		$out, $ooff, $out	! original $out+$len&-15
1360289848Sjkim	mov		0, $ileft
1361289848Sjkim	add		$out, 16, $out
1362289848Sjkim	nop					! align
1363289848Sjkim
1364289848Sjkim.L${bits}_xts_${dir}stealing:
1365289848Sjkim	ldub		[$inp + $ileft], %o0
1366289848Sjkim	ldub		[%l7  + $ileft], %o1
1367289848Sjkim	dec		$rem
1368289848Sjkim	stb		%o0, [%l7  + $ileft]
1369289848Sjkim	stb		%o1, [$out + $ileft]
1370289848Sjkim	brnz		$rem, .L${bits}_xts_${dir}stealing
1371289848Sjkim	inc		$ileft
1372289848Sjkim
1373289848Sjkim	mov		%l7, $inp
1374289848Sjkim	sub		$out, 16, $out
1375289848Sjkim	mov		0, $ileft
1376289848Sjkim	sub		$out, $ooff, $out
1377289848Sjkim	ba		.L${bits}_xts_${dir}loop	! one more time
1378289848Sjkim	mov		1, $len				! $rem is 0
1379289848Sjkim___
1380289848Sjkim$code.=<<___;
1381289848Sjkim	ret
1382289848Sjkim	restore
1383289848Sjkim.type	${alg}${bits}_t4_xts_${dir}crypt,#function
1384289848Sjkim.size	${alg}${bits}_t4_xts_${dir}crypt,.-${alg}${bits}_t4_xts_${dir}crypt
1385289848Sjkim___
1386289848Sjkim}
1387289848Sjkim
1388289848Sjkim# Purpose of these subroutines is to explicitly encode VIS instructions,
1389289848Sjkim# so that one can compile the module without having to specify VIS
1390289848Sjkim# extentions on compiler command line, e.g. -xarch=v9 vs. -xarch=v9a.
1391289848Sjkim# Idea is to reserve for option to produce "universal" binary and let
1392289848Sjkim# programmer detect if current CPU is VIS capable at run-time.
1393289848Sjkimsub unvis {
1394289848Sjkimmy ($mnemonic,$rs1,$rs2,$rd)=@_;
1395289848Sjkimmy ($ref,$opf);
1396289848Sjkimmy %visopf = (	"faligndata"	=> 0x048,
1397289848Sjkim		"bshuffle"	=> 0x04c,
1398289848Sjkim		"fnot2"		=> 0x066,
1399289848Sjkim		"fxor"		=> 0x06c,
1400289848Sjkim		"fsrc2"		=> 0x078	);
1401289848Sjkim
1402289848Sjkim    $ref = "$mnemonic\t$rs1,$rs2,$rd";
1403289848Sjkim
1404289848Sjkim    if ($opf=$visopf{$mnemonic}) {
1405289848Sjkim	foreach ($rs1,$rs2,$rd) {
1406289848Sjkim	    return $ref if (!/%f([0-9]{1,2})/);
1407289848Sjkim	    $_=$1;
1408289848Sjkim	    if ($1>=32) {
1409289848Sjkim		return $ref if ($1&1);
1410289848Sjkim		# re-encode for upper double register addressing
1411289848Sjkim		$_=($1|$1>>5)&31;
1412289848Sjkim	    }
1413289848Sjkim	}
1414289848Sjkim
1415289848Sjkim	return	sprintf ".word\t0x%08x !%s",
1416289848Sjkim			0x81b00000|$rd<<25|$rs1<<14|$opf<<5|$rs2,
1417289848Sjkim			$ref;
1418289848Sjkim    } else {
1419289848Sjkim	return $ref;
1420289848Sjkim    }
1421289848Sjkim}
1422289848Sjkim
1423289848Sjkimsub unvis3 {
1424289848Sjkimmy ($mnemonic,$rs1,$rs2,$rd)=@_;
1425289848Sjkimmy %bias = ( "g" => 0, "o" => 8, "l" => 16, "i" => 24 );
1426289848Sjkimmy ($ref,$opf);
1427289848Sjkimmy %visopf = (	"addxc"		=> 0x011,
1428289848Sjkim		"addxccc"	=> 0x013,
1429289848Sjkim		"umulxhi"	=> 0x016,
1430289848Sjkim		"alignaddr"	=> 0x018,
1431289848Sjkim		"bmask"		=> 0x019,
1432289848Sjkim		"alignaddrl"	=> 0x01a	);
1433289848Sjkim
1434289848Sjkim    $ref = "$mnemonic\t$rs1,$rs2,$rd";
1435289848Sjkim
1436289848Sjkim    if ($opf=$visopf{$mnemonic}) {
1437289848Sjkim	foreach ($rs1,$rs2,$rd) {
1438289848Sjkim	    return $ref if (!/%([goli])([0-9])/);
1439289848Sjkim	    $_=$bias{$1}+$2;
1440289848Sjkim	}
1441289848Sjkim
1442289848Sjkim	return	sprintf ".word\t0x%08x !%s",
1443289848Sjkim			0x81b00000|$rd<<25|$rs1<<14|$opf<<5|$rs2,
1444289848Sjkim			$ref;
1445289848Sjkim    } else {
1446289848Sjkim	return $ref;
1447289848Sjkim    }
1448289848Sjkim}
1449289848Sjkim
1450289848Sjkimsub unaes_round {	# 4-argument instructions
1451289848Sjkimmy ($mnemonic,$rs1,$rs2,$rs3,$rd)=@_;
1452289848Sjkimmy ($ref,$opf);
1453289848Sjkimmy %aesopf = (	"aes_eround01"	=> 0,
1454289848Sjkim		"aes_eround23"	=> 1,
1455289848Sjkim		"aes_dround01"	=> 2,
1456289848Sjkim		"aes_dround23"	=> 3,
1457289848Sjkim		"aes_eround01_l"=> 4,
1458289848Sjkim		"aes_eround23_l"=> 5,
1459289848Sjkim		"aes_dround01_l"=> 6,
1460289848Sjkim		"aes_dround23_l"=> 7,
1461289848Sjkim		"aes_kexpand1"	=> 8	);
1462289848Sjkim
1463289848Sjkim    $ref = "$mnemonic\t$rs1,$rs2,$rs3,$rd";
1464289848Sjkim
1465289848Sjkim    if (defined($opf=$aesopf{$mnemonic})) {
1466289848Sjkim	$rs3 = ($rs3 =~ /%f([0-6]*[02468])/) ? (($1|$1>>5)&31) : $rs3;
1467289848Sjkim	foreach ($rs1,$rs2,$rd) {
1468289848Sjkim	    return $ref if (!/%f([0-9]{1,2})/);
1469289848Sjkim	    $_=$1;
1470289848Sjkim	    if ($1>=32) {
1471289848Sjkim		return $ref if ($1&1);
1472289848Sjkim		# re-encode for upper double register addressing
1473289848Sjkim		$_=($1|$1>>5)&31;
1474289848Sjkim	    }
1475289848Sjkim	}
1476289848Sjkim
1477289848Sjkim	return	sprintf ".word\t0x%08x !%s",
1478289848Sjkim			2<<30|$rd<<25|0x19<<19|$rs1<<14|$rs3<<9|$opf<<5|$rs2,
1479289848Sjkim			$ref;
1480289848Sjkim    } else {
1481289848Sjkim	return $ref;
1482289848Sjkim    }
1483289848Sjkim}
1484289848Sjkim
1485289848Sjkimsub unaes_kexpand {	# 3-argument instructions
1486289848Sjkimmy ($mnemonic,$rs1,$rs2,$rd)=@_;
1487289848Sjkimmy ($ref,$opf);
1488289848Sjkimmy %aesopf = (	"aes_kexpand0"	=> 0x130,
1489289848Sjkim		"aes_kexpand2"	=> 0x131	);
1490289848Sjkim
1491289848Sjkim    $ref = "$mnemonic\t$rs1,$rs2,$rd";
1492289848Sjkim
1493289848Sjkim    if (defined($opf=$aesopf{$mnemonic})) {
1494289848Sjkim	foreach ($rs1,$rs2,$rd) {
1495289848Sjkim	    return $ref if (!/%f([0-9]{1,2})/);
1496289848Sjkim	    $_=$1;
1497289848Sjkim	    if ($1>=32) {
1498289848Sjkim		return $ref if ($1&1);
1499289848Sjkim		# re-encode for upper double register addressing
1500289848Sjkim		$_=($1|$1>>5)&31;
1501289848Sjkim	    }
1502289848Sjkim	}
1503289848Sjkim
1504289848Sjkim	return	sprintf ".word\t0x%08x !%s",
1505289848Sjkim			2<<30|$rd<<25|0x36<<19|$rs1<<14|$opf<<5|$rs2,
1506289848Sjkim			$ref;
1507289848Sjkim    } else {
1508289848Sjkim	return $ref;
1509289848Sjkim    }
1510289848Sjkim}
1511289848Sjkim
1512289848Sjkimsub uncamellia_f {	# 4-argument instructions
1513289848Sjkimmy ($mnemonic,$rs1,$rs2,$rs3,$rd)=@_;
1514289848Sjkimmy ($ref,$opf);
1515289848Sjkim
1516289848Sjkim    $ref = "$mnemonic\t$rs1,$rs2,$rs3,$rd";
1517289848Sjkim
1518289848Sjkim    if (1) {
1519289848Sjkim	$rs3 = ($rs3 =~ /%f([0-6]*[02468])/) ? (($1|$1>>5)&31) : $rs3;
1520289848Sjkim	foreach ($rs1,$rs2,$rd) {
1521289848Sjkim	    return $ref if (!/%f([0-9]{1,2})/);
1522289848Sjkim	    $_=$1;
1523289848Sjkim	    if ($1>=32) {
1524289848Sjkim		return $ref if ($1&1);
1525289848Sjkim		# re-encode for upper double register addressing
1526289848Sjkim		$_=($1|$1>>5)&31;
1527289848Sjkim	    }
1528289848Sjkim	}
1529289848Sjkim
1530289848Sjkim	return	sprintf ".word\t0x%08x !%s",
1531289848Sjkim			2<<30|$rd<<25|0x19<<19|$rs1<<14|$rs3<<9|0xc<<5|$rs2,
1532289848Sjkim			$ref;
1533289848Sjkim    } else {
1534289848Sjkim	return $ref;
1535289848Sjkim    }
1536289848Sjkim}
1537289848Sjkim
1538289848Sjkimsub uncamellia3 {	# 3-argument instructions
1539289848Sjkimmy ($mnemonic,$rs1,$rs2,$rd)=@_;
1540289848Sjkimmy ($ref,$opf);
1541289848Sjkimmy %cmllopf = (	"camellia_fl"	=> 0x13c,
1542289848Sjkim		"camellia_fli"	=> 0x13d	);
1543289848Sjkim
1544289848Sjkim    $ref = "$mnemonic\t$rs1,$rs2,$rd";
1545289848Sjkim
1546289848Sjkim    if (defined($opf=$cmllopf{$mnemonic})) {
1547289848Sjkim	foreach ($rs1,$rs2,$rd) {
1548289848Sjkim	    return $ref if (!/%f([0-9]{1,2})/);
1549289848Sjkim	    $_=$1;
1550289848Sjkim	    if ($1>=32) {
1551289848Sjkim		return $ref if ($1&1);
1552289848Sjkim		# re-encode for upper double register addressing
1553289848Sjkim		$_=($1|$1>>5)&31;
1554289848Sjkim	    }
1555289848Sjkim	}
1556289848Sjkim
1557289848Sjkim	return	sprintf ".word\t0x%08x !%s",
1558289848Sjkim			2<<30|$rd<<25|0x36<<19|$rs1<<14|$opf<<5|$rs2,
1559289848Sjkim			$ref;
1560289848Sjkim    } else {
1561289848Sjkim	return $ref;
1562289848Sjkim    }
1563289848Sjkim}
1564289848Sjkim
1565289848Sjkimsub unmovxtox {		# 2-argument instructions
1566289848Sjkimmy ($mnemonic,$rs,$rd)=@_;
1567289848Sjkimmy %bias = ( "g" => 0, "o" => 8, "l" => 16, "i" => 24, "f" => 0 );
1568289848Sjkimmy ($ref,$opf);
1569289848Sjkimmy %movxopf = (	"movdtox"	=> 0x110,
1570289848Sjkim		"movstouw"	=> 0x111,
1571289848Sjkim		"movstosw"	=> 0x113,
1572289848Sjkim		"movxtod"	=> 0x118,
1573289848Sjkim		"movwtos"	=> 0x119	);
1574289848Sjkim
1575289848Sjkim    $ref = "$mnemonic\t$rs,$rd";
1576289848Sjkim
1577289848Sjkim    if (defined($opf=$movxopf{$mnemonic})) {
1578289848Sjkim	foreach ($rs,$rd) {
1579289848Sjkim	    return $ref if (!/%([fgoli])([0-9]{1,2})/);
1580289848Sjkim	    $_=$bias{$1}+$2;
1581289848Sjkim	    if ($2>=32) {
1582289848Sjkim		return $ref if ($2&1);
1583289848Sjkim		# re-encode for upper double register addressing
1584289848Sjkim		$_=($2|$2>>5)&31;
1585289848Sjkim	    }
1586289848Sjkim	}
1587289848Sjkim
1588289848Sjkim	return	sprintf ".word\t0x%08x !%s",
1589289848Sjkim			2<<30|$rd<<25|0x36<<19|$opf<<5|$rs,
1590289848Sjkim			$ref;
1591289848Sjkim    } else {
1592289848Sjkim	return $ref;
1593289848Sjkim    }
1594289848Sjkim}
1595289848Sjkim
1596289848Sjkimsub undes {
1597289848Sjkimmy ($mnemonic)=shift;
1598289848Sjkimmy @args=@_;
1599289848Sjkimmy ($ref,$opf);
1600289848Sjkimmy %desopf = (	"des_round"	=> 0b1001,
1601289848Sjkim		"des_ip"	=> 0b100110100,
1602289848Sjkim		"des_iip"	=> 0b100110101,
1603289848Sjkim		"des_kexpand"	=> 0b100110110	);
1604289848Sjkim
1605289848Sjkim    $ref = "$mnemonic\t".join(",",@_);
1606289848Sjkim
1607289848Sjkim    if (defined($opf=$desopf{$mnemonic})) {	# 4-arg
1608289848Sjkim	if ($mnemonic eq "des_round") {
1609289848Sjkim	    foreach (@args[0..3]) {
1610289848Sjkim		return $ref if (!/%f([0-9]{1,2})/);
1611289848Sjkim		$_=$1;
1612289848Sjkim		if ($1>=32) {
1613289848Sjkim		    return $ref if ($1&1);
1614289848Sjkim		    # re-encode for upper double register addressing
1615289848Sjkim		    $_=($1|$1>>5)&31;
1616289848Sjkim		}
1617289848Sjkim	    }
1618289848Sjkim	    return  sprintf ".word\t0x%08x !%s",
1619289848Sjkim			    2<<30|0b011001<<19|$opf<<5|$args[0]<<14|$args[1]|$args[2]<<9|$args[3]<<25,
1620289848Sjkim			    $ref;
1621289848Sjkim	} elsif ($mnemonic eq "des_kexpand") {	# 3-arg
1622289848Sjkim	    foreach (@args[0..2]) {
1623289848Sjkim		return $ref if (!/(%f)?([0-9]{1,2})/);
1624289848Sjkim		$_=$2;
1625289848Sjkim		if ($2>=32) {
1626289848Sjkim		    return $ref if ($2&1);
1627289848Sjkim		    # re-encode for upper double register addressing
1628289848Sjkim		    $_=($2|$2>>5)&31;
1629289848Sjkim		}
1630289848Sjkim	    }
1631289848Sjkim	    return  sprintf ".word\t0x%08x !%s",
1632289848Sjkim			    2<<30|0b110110<<19|$opf<<5|$args[0]<<14|$args[1]|$args[2]<<25,
1633289848Sjkim			    $ref;
1634289848Sjkim	} else {				# 2-arg
1635289848Sjkim	    foreach (@args[0..1]) {
1636289848Sjkim		return $ref if (!/%f([0-9]{1,2})/);
1637289848Sjkim		$_=$1;
1638289848Sjkim		if ($1>=32) {
1639289848Sjkim		    return $ref if ($2&1);
1640289848Sjkim		    # re-encode for upper double register addressing
1641289848Sjkim		    $_=($1|$1>>5)&31;
1642289848Sjkim		}
1643289848Sjkim	    }
1644289848Sjkim	    return  sprintf ".word\t0x%08x !%s",
1645289848Sjkim			    2<<30|0b110110<<19|$opf<<5|$args[0]<<14|$args[1]<<25,
1646289848Sjkim			    $ref;
1647289848Sjkim	}
1648289848Sjkim    } else {
1649289848Sjkim	return $ref;
1650289848Sjkim    }
1651289848Sjkim}
1652289848Sjkim
1653289848Sjkimsub emit_assembler {
1654289848Sjkim    foreach (split("\n",$::code)) {
1655289848Sjkim	s/\`([^\`]*)\`/eval $1/ge;
1656289848Sjkim
1657289848Sjkim	s/\b(f[a-z]+2[sd]*)\s+(%f[0-9]{1,2}),\s*(%f[0-9]{1,2})\s*$/$1\t%f0,$2,$3/go;
1658289848Sjkim
1659289848Sjkim	s/\b(aes_[edk][^\s]*)\s+(%f[0-9]{1,2}),\s*(%f[0-9]{1,2}),\s*([%fx0-9]+),\s*(%f[0-9]{1,2})/
1660289848Sjkim		&unaes_round($1,$2,$3,$4,$5)
1661289848Sjkim	 /geo or
1662289848Sjkim	s/\b(aes_kexpand[02])\s+(%f[0-9]{1,2}),\s*(%f[0-9]{1,2}),\s*(%f[0-9]{1,2})/
1663289848Sjkim		&unaes_kexpand($1,$2,$3,$4)
1664289848Sjkim	 /geo or
1665289848Sjkim	s/\b(camellia_f)\s+(%f[0-9]{1,2}),\s*(%f[0-9]{1,2}),\s*([%fx0-9]+),\s*(%f[0-9]{1,2})/
1666289848Sjkim		&uncamellia_f($1,$2,$3,$4,$5)
1667289848Sjkim	 /geo or
1668289848Sjkim	s/\b(camellia_[^s]+)\s+(%f[0-9]{1,2}),\s*(%f[0-9]{1,2}),\s*(%f[0-9]{1,2})/
1669289848Sjkim		&uncamellia3($1,$2,$3,$4)
1670289848Sjkim	 /geo or
1671289848Sjkim	s/\b(des_\w+)\s+(%f[0-9]{1,2}),\s*([%fx0-9]+)(?:,\s*(%f[0-9]{1,2})(?:,\s*(%f[0-9]{1,2}))?)?/
1672289848Sjkim		&undes($1,$2,$3,$4,$5)
1673289848Sjkim	 /geo or
1674289848Sjkim	s/\b(mov[ds]to\w+)\s+(%f[0-9]{1,2}),\s*(%[goli][0-7])/
1675289848Sjkim		&unmovxtox($1,$2,$3)
1676289848Sjkim	 /geo or
1677289848Sjkim	s/\b(mov[xw]to[ds])\s+(%[goli][0-7]),\s*(%f[0-9]{1,2})/
1678289848Sjkim		&unmovxtox($1,$2,$3)
1679289848Sjkim	 /geo or
1680289848Sjkim	s/\b([fb][^\s]*)\s+(%f[0-9]{1,2}),\s*(%f[0-9]{1,2}),\s*(%f[0-9]{1,2})/
1681289848Sjkim		&unvis($1,$2,$3,$4)
1682289848Sjkim	 /geo or
1683289848Sjkim	s/\b(umulxhi|bmask|addxc[c]{0,2}|alignaddr[l]*)\s+(%[goli][0-7]),\s*(%[goli][0-7]),\s*(%[goli][0-7])/
1684289848Sjkim		&unvis3($1,$2,$3,$4)
1685289848Sjkim	 /geo;
1686289848Sjkim
1687289848Sjkim	print $_,"\n";
1688289848Sjkim    }
1689289848Sjkim}
1690289848Sjkim
1691289848Sjkim1;
1692