Add SPARC T4 AES support.
[openssl.git] / crypto / aes / asm / aest4-sparcv9.pl
1 #!/usr/bin/env perl
2
3 # ====================================================================
4 # Written by David S. Miller <davem@devemloft.net> and Andy Polyakov
5 # <appro@openssl.org>. The module is licensed under 2-clause BSD
6 # license. October 2012. All rights reserved.
7 # ====================================================================
8
9 ######################################################################
10 # AES round instructions complete in 3 cycles and can be issued every
11 # cycle. It means that round calculations should take 4*rounds cycles,
12 # because any given round instruction depends on result of *both*
13 # previous instructions:
14 #
15 #       |0 |1 |2 |3 |4
16 #       |01|01|01|
17 #          |23|23|23|
18 #                   |01|01|...
19 #                      |23|...
20 #
21 # Provided that fxor [with IV] takes 3 cycles to complete, critical
22 # path length for CBC encrypt would be 3+4*rounds, or in other words
23 # it should process one byte in at least (3+4*rounds)/16 cycles. This
24 # estimate doesn't account for "collateral" instructions, such as
25 # fetching input from memory, xor-ing it with zero-round key and
26 # storing the result. Yet, *measured* performance [for data aligned
27 # at 64-bit boundary!] deviates from this equation by less than 0.5%:
28 #
29 #               128-bit key     192-            256-
30 # CBC encrypt   2.70/2.90(*)    3.20/3.40       3.70/3.90
31 #                        (*) numbers after slash are for
32 #                            misaligned data.
33 #
34 # Out-of-order execution logic managed to fully overlap "collateral"
35 # instructions with those on critical path. Amazing!
36 #
37 # As with Intel AES-NI, question is if it's possible to improve
38 # performance of parallelizeable modes by interleaving round
39 # instructions. Provided round instruction latency and throughput
40 # optimal interleave factor is 2. But can we expect 2x performance
41 # improvement? Well, as round instructions can be issued one per
42 # cycle, they don't saturate the 2-way issue pipeline and therefore
43 # there is room for "collateral" calculations... Yet, 2x speed-up
44 # over CBC encrypt remains unattaintable:
45 #
46 #               128-bit key     192-            256-
47 # CBC decrypt   1.64/2.11       1.89/2.37       2.23/2.61
48 # CTR           1.64/2.08(*)    1.89/2.33       2.23/2.61
49 #                        (*) numbers after slash are for
50 #                            misaligned data.
51 #
52 # Estimates based on amount of instructions under assumption that
53 # round instructions are not pairable with any other instruction
54 # suggest that latter is the actual case and pipeline runs
55 # underutilized. It should be noted that T4 out-of-order execution
56 # logic is so capable that performance gain from 2x interleave is
57 # not even impressive, ~7-13% over non-interleaved code, largest
58 # for 256-bit keys.
59
60 # To anchor to something else, software implementation processes
61 # one byte in 29 cycles with 128-bit key on same processor. Intel
62 # Sandy Bridge encrypts byte in 5.07 cycles in CBC mode and decrypts
63 # in 0.93, naturally with AES-NI.
64
65 $bits=32;
66 for (@ARGV)     { $bits=64 if (/\-m64/ || /\-xarch\=v9/); }
67 if ($bits==64)  { $bias=2047; $frame=192; }
68 else            { $bias=0;    $frame=112; }
69
70 $evp=1;         # if $evp is set to 0, script generates module with
71 # AES_[en|de]crypt, AES_set_[en|de]crypt_key and AES_cbc_encrypt entry
72 # points. These however are not fully compatible with openssl/aes.h,
73 # because they expect AES_KEY to be aligned at 64-bit boundary. When
74 # used through EVP, alignment is arranged at EVP layer. Second thing
75 # that is arranged by EVP is at least 32-bit alignment of IV.
76
77 ######################################################################
78 # single-round subroutines
79 #
80 {
81 my ($inp,$out,$key,$rounds,$tmp,$mask)=map("%o$_",(0..5));
82
83 $code=<<___;
84 .text
85
86 .globl  aes_t4_encrypt
87 .align  32
88 aes_t4_encrypt:
89         andcc           $inp, 7, %g1            ! is input aligned?
90         andn            $inp, 7, $inp
91
92         ldx             [$key + 0], %g4
93         ldx             [$key + 8], %g5
94
95         ldx             [$inp + 0], %o4
96         bz,pt           %icc, 1f
97         ldx             [$inp + 8], %o5
98         ldx             [$inp + 16], $inp
99         sll             %g1, 3, %g1
100         sub             %g0, %g1, %o3
101         sllx            %o4, %g1, %o4
102         sllx            %o5, %g1, %g1
103         srlx            %o5, %o3, %o5
104         srlx            $inp, %o3, %o3
105         or              %o5, %o4, %o4
106         or              %o3, %g1, %o5
107 1:
108         ld              [$key + 240], $rounds
109         ldd             [$key + 16], %f12
110         ldd             [$key + 24], %f14
111         xor             %g4, %o4, %o4
112         xor             %g5, %o5, %o5
113         movxtod         %o4, %f0
114         movxtod         %o5, %f2
115         srl             $rounds, 1, $rounds
116         ldd             [$key + 32], %f16
117         sub             $rounds, 1, $rounds
118         ldd             [$key + 40], %f18
119         add             $key, 48, $key
120
121 .Lenc:
122         aes_eround01    %f12, %f0, %f2, %f4
123         aes_eround23    %f14, %f0, %f2, %f2
124         ldd             [$key + 0], %f12
125         ldd             [$key + 8], %f14
126         sub             $rounds,1,$rounds
127         aes_eround01    %f16, %f4, %f2, %f0
128         aes_eround23    %f18, %f4, %f2, %f2
129         ldd             [$key + 16], %f16
130         ldd             [$key + 24], %f18
131         brnz,pt         $rounds, .Lenc
132         add             $key, 32, $key
133
134         andcc           $out, 7, $tmp           ! is output aligned?
135         aes_eround01    %f12, %f0, %f2, %f4
136         aes_eround23    %f14, %f0, %f2, %f2
137         aes_eround01_l  %f16, %f4, %f2, %f0
138         aes_eround23_l  %f18, %f4, %f2, %f2
139
140         bnz,pn          %icc, 2f
141         nop
142
143         std             %f0, [$out + 0]
144         retl
145         std             %f2, [$out + 8]
146
147 2:      alignaddrl      $out, %g0, $out
148         mov             0xff, $mask
149         srl             $mask, $tmp, $mask
150
151         faligndata      %f0, %f0, %f4
152         faligndata      %f0, %f2, %f6
153         faligndata      %f2, %f2, %f8
154
155         stda            %f4, [$out + $mask]0xc0 ! partial store
156         std             %f6, [$out + 8]
157         add             $out, 16, $out
158         orn             %g0, $mask, $mask
159         retl
160         stda            %f8, [$out + $mask]0xc0 ! partial store
161 .type   aes_t4_encrypt,#function
162 .size   aes_t4_encrypt,.-aes_t4_encrypt
163
164 .globl  aes_t4_decrypt
165 .align  32
166 aes_t4_decrypt:
167         andcc           $inp, 7, %g1            ! is input aligned?
168         andn            $inp, 7, $inp
169
170         ldx             [$key + 0], %g4
171         ldx             [$key + 8], %g5
172
173         ldx             [$inp + 0], %o4
174         bz,pt           %icc, 1f
175         ldx             [$inp + 8], %o5
176         ldx             [$inp + 16], $inp
177         sll             %g1, 3, %g1
178         sub             %g0, %g1, %o3
179         sllx            %o4, %g1, %o4
180         sllx            %o5, %g1, %g1
181         srlx            %o5, %o3, %o5
182         srlx            $inp, %o3, %o3
183         or              %o5, %o4, %o4
184         or              %o3, %g1, %o5
185 1:
186         ld              [$key + 240], $rounds
187         ldd             [$key + 16], %f12
188         ldd             [$key + 24], %f14
189         xor             %g4, %o4, %o4
190         xor             %g5, %o5, %o5
191         movxtod         %o4, %f0
192         movxtod         %o5, %f2
193         srl             $rounds, 1, $rounds
194         ldd             [$key + 32], %f16
195         sub             $rounds, 1, $rounds
196         ldd             [$key + 40], %f18
197         add             $key, 48, $key
198
199 .Ldec:
200         aes_dround01    %f12, %f0, %f2, %f4
201         aes_dround23    %f14, %f0, %f2, %f2
202         ldd             [$key + 0], %f12
203         ldd             [$key + 8], %f14
204         sub             $rounds,1,$rounds
205         aes_dround01    %f16, %f4, %f2, %f0
206         aes_dround23    %f18, %f4, %f2, %f2
207         ldd             [$key + 16], %f16
208         ldd             [$key + 24], %f18
209         brnz,pt         $rounds, .Ldec
210         add             $key, 32, $key
211
212         andcc           $out, 7, $tmp           ! is output aligned?
213         aes_dround01    %f12, %f0, %f2, %f4
214         aes_dround23    %f14, %f0, %f2, %f2
215         aes_dround01_l  %f16, %f4, %f2, %f0
216         aes_dround23_l  %f18, %f4, %f2, %f2
217
218         bnz,pn          %icc, 2f
219         nop
220
221         std             %f0, [$out + 0]
222         retl
223         std             %f2, [$out + 8]
224
225 2:      alignaddrl      $out, %g0, $out
226         mov             0xff, $mask
227         srl             $mask, $tmp, $mask
228
229         faligndata      %f0, %f0, %f4
230         faligndata      %f0, %f2, %f6
231         faligndata      %f2, %f2, %f8
232
233         stda            %f4, [$out + $mask]0xc0 ! partial store
234         std             %f6, [$out + 8]
235         add             $out, 16, $out
236         orn             %g0, $mask, $mask
237         retl
238         stda            %f8, [$out + $mask]0xc0 ! partial store
239 .type   aes_t4_decrypt,#function
240 .size   aes_t4_decrypt,.-aes_t4_decrypt
241 ___
242 }
243
244 ######################################################################
245 # key setup subroutines
246 #
247 {
248 my ($inp,$bits,$out,$tmp)=map("%o$_",(0..5));
249 $code.=<<___;
250 .globl  aes_t4_set_encrypt_key
251 .align  32
252 aes_t4_set_encrypt_key:
253 .Lset_encrypt_key:
254         and             $inp, 7, $tmp
255         alignaddr       $inp, %g0, $inp
256         cmp             $bits, 192
257         ldd             [$inp + 0], %f0
258         bl,pt           %icc,.L128
259         ldd             [$inp + 8], %f2
260
261         be,pt           %icc,.L192
262         ldd             [$inp + 16], %f4
263         brz,pt          $tmp, .L256aligned
264         ldd             [$inp + 24], %f6
265
266         ldd             [$inp + 32], %f8
267         faligndata      %f0, %f2, %f0
268         faligndata      %f2, %f4, %f2
269         faligndata      %f4, %f6, %f4
270         faligndata      %f6, %f8, %f6
271 .L256aligned:
272 ___
273 for ($i=0; $i<6; $i++) {
274     $code.=<<___;
275         std             %f0, [$out + `32*$i+0`]
276         aes_kexpand1    %f0, %f6, $i, %f0
277         std             %f2, [$out + `32*$i+8`]
278         aes_kexpand2    %f2, %f0, %f2
279         std             %f4, [$out + `32*$i+16`]
280         aes_kexpand0    %f4, %f2, %f4
281         std             %f6, [$out + `32*$i+24`]
282         aes_kexpand2    %f6, %f4, %f6
283 ___
284 }
285 $code.=<<___;
286         std             %f0, [$out + `32*$i+0`]
287         aes_kexpand1    %f0, %f6, $i, %f0
288         std             %f2, [$out + `32*$i+8`]
289         aes_kexpand2    %f2, %f0, %f2
290         std             %f4, [$out + `32*$i+16`]
291         std             %f6, [$out + `32*$i+24`]
292         std             %f0, [$out + `32*$i+32`]
293         std             %f2, [$out + `32*$i+40`]
294
295         mov             14, $tmp
296         st              $tmp, [$out + 240]
297         retl
298         xor             %o0, %o0, %o0
299
300 .align  16
301 .L192:
302         brz,pt          $tmp, .L192aligned
303         nop
304
305         ldd             [$inp + 24], %f6
306         faligndata      %f0, %f2, %f0
307         faligndata      %f2, %f4, %f2
308         faligndata      %f4, %f6, %f4
309 .L192aligned:
310 ___
311 for ($i=0; $i<7; $i++) {
312     $code.=<<___;
313         std             %f0, [$out + `24*$i+0`]
314         aes_kexpand1    %f0, %f4, $i, %f0
315         std             %f2, [$out + `24*$i+8`]
316         aes_kexpand2    %f2, %f0, %f2
317         std             %f4, [$out + `24*$i+16`]
318         aes_kexpand2    %f4, %f2, %f4
319 ___
320 }
321 $code.=<<___;
322         std             %f0, [$out + `24*$i+0`]
323         aes_kexpand1    %f0, %f4, $i, %f0
324         std             %f2, [$out + `24*$i+8`]
325         aes_kexpand2    %f2, %f0, %f2
326         std             %f4, [$out + `24*$i+16`]
327         std             %f0, [$out + `24*$i+24`]
328         std             %f2, [$out + `24*$i+32`]
329
330         mov             12, $tmp
331         st              $tmp, [$out + 240]
332         retl
333         xor             %o0, %o0, %o0
334
335 .align  16
336 .L128:
337         brz,pt          $tmp, .L128aligned
338         nop
339
340         ldd             [$inp + 16], %f4
341         faligndata      %f0, %f2, %f0
342         faligndata      %f2, %f4, %f2
343 .L128aligned:
344 ___
345 for ($i=0; $i<10; $i++) {
346     $code.=<<___;
347         std             %f0, [$out + `16*$i+0`]
348         aes_kexpand1    %f0, %f2, $i, %f0
349         std             %f2, [$out + `16*$i+8`]
350         aes_kexpand2    %f2, %f0, %f2
351 ___
352 }
353 $code.=<<___;
354         std             %f0, [$out + `16*$i+0`]
355         std             %f2, [$out + `16*$i+8`]
356
357         mov             10, $tmp
358         st              $tmp, [$out + 240]
359         retl
360         xor             %o0, %o0, %o0
361 .type   aes_t4_set_encrypt_key,#function
362 .size   aes_t4_set_encrypt_key,.-aes_t4_set_encrypt_key
363
364 .globl  aes_t4_set_decrypt_key
365 .align  32
366 aes_t4_set_decrypt_key:
367         mov             %o7, %o5
368         call            .Lset_encrypt_key
369         nop
370
371         mov             %o5, %o7
372         sll             $tmp, 4, $inp           ! $tmp is number of rounds
373         add             $tmp, 2, $tmp
374         add             $out, $inp, $inp        ! $inp=$out+16*rounds
375         srl             $tmp, 2, $tmp           ! $tmp=(rounds+2)/4
376
377 .Lkey_flip:
378         ldd             [$out + 0],  %f0
379         ldd             [$out + 8],  %f2
380         ldd             [$out + 16], %f4
381         ldd             [$out + 24], %f6
382         ldd             [$inp + 0],  %f8
383         ldd             [$inp + 8],  %f10
384         ldd             [$inp - 16], %f12
385         ldd             [$inp - 8],  %f14
386         sub             $tmp, 1, $tmp
387         std             %f0, [$inp + 0]
388         std             %f2, [$inp + 8]
389         std             %f4, [$inp - 16]
390         std             %f6, [$inp - 8]
391         std             %f8, [$out + 0]
392         std             %f10, [$out + 8]
393         std             %f12, [$out + 16]
394         std             %f14, [$out + 24]
395         add             $out, 32, $out
396         brnz            $tmp, .Lkey_flip
397         sub             $inp, 32, $inp
398
399         retl
400         xor             %o0, %o0, %o0
401 .type   aes_t4_set_decrypt_key,#function
402 .size   aes_t4_set_decrypt_key,.-aes_t4_set_decrypt_key
403 ___
404 }
405
406 {{{
407 my ($inp,$out,$len,$key,$ivec,$enc)=map("%i$_",(0..5));
408 my ($ileft,$iright,$ooff,$omask,$ivoff)=map("%l$_",(1..7));
409
410 $code.=<<___;
411 .align  32
412 _aes128_loadkey:
413         ldx             [$key + 0], %g4
414         ldx             [$key + 8], %g5
415 ___
416 for ($i=2; $i<22;$i++) {                        # load key schedule
417     $code.=<<___;
418         ldd             [$key + `8*$i`], %f`12+2*$i`
419 ___
420 }
421 $code.=<<___;
422         retl
423         nop
424 .type   _aes128_loadkey,#function
425 .size   _aes128_loadkey,.-_aes128_loadkey
426
427 .align  32
428 _aes128_encrypt_1x:
429 ___
430 for ($i=0; $i<4; $i++) {
431     $code.=<<___;
432         aes_eround01    %f`16+8*$i+0`, %f0, %f2, %f4
433         aes_eround23    %f`16+8*$i+2`, %f0, %f2, %f2
434         aes_eround01    %f`16+8*$i+4`, %f4, %f2, %f0
435         aes_eround23    %f`16+8*$i+6`, %f4, %f2, %f2
436 ___
437 }
438 $code.=<<___;
439         aes_eround01    %f48, %f0, %f2, %f4
440         aes_eround23    %f50, %f0, %f2, %f2
441         aes_eround01_l  %f52, %f4, %f2, %f0
442         retl
443         aes_eround23_l  %f54, %f4, %f2, %f2
444 .type   _aes128_encrypt_1x,#function
445 .size   _aes128_encrypt_1x,.-_aes128_encrypt_1x
446
447 .align  32
448 _aes128_encrypt_2x:
449 ___
450 for ($i=0; $i<4; $i++) {
451     $code.=<<___;
452         aes_eround01    %f`16+8*$i+0`, %f0, %f2, %f8
453         aes_eround23    %f`16+8*$i+2`, %f0, %f2, %f2
454         aes_eround01    %f`16+8*$i+0`, %f4, %f6, %f10
455         aes_eround23    %f`16+8*$i+2`, %f4, %f6, %f6
456         aes_eround01    %f`16+8*$i+4`, %f8, %f2, %f0
457         aes_eround23    %f`16+8*$i+6`, %f8, %f2, %f2
458         aes_eround01    %f`16+8*$i+4`, %f10, %f6, %f4
459         aes_eround23    %f`16+8*$i+6`, %f10, %f6, %f6
460 ___
461 }
462 $code.=<<___;
463         aes_eround01    %f48, %f0, %f2, %f8
464         aes_eround23    %f50, %f0, %f2, %f2
465         aes_eround01    %f48, %f4, %f6, %f10
466         aes_eround23    %f50, %f4, %f6, %f6
467         aes_eround01_l  %f52, %f8, %f2, %f0
468         aes_eround23_l  %f54, %f8, %f2, %f2
469         aes_eround01_l  %f52, %f10, %f6, %f4
470         retl
471         aes_eround23_l  %f54, %f10, %f6, %f6
472 .type   _aes128_encrypt_2x,#function
473 .size   _aes128_encrypt_2x,.-_aes128_encrypt_2x
474
475 .align  32
476 _aes128_decrypt_1x:
477 ___
478 for ($i=0; $i<4; $i++) {
479     $code.=<<___;
480         aes_dround01    %f`16+8*$i+0`, %f0, %f2, %f4
481         aes_dround23    %f`16+8*$i+2`, %f0, %f2, %f2
482         aes_dround01    %f`16+8*$i+4`, %f4, %f2, %f0
483         aes_dround23    %f`16+8*$i+6`, %f4, %f2, %f2
484 ___
485 }
486 $code.=<<___;
487         aes_dround01    %f48, %f0, %f2, %f4
488         aes_dround23    %f50, %f0, %f2, %f2
489         aes_dround01_l  %f52, %f4, %f2, %f0
490         retl
491         aes_dround23_l  %f54, %f4, %f2, %f2
492 .type   _aes128_decrypt_1x,#function
493 .size   _aes128_decrypt_1x,.-_aes128_decrypt_1x
494
495 .align  32
496 _aes128_decrypt_2x:
497 ___
498 for ($i=0; $i<4; $i++) {
499     $code.=<<___;
500         aes_dround01    %f`16+8*$i+0`, %f0, %f2, %f8
501         aes_dround23    %f`16+8*$i+2`, %f0, %f2, %f2
502         aes_dround01    %f`16+8*$i+0`, %f4, %f6, %f10
503         aes_dround23    %f`16+8*$i+2`, %f4, %f6, %f6
504         aes_dround01    %f`16+8*$i+4`, %f8, %f2, %f0
505         aes_dround23    %f`16+8*$i+6`, %f8, %f2, %f2
506         aes_dround01    %f`16+8*$i+4`, %f10, %f6, %f4
507         aes_dround23    %f`16+8*$i+6`, %f10, %f6, %f6
508 ___
509 }
510 $code.=<<___;
511         aes_dround01    %f48, %f0, %f2, %f8
512         aes_dround23    %f50, %f0, %f2, %f2
513         aes_dround01    %f48, %f4, %f6, %f10
514         aes_dround23    %f50, %f4, %f6, %f6
515         aes_dround01_l  %f52, %f8, %f2, %f0
516         aes_dround23_l  %f54, %f8, %f2, %f2
517         aes_dround01_l  %f52, %f10, %f6, %f4
518         retl
519         aes_dround23_l  %f54, %f10, %f6, %f6
520 .type   _aes128_decrypt_2x,#function
521 .size   _aes128_decrypt_2x,.-_aes128_decrypt_2x
522
523 .align  32
524 _aes192_loadkey:
525 _aes256_loadkey:
526         ldx             [$key + 0], %g4
527         ldx             [$key + 8], %g5
528 ___
529 for ($i=2; $i<26;$i++) {                        # load key schedule
530     $code.=<<___;
531         ldd             [$key + `8*$i`], %f`12+2*$i`
532 ___
533 }
534 $code.=<<___;
535         retl
536         nop
537 .type   _aes192_loadkey,#function
538 .size   _aes192_loadkey,.-_aes192_loadkey
539
540 .align  32
541 _aes192_encrypt_1x:
542 ___
543 for ($i=0; $i<5; $i++) {
544     $code.=<<___;
545         aes_eround01    %f`16+8*$i+0`, %f0, %f2, %f4
546         aes_eround23    %f`16+8*$i+2`, %f0, %f2, %f2
547         aes_eround01    %f`16+8*$i+4`, %f4, %f2, %f0
548         aes_eround23    %f`16+8*$i+6`, %f4, %f2, %f2
549 ___
550 }
551 $code.=<<___;
552         aes_eround01    %f56, %f0, %f2, %f4
553         aes_eround23    %f58, %f0, %f2, %f2
554         aes_eround01_l  %f60, %f4, %f2, %f0
555         retl
556         aes_eround23_l  %f62, %f4, %f2, %f2
557 .type   _aes192_encrypt_1x,#function
558 .size   _aes192_encrypt_1x,.-_aes192_encrypt_1x
559
560 .align  32
561 _aes192_encrypt_2x:
562 ___
563 for ($i=0; $i<5; $i++) {
564     $code.=<<___;
565         aes_eround01    %f`16+8*$i+0`, %f0, %f2, %f8
566         aes_eround23    %f`16+8*$i+2`, %f0, %f2, %f2
567         aes_eround01    %f`16+8*$i+0`, %f4, %f6, %f10
568         aes_eround23    %f`16+8*$i+2`, %f4, %f6, %f6
569         aes_eround01    %f`16+8*$i+4`, %f8, %f2, %f0
570         aes_eround23    %f`16+8*$i+6`, %f8, %f2, %f2
571         aes_eround01    %f`16+8*$i+4`, %f10, %f6, %f4
572         aes_eround23    %f`16+8*$i+6`, %f10, %f6, %f6
573 ___
574 }
575 $code.=<<___;
576         aes_eround01    %f56, %f0, %f2, %f8
577         aes_eround23    %f58, %f0, %f2, %f2
578         aes_eround01    %f56, %f4, %f6, %f10
579         aes_eround23    %f58, %f4, %f6, %f6
580         aes_eround01_l  %f60, %f8, %f2, %f0
581         aes_eround23_l  %f62, %f8, %f2, %f2
582         aes_eround01_l  %f60, %f10, %f6, %f4
583         retl
584         aes_eround23_l  %f62, %f10, %f6, %f6
585 .type   _aes192_encrypt_2x,#function
586 .size   _aes192_encrypt_2x,.-_aes192_encrypt_2x
587
588 .align  32
589 _aes192_decrypt_1x:
590 ___
591 for ($i=0; $i<5; $i++) {
592     $code.=<<___;
593         aes_dround01    %f`16+8*$i+0`, %f0, %f2, %f4
594         aes_dround23    %f`16+8*$i+2`, %f0, %f2, %f2
595         aes_dround01    %f`16+8*$i+4`, %f4, %f2, %f0
596         aes_dround23    %f`16+8*$i+6`, %f4, %f2, %f2
597 ___
598 }
599 $code.=<<___;
600         aes_dround01    %f56, %f0, %f2, %f4
601         aes_dround23    %f58, %f0, %f2, %f2
602         aes_dround01_l  %f60, %f4, %f2, %f0
603         retl
604         aes_dround23_l  %f62, %f4, %f2, %f2
605 .type   _aes192_decrypt_1x,#function
606 .size   _aes192_decrypt_1x,.-_aes192_decrypt_1x
607
608 .align  32
609 _aes192_decrypt_2x:
610 ___
611 for ($i=0; $i<5; $i++) {
612     $code.=<<___;
613         aes_dround01    %f`16+8*$i+0`, %f0, %f2, %f8
614         aes_dround23    %f`16+8*$i+2`, %f0, %f2, %f2
615         aes_dround01    %f`16+8*$i+0`, %f4, %f6, %f10
616         aes_dround23    %f`16+8*$i+2`, %f4, %f6, %f6
617         aes_dround01    %f`16+8*$i+4`, %f8, %f2, %f0
618         aes_dround23    %f`16+8*$i+6`, %f8, %f2, %f2
619         aes_dround01    %f`16+8*$i+4`, %f10, %f6, %f4
620         aes_dround23    %f`16+8*$i+6`, %f10, %f6, %f6
621 ___
622 }
623 $code.=<<___;
624         aes_dround01    %f56, %f0, %f2, %f8
625         aes_dround23    %f58, %f0, %f2, %f2
626         aes_dround01    %f56, %f4, %f6, %f10
627         aes_dround23    %f58, %f4, %f6, %f6
628         aes_dround01_l  %f60, %f8, %f2, %f0
629         aes_dround23_l  %f62, %f8, %f2, %f2
630         aes_dround01_l  %f60, %f10, %f6, %f4
631         retl
632         aes_dround23_l  %f62, %f10, %f6, %f6
633 .type   _aes192_decrypt_2x,#function
634 .size   _aes192_decrypt_2x,.-_aes192_decrypt_2x
635
636 .align  32
637 _aes256_encrypt_1x:
638         aes_eround01    %f16, %f0, %f2, %f4
639         aes_eround23    %f18, %f0, %f2, %f2
640         ldd             [$key + 208], %f16
641         ldd             [$key + 216], %f18
642         aes_eround01    %f20, %f4, %f2, %f0
643         aes_eround23    %f22, %f4, %f2, %f2
644         ldd             [$key + 224], %f20
645         ldd             [$key + 232], %f22
646 ___
647 for ($i=1; $i<6; $i++) {
648     $code.=<<___;
649         aes_eround01    %f`16+8*$i+0`, %f0, %f2, %f4
650         aes_eround23    %f`16+8*$i+2`, %f0, %f2, %f2
651         aes_eround01    %f`16+8*$i+4`, %f4, %f2, %f0
652         aes_eround23    %f`16+8*$i+6`, %f4, %f2, %f2
653 ___
654 }
655 $code.=<<___;
656         aes_eround01    %f16, %f0, %f2, %f4
657         aes_eround23    %f18, %f0, %f2, %f2
658         ldd             [$key + 16], %f16
659         ldd             [$key + 24], %f18
660         aes_eround01_l  %f20, %f4, %f2, %f0
661         aes_eround23_l  %f22, %f4, %f2, %f2
662         ldd             [$key + 32], %f20
663         retl
664         ldd             [$key + 40], %f22
665 .type   _aes256_encrypt_1x,#function
666 .size   _aes256_encrypt_1x,.-_aes256_encrypt_1x
667
668 .align  32
669 _aes256_encrypt_2x:
670         aes_eround01    %f16, %f0, %f2, %f8
671         aes_eround23    %f18, %f0, %f2, %f2
672         aes_eround01    %f16, %f4, %f6, %f10
673         aes_eround23    %f18, %f4, %f6, %f6
674         ldd             [$key + 208], %f16
675         ldd             [$key + 216], %f18
676         aes_eround01    %f20, %f8, %f2, %f0
677         aes_eround23    %f22, %f8, %f2, %f2
678         aes_eround01    %f20, %f10, %f6, %f4
679         aes_eround23    %f22, %f10, %f6, %f6
680         ldd             [$key + 224], %f20
681         ldd             [$key + 232], %f22
682 ___
683 for ($i=1; $i<6; $i++) {
684     $code.=<<___;
685         aes_eround01    %f`16+8*$i+0`, %f0, %f2, %f8
686         aes_eround23    %f`16+8*$i+2`, %f0, %f2, %f2
687         aes_eround01    %f`16+8*$i+0`, %f4, %f6, %f10
688         aes_eround23    %f`16+8*$i+2`, %f4, %f6, %f6
689         aes_eround01    %f`16+8*$i+4`, %f8, %f2, %f0
690         aes_eround23    %f`16+8*$i+6`, %f8, %f2, %f2
691         aes_eround01    %f`16+8*$i+4`, %f10, %f6, %f4
692         aes_eround23    %f`16+8*$i+6`, %f10, %f6, %f6
693 ___
694 }
695 $code.=<<___;
696         aes_eround01    %f16, %f0, %f2, %f8
697         aes_eround23    %f18, %f0, %f2, %f2
698         aes_eround01    %f16, %f4, %f6, %f10
699         aes_eround23    %f18, %f4, %f6, %f6
700         ldd             [$key + 16], %f16
701         ldd             [$key + 24], %f18
702         aes_eround01_l  %f20, %f8, %f2, %f0
703         aes_eround23_l  %f22, %f8, %f2, %f2
704         aes_eround01_l  %f20, %f10, %f6, %f4
705         aes_eround23_l  %f22, %f10, %f6, %f6
706         ldd             [$key + 32], %f20
707         retl
708         ldd             [$key + 40], %f22
709 .type   _aes256_encrypt_2x,#function
710 .size   _aes256_encrypt_2x,.-_aes256_encrypt_2x
711
712 .align  32
713 _aes256_decrypt_1x:
714         aes_dround01    %f16, %f0, %f2, %f4
715         aes_dround23    %f18, %f0, %f2, %f2
716         ldd             [$key + 208], %f16
717         ldd             [$key + 216], %f18
718         aes_dround01    %f20, %f4, %f2, %f0
719         aes_dround23    %f22, %f4, %f2, %f2
720         ldd             [$key + 224], %f20
721         ldd             [$key + 232], %f22
722 ___
723 for ($i=1; $i<6; $i++) {
724     $code.=<<___;
725         aes_dround01    %f`16+8*$i+0`, %f0, %f2, %f4
726         aes_dround23    %f`16+8*$i+2`, %f0, %f2, %f2
727         aes_dround01    %f`16+8*$i+4`, %f4, %f2, %f0
728         aes_dround23    %f`16+8*$i+6`, %f4, %f2, %f2
729 ___
730 }
731 $code.=<<___;
732         aes_dround01    %f16, %f0, %f2, %f4
733         aes_dround23    %f18, %f0, %f2, %f2
734         ldd             [$key + 16], %f16
735         ldd             [$key + 24], %f18
736         aes_dround01_l  %f20, %f4, %f2, %f0
737         aes_dround23_l  %f22, %f4, %f2, %f2
738         ldd             [$key + 32], %f20
739         retl
740         ldd             [$key + 40], %f22
741 .type   _aes256_decrypt_1x,#function
742 .size   _aes256_decrypt_1x,.-_aes256_decrypt_1x
743
744 .align  32
745 _aes256_decrypt_2x:
746         aes_dround01    %f16, %f0, %f2, %f8
747         aes_dround23    %f18, %f0, %f2, %f2
748         aes_dround01    %f16, %f4, %f6, %f10
749         aes_dround23    %f18, %f4, %f6, %f6
750         ldd             [$key + 208], %f16
751         ldd             [$key + 216], %f18
752         aes_dround01    %f20, %f8, %f2, %f0
753         aes_dround23    %f22, %f8, %f2, %f2
754         aes_dround01    %f20, %f10, %f6, %f4
755         aes_dround23    %f22, %f10, %f6, %f6
756         ldd             [$key + 224], %f20
757         ldd             [$key + 232], %f22
758 ___
759 for ($i=1; $i<6; $i++) {
760     $code.=<<___;
761         aes_dround01    %f`16+8*$i+0`, %f0, %f2, %f8
762         aes_dround23    %f`16+8*$i+2`, %f0, %f2, %f2
763         aes_dround01    %f`16+8*$i+0`, %f4, %f6, %f10
764         aes_dround23    %f`16+8*$i+2`, %f4, %f6, %f6
765         aes_dround01    %f`16+8*$i+4`, %f8, %f2, %f0
766         aes_dround23    %f`16+8*$i+6`, %f8, %f2, %f2
767         aes_dround01    %f`16+8*$i+4`, %f10, %f6, %f4
768         aes_dround23    %f`16+8*$i+6`, %f10, %f6, %f6
769 ___
770 }
771 $code.=<<___;
772         aes_dround01    %f16, %f0, %f2, %f8
773         aes_dround23    %f18, %f0, %f2, %f2
774         aes_dround01    %f16, %f4, %f6, %f10
775         aes_dround23    %f18, %f4, %f6, %f6
776         ldd             [$key + 16], %f16
777         ldd             [$key + 24], %f18
778         aes_dround01_l  %f20, %f8, %f2, %f0
779         aes_dround23_l  %f22, %f8, %f2, %f2
780         aes_dround01_l  %f20, %f10, %f6, %f4
781         aes_dround23_l  %f22, %f10, %f6, %f6
782         ldd             [$key + 32], %f20
783         retl
784         ldd             [$key + 40], %f22
785 .type   _aes256_decrypt_2x,#function
786 .size   _aes256_decrypt_2x,.-_aes256_decrypt_2x
787 ___
788
789 sub aes_cbc_encrypt_implement {
790 my $bits = shift;
791
792 $code.=<<___;
793 .globl  aes${bits}_t4_cbc_encrypt
794 .align  32
795 aes${bits}_t4_cbc_encrypt:
796         save            %sp, -$frame, %sp
797 ___
798 $code.=<<___ if (!$evp);
799         andcc           $ivec, 7, $ivoff
800         alignaddr       $ivec, %g0, $ivec
801
802         ldd             [$ivec + 0], %f0        ! load ivec
803         bz,pt           %icc, 1f
804         ldd             [$ivec + 8], %f2
805         ldd             [$ivec + 16], %f4
806         faligndata      %f0, %f2, %f0
807         faligndata      %f2, %f4, %f2
808 1:
809 ___
810 $code.=<<___ if ($evp);
811         ld              [$ivec + 0], %f0
812         ld              [$ivec + 4], %f1
813         ld              [$ivec + 8], %f2
814         ld              [$ivec + 12], %f3
815 ___
816 $code.=<<___;
817         call            _aes${bits}_loadkey
818         srlx            $len, 4, $len
819         and             $inp, 7, $ileft
820         andn            $inp, 7, $inp
821         sll             $ileft, 3, $ileft
822         mov             64, $iright
823         mov             0xff, $omask
824         sub             $iright, $ileft, $iright
825         and             $out, 7, $ooff
826         alignaddrl      $out, %g0, $out
827         srl             $omask, $ooff, $omask
828
829 .L${bits}_cbc_enc_loop:
830         ldx             [$inp + 0], %o0
831         brz,pt          $ileft, 4f
832         ldx             [$inp + 8], %o1
833
834         ldx             [$inp + 16], %o2
835         sllx            %o0, $ileft, %o0
836         srlx            %o1, $iright, %g1
837         sllx            %o1, $ileft, %o1
838         or              %g1, %o0, %o0
839         srlx            %o2, $iright, %o2
840         or              %o2, %o1, %o1
841 4:
842         xor             %g4, %o0, %o0           ! ^= rk[0]
843         xor             %g5, %o1, %o1
844         movxtod         %o0, %f12
845         movxtod         %o1, %f14
846
847         fxor            %f12, %f0, %f0          ! ^= ivec
848         fxor            %f14, %f2, %f2
849         call            _aes${bits}_encrypt_1x
850         add             $inp, 16, $inp
851
852         brnz,pn         $ooff, 2f
853         sub             $len, 1, $len
854                 
855         std             %f0, [$out + 0]
856         std             %f2, [$out + 8]
857         brnz,pt         $len, .L${bits}_cbc_enc_loop
858         add             $out, 16, $out
859 ___
860 $code.=<<___ if ($evp);
861         st              %f0, [$ivec + 0]
862         st              %f1, [$ivec + 4]
863         st              %f2, [$ivec + 8]
864         st              %f3, [$ivec + 12]
865 ___
866 $code.=<<___ if (!$evp);
867         brnz,pn         $ivoff, 3f
868         nop
869
870         std             %f0, [$ivec + 0]        ! write out ivec
871         std             %f2, [$ivec + 8]
872 ___
873 $code.=<<___;
874         ret
875         restore
876
877 .align  16
878 2:      ldxa            [$inp]0x82, %o0         ! avoid read-after-write hazard
879                                                 ! and ~3x deterioration
880                                                 ! in inp==out case
881         faligndata      %f0, %f0, %f4           ! handle unaligned output
882         faligndata      %f0, %f2, %f6
883         faligndata      %f2, %f2, %f8
884
885         stda            %f4, [$out + $omask]0xc0        ! partial store
886         std             %f6, [$out + 8]
887         add             $out, 16, $out
888         orn             %g0, $omask, $omask
889         stda            %f8, [$out + $omask]0xc0        ! partial store
890
891         brnz,pt         $len, .L${bits}_cbc_enc_loop+4
892         orn             %g0, $omask, $omask
893 ___
894 $code.=<<___ if ($evp);
895         st              %f0, [$ivec + 0]
896         st              %f1, [$ivec + 4]
897         st              %f2, [$ivec + 8]
898         st              %f3, [$ivec + 12]
899 ___
900 $code.=<<___ if (!$evp);
901         brnz,pn         $ivoff, 3f
902         nop
903
904         std             %f0, [$ivec + 0]        ! write out ivec
905         std             %f2, [$ivec + 8]
906         ret
907         restore
908
909 .align  16
910 3:      alignaddrl      $ivec, $ivoff, %g0      ! handle unaligned ivec
911         mov             0xff, $omask
912         srl             $omask, $ivoff, $omask
913         faligndata      %f0, %f0, %f4
914         faligndata      %f0, %f2, %f6
915         faligndata      %f2, %f2, %f8
916         stda            %f4, [$ivec + $omask]0xc0
917         std             %f6, [$ivec + 8]
918         add             $ivec, 16, $ivec
919         orn             %g0, $omask, $omask
920         stda            %f8, [$ivec + $omask]0xc0
921 ___
922 $code.=<<___;
923         ret
924         restore
925 .type   aes${bits}_t4_cbc_encrypt,#function
926 .size   aes${bits}_t4_cbc_encrypt,.-aes${bits}_t4_cbc_encrypt
927 ___
928 }
929
930 &aes_cbc_encrypt_implement(128);
931 &aes_cbc_encrypt_implement(192);
932 &aes_cbc_encrypt_implement(256);
933
934 sub aes_cbc_decrypt_implement {
935 my $bits = shift;
936
937 $code.=<<___;
938 .globl  aes${bits}_t4_cbc_decrypt
939 .align  32
940 aes${bits}_t4_cbc_decrypt:
941         save            %sp, -$frame, %sp
942 ___
943 $code.=<<___ if (!$evp);
944         andcc           $ivec, 7, $ivoff
945         alignaddr       $ivec, %g0, $ivec
946
947         ldd             [$ivec + 0], %f12       ! load ivec
948         bz,pt           %icc, 1f
949         ldd             [$ivec + 8], %f14
950         ldd             [$ivec + 16], %f0
951         faligndata      %f12, %f14, %f12
952         faligndata      %f14, %f0, %f14
953 1:
954 ___
955 $code.=<<___ if ($evp);
956         ld              [$ivec + 0], %f12       ! load ivec
957         ld              [$ivec + 4], %f13
958         ld              [$ivec + 8], %f14
959         ld              [$ivec + 12], %f15
960 ___
961 $code.=<<___;
962         call            _aes${bits}_loadkey
963         srlx            $len, 4, $len
964         andcc           $len, 1, %g0            ! is number of blocks even?
965         and             $inp, 7, $ileft
966         andn            $inp, 7, $inp
967         sll             $ileft, 3, $ileft
968         mov             64, $iright
969         mov             0xff, $omask
970         sub             $iright, $ileft, $iright
971         and             $out, 7, $ooff
972         alignaddrl      $out, %g0, $out
973         bz              %icc, .L${bits}_cbc_dec_loop2x
974         srl             $omask, $ooff, $omask
975 .L${bits}_cbc_dec_loop:
976         ldx             [$inp + 0], %o0
977         brz,pt          $ileft, 4f
978         ldx             [$inp + 8], %o1
979
980         ldx             [$inp + 16], %o2
981         sllx            %o0, $ileft, %o0
982         srlx            %o1, $iright, %g1
983         sllx            %o1, $ileft, %o1
984         or              %g1, %o0, %o0
985         srlx            %o2, $iright, %o2
986         or              %o2, %o1, %o1
987 4:
988         xor             %g4, %o0, %o2           ! ^= rk[0]
989         xor             %g5, %o1, %o3
990         movxtod         %o2, %f0
991         movxtod         %o3, %f2
992
993         call            _aes${bits}_decrypt_1x
994         add             $inp, 16, $inp
995
996         fxor            %f12, %f0, %f0          ! ^= ivec
997         fxor            %f14, %f2, %f2
998         movxtod         %o0, %f12
999         movxtod         %o1, %f14
1000
1001         brnz,pn         $ooff, 2f
1002         sub             $len, 1, $len
1003                 
1004         std             %f0, [$out + 0]
1005         std             %f2, [$out + 8]
1006         brnz,pt         $len, .L${bits}_cbc_dec_loop2x
1007         add             $out, 16, $out
1008 ___
1009 $code.=<<___ if ($evp);
1010         st              %f12, [$ivec + 0]
1011         st              %f13, [$ivec + 4]
1012         st              %f14, [$ivec + 8]
1013         st              %f15, [$ivec + 12]
1014 ___
1015 $code.=<<___ if (!$evp);
1016         brnz,pn         $ivoff, .L${bits}_cbc_dec_unaligned_ivec
1017         nop
1018
1019         std             %f12, [$ivec + 0]       ! write out ivec
1020         std             %f14, [$ivec + 8]
1021 ___
1022 $code.=<<___;
1023         ret
1024         restore
1025
1026 .align  16
1027 2:      ldxa            [$inp]0x82, %o0         ! avoid read-after-write hazard
1028                                                 ! and ~3x deterioration
1029                                                 ! in inp==out case
1030         faligndata      %f0, %f0, %f4           ! handle unaligned output
1031         faligndata      %f0, %f2, %f6
1032         faligndata      %f2, %f2, %f8
1033
1034         stda            %f4, [$out + $omask]0xc0        ! partial store
1035         std             %f6, [$out + 8]
1036         add             $out, 16, $out
1037         orn             %g0, $omask, $omask
1038         stda            %f8, [$out + $omask]0xc0        ! partial store
1039
1040         brnz,pt         $len, .L${bits}_cbc_dec_loop2x+4
1041         orn             %g0, $omask, $omask
1042 ___
1043 $code.=<<___ if ($evp);
1044         st              %f12, [$ivec + 0]
1045         st              %f13, [$ivec + 4]
1046         st              %f14, [$ivec + 8]
1047         st              %f15, [$ivec + 12]
1048 ___
1049 $code.=<<___ if (!$evp);
1050         brnz,pn         $ivoff, .L${bits}_cbc_dec_unaligned_ivec
1051         nop
1052
1053         std             %f12, [$ivec + 0]       ! write out ivec
1054         std             %f14, [$ivec + 8]
1055 ___
1056 $code.=<<___;
1057         ret
1058         restore
1059
1060 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1061 .align  32
1062 .L${bits}_cbc_dec_loop2x:
1063         ldx             [$inp + 0], %o0
1064         ldx             [$inp + 8], %o1
1065         ldx             [$inp + 16], %o2
1066         brz,pt          $ileft, 4f
1067         ldx             [$inp + 24], %o3
1068
1069         ldx             [$inp + 32], %o4
1070         sllx            %o0, $ileft, %o0
1071         srlx            %o1, $iright, %g1
1072         or              %g1, %o0, %o0
1073         sllx            %o1, $ileft, %o1
1074         srlx            %o2, $iright, %g1
1075         or              %g1, %o1, %o1
1076         sllx            %o2, $ileft, %o2
1077         srlx            %o3, $iright, %g1
1078         or              %g1, %o2, %o2
1079         sllx            %o3, $ileft, %o3
1080         srlx            %o4, $iright, %o4
1081         or              %o4, %o3, %o3
1082 4:
1083         xor             %g4, %o0, %o4           ! ^= rk[0]
1084         xor             %g5, %o1, %o5
1085         movxtod         %o4, %f0
1086         movxtod         %o5, %f2
1087         xor             %g4, %o2, %o4
1088         xor             %g5, %o3, %o5
1089         movxtod         %o4, %f4
1090         movxtod         %o5, %f6
1091
1092         call            _aes${bits}_decrypt_2x
1093         add             $inp, 32, $inp
1094
1095         movxtod         %o0, %f8
1096         movxtod         %o1, %f10
1097         fxor            %f12, %f0, %f0          ! ^= ivec
1098         fxor            %f14, %f2, %f2
1099         movxtod         %o2, %f12
1100         movxtod         %o3, %f14
1101         fxor            %f8, %f4, %f4
1102         fxor            %f10, %f6, %f6
1103
1104         brnz,pn         $ooff, 2f
1105         sub             $len, 2, $len
1106                 
1107         std             %f0, [$out + 0]
1108         std             %f2, [$out + 8]
1109         std             %f4, [$out + 16]
1110         std             %f6, [$out + 24]
1111         brnz,pt         $len, .L${bits}_cbc_dec_loop2x
1112         add             $out, 32, $out
1113 ___
1114 $code.=<<___ if ($evp);
1115         st              %f12, [$ivec + 0]
1116         st              %f13, [$ivec + 4]
1117         st              %f14, [$ivec + 8]
1118         st              %f15, [$ivec + 12]
1119 ___
1120 $code.=<<___ if (!$evp);
1121         brnz,pn         $ivoff, .L${bits}_cbc_dec_unaligned_ivec
1122         nop
1123
1124         std             %f12, [$ivec + 0]       ! write out ivec
1125         std             %f14, [$ivec + 8]
1126 ___
1127 $code.=<<___;
1128         ret
1129         restore
1130
1131 .align  16
1132 2:      ldxa            [$inp]0x82, %o0         ! avoid read-after-write hazard
1133                                                 ! and ~3x deterioration
1134                                                 ! in inp==out case
1135         faligndata      %f0, %f0, %f8           ! handle unaligned output
1136         faligndata      %f0, %f2, %f0
1137         faligndata      %f2, %f4, %f2
1138         faligndata      %f4, %f6, %f4
1139         faligndata      %f6, %f6, %f6
1140         stda            %f8, [$out + $omask]0xc0        ! partial store
1141         std             %f0, [$out + 8]
1142         std             %f2, [$out + 16]
1143         std             %f4, [$out + 24]
1144         add             $out, 32, $out
1145         orn             %g0, $omask, $omask
1146         stda            %f6, [$out + $omask]0xc0        ! partial store
1147
1148         brnz,pt         $len, .L${bits}_cbc_dec_loop2x+4
1149         orn             %g0, $omask, $omask
1150 ___
1151 $code.=<<___ if ($evp);
1152         st              %f12, [$ivec + 0]
1153         st              %f13, [$ivec + 4]
1154         st              %f14, [$ivec + 8]
1155         st              %f15, [$ivec + 12]
1156 ___
1157 $code.=<<___ if (!$evp);
1158         brnz,pn         $ivoff, .L${bits}_cbc_dec_unaligned_ivec
1159         nop
1160
1161         std             %f12, [$ivec + 0]       ! write out ivec
1162         std             %f14, [$ivec + 8]
1163         ret
1164         restore
1165
1166 .align  16
1167 .L${bits}_cbc_dec_unaligned_ivec:
1168         alignaddrl      $ivec, $ivoff, %g0      ! handle unaligned ivec
1169         mov             0xff, $omask
1170         srl             $omask, $ivoff, $omask
1171         faligndata      %f12, %f12, %f0
1172         faligndata      %f12, %f14, %f2
1173         faligndata      %f14, %f14, %f4
1174         stda            %f0, [$ivec + $omask]0xc0
1175         std             %f2, [$ivec + 8]
1176         add             $ivec, 16, $ivec
1177         orn             %g0, $omask, $omask
1178         stda            %f4, [$ivec + $omask]0xc0
1179 ___
1180 $code.=<<___;
1181         ret
1182         restore
1183 .type   aes${bits}_t4_cbc_decrypt,#function
1184 .size   aes${bits}_t4_cbc_decrypt,.-aes${bits}_t4_cbc_decrypt
1185 ___
1186 }
1187
1188 &aes_cbc_decrypt_implement(128);
1189 &aes_cbc_decrypt_implement(192);
1190 &aes_cbc_decrypt_implement(256);
1191
1192 sub aes_ctr32_implement {
1193 my $bits = shift;
1194
1195 $code.=<<___;
1196 .globl  aes${bits}_t4_ctr32_encrypt
1197 .align  32
1198 aes${bits}_t4_ctr32_encrypt:
1199         save            %sp, -$frame, %sp
1200
1201         call            _aes${bits}_loadkey
1202         nop
1203
1204         ld              [$ivec + 0], %l4        ! counter
1205         ld              [$ivec + 4], %l5
1206         ld              [$ivec + 8], %l6
1207         ld              [$ivec + 12], %l7
1208
1209         sllx            %l4, 32, %o5
1210         or              %l5, %o5, %o5
1211         sllx            %l6, 32, %g1
1212         xor             %o5, %g4, %g4           ! ^= rk[0]
1213         xor             %g1, %g5, %g5
1214         movxtod         %g4, %f14               ! most significant 64 bits
1215
1216         andcc           $len, 1, %g0            ! is number of blocks even?
1217         and             $inp, 7, $ileft
1218         andn            $inp, 7, $inp
1219         sll             $ileft, 3, $ileft
1220         mov             64, $iright
1221         mov             0xff, $omask
1222         sub             $iright, $ileft, $iright
1223         and             $out, 7, $ooff
1224         alignaddrl      $out, %g0, $out
1225         bz              %icc, .L${bits}_ctr32_loop2x
1226         srl             $omask, $ooff, $omask
1227 .L${bits}_ctr32_loop:
1228         ldx             [$inp + 0], %o0
1229         brz,pt          $ileft, 4f
1230         ldx             [$inp + 8], %o1
1231
1232         ldx             [$inp + 16], %o2
1233         sllx            %o0, $ileft, %o0
1234         srlx            %o1, $iright, %g1
1235         sllx            %o1, $ileft, %o1
1236         or              %g1, %o0, %o0
1237         srlx            %o2, $iright, %o2
1238         or              %o2, %o1, %o1
1239 4:
1240         xor             %g5, %l7, %g1           ! ^= rk[0]
1241         add             %l7, 1, %l7
1242         movxtod         %g1, %f2
1243         srl             %l7, 0, %l7             ! clruw
1244
1245         aes_eround01    %f16, %f14, %f2, %f4
1246         aes_eround23    %f18, %f14, %f2, %f2
1247         call            _aes${bits}_encrypt_1x+8
1248         add             $inp, 16, $inp
1249
1250         movxtod         %o0, %f10
1251         movxtod         %o1, %f12
1252         fxor            %f10, %f0, %f0          ! ^= inp
1253         fxor            %f12, %f2, %f2
1254
1255         brnz,pn         $ooff, 2f
1256         sub             $len, 1, $len
1257                 
1258         std             %f0, [$out + 0]
1259         std             %f2, [$out + 8]
1260         brnz,pt         $len, .L${bits}_ctr32_loop2x
1261         add             $out, 16, $out
1262
1263         ret
1264         restore
1265
1266 .align  16
1267 2:      ldxa            [$inp]0x82, %o0         ! avoid read-after-write hazard
1268                                                 ! and ~3x deterioration
1269                                                 ! in inp==out case
1270         faligndata      %f0, %f0, %f4           ! handle unaligned output
1271         faligndata      %f0, %f2, %f6
1272         faligndata      %f2, %f2, %f8
1273         stda            %f4, [$out + $omask]0xc0        ! partial store
1274         std             %f6, [$out + 8]
1275         add             $out, 16, $out
1276         orn             %g0, $omask, $omask
1277         stda            %f8, [$out + $omask]0xc0        ! partial store
1278
1279         brnz,pt         $len, .L${bits}_ctr32_loop2x+4
1280         orn             %g0, $omask, $omask
1281
1282         ret
1283         restore
1284
1285 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1286 .align  32
1287 .L${bits}_ctr32_loop2x:
1288         ldx             [$inp + 0], %o0
1289         ldx             [$inp + 8], %o1
1290         ldx             [$inp + 16], %o2
1291         brz,pt          $ileft, 4f
1292         ldx             [$inp + 24], %o3
1293
1294         ldx             [$inp + 32], %o4
1295         sllx            %o0, $ileft, %o0
1296         srlx            %o1, $iright, %g1
1297         or              %g1, %o0, %o0
1298         sllx            %o1, $ileft, %o1
1299         srlx            %o2, $iright, %g1
1300         or              %g1, %o1, %o1
1301         sllx            %o2, $ileft, %o2
1302         srlx            %o3, $iright, %g1
1303         or              %g1, %o2, %o2
1304         sllx            %o3, $ileft, %o3
1305         srlx            %o4, $iright, %o4
1306         or              %o4, %o3, %o3
1307 4:
1308         xor             %g5, %l7, %g1           ! ^= rk[0]
1309         add             %l7, 1, %l7
1310         movxtod         %g1, %f2
1311         srl             %l7, 0, %l7             ! clruw
1312         xor             %g5, %l7, %g1
1313         add             %l7, 1, %l7
1314         movxtod         %g1, %f6
1315         srl             %l7, 0, %l7             ! clruw
1316
1317         aes_eround01    %f16, %f14, %f2, %f8
1318         aes_eround23    %f18, %f14, %f2, %f2
1319         aes_eround01    %f16, %f14, %f6, %f10
1320         aes_eround23    %f18, %f14, %f6, %f6
1321         call            _aes${bits}_encrypt_2x+16
1322         add             $inp, 32, $inp
1323
1324         movxtod         %o0, %f8
1325         movxtod         %o1, %f10
1326         movxtod         %o2, %f12
1327         fxor            %f8, %f0, %f0           ! ^= inp
1328         movxtod         %o3, %f8
1329         fxor            %f10, %f2, %f2
1330         fxor            %f12, %f4, %f4
1331         fxor            %f8, %f6, %f6
1332
1333         brnz,pn         $ooff, 2f
1334         sub             $len, 2, $len
1335                 
1336         std             %f0, [$out + 0]
1337         std             %f2, [$out + 8]
1338         std             %f4, [$out + 16]
1339         std             %f6, [$out + 24]
1340         brnz,pt         $len, .L${bits}_ctr32_loop2x
1341         add             $out, 32, $out
1342
1343         ret
1344         restore
1345
1346 .align  16
1347 2:      ldxa            [$inp]0x82, %o0         ! avoid read-after-write hazard
1348                                                 ! and ~3x deterioration
1349                                                 ! in inp==out case
1350         faligndata      %f0, %f0, %f8           ! handle unaligned output
1351         faligndata      %f0, %f2, %f0
1352         faligndata      %f2, %f4, %f2
1353         faligndata      %f4, %f6, %f4
1354         faligndata      %f6, %f6, %f6
1355
1356         stda            %f8, [$out + $omask]0xc0        ! partial store
1357         std             %f0, [$out + 8]
1358         std             %f2, [$out + 16]
1359         std             %f4, [$out + 24]
1360         add             $out, 32, $out
1361         orn             %g0, $omask, $omask
1362         stda            %f6, [$out + $omask]0xc0        ! partial store
1363
1364         brnz,pt         $len, .L${bits}_ctr32_loop2x+4
1365         orn             %g0, $omask, $omask
1366
1367         ret
1368         restore
1369 .type   aes${bits}_t4_ctr32_encrypt,#function
1370 .size   aes${bits}_t4_ctr32_encrypt,.-aes${bits}_t4_ctr32_encrypt
1371 ___
1372 }
1373
1374 if ($evp) {
1375     &aes_ctr32_implement(128);
1376     &aes_ctr32_implement(192);
1377     &aes_ctr32_implement(256);
1378 }
1379 }}}
1380
1381 if (!$evp) {
1382 $code.=<<___;
1383 .global AES_encrypt
1384 AES_encrypt=aes_t4_encrypt
1385 .global AES_decrypt
1386 AES_decrypt=aes_t4_decrypt
1387 .global AES_set_encrypt_key
1388 AES_set_encrypt_key=aes_t4_set_encrypt_key
1389 .global AES_set_decrypt_key
1390 AES_set_decrypt_key=aes_t4_set_decrypt_key
1391 ___
1392
1393 my ($inp,$out,$len,$key,$ivec,$enc)=map("%o$_",(0..5));
1394
1395 $code.=<<___;
1396 .globl  AES_cbc_encrypt
1397 .align  32
1398 AES_cbc_encrypt:
1399         ld              [$key + 240], %g1
1400         nop
1401         brz             $enc, .Lcbc_decrypt
1402         cmp             %g1, 12
1403
1404         bl,pt           %icc, aes128_t4_cbc_encrypt
1405         nop
1406         be,pn           %icc, aes192_t4_cbc_encrypt
1407         nop
1408         ba              aes256_t4_cbc_encrypt
1409         nop
1410
1411 .Lcbc_decrypt:
1412         bl,pt           %icc, aes128_t4_cbc_decrypt
1413         nop
1414         be,pn           %icc, aes192_t4_cbc_decrypt
1415         nop
1416         ba              aes256_t4_cbc_decrypt
1417         nop
1418 .type   AES_cbc_encrypt,#function
1419 .size   AES_cbc_encrypt,.-AES_cbc_encrypt
1420 ___
1421 }
1422 $code.=<<___;
1423 .asciz  "AES for SPARC T4, David S. Miller, Andy Polyakov"
1424 .align  4
1425 ___
1426 # Purpose of these subroutines is to explicitly encode VIS instructions,
1427 # so that one can compile the module without having to specify VIS
1428 # extentions on compiler command line, e.g. -xarch=v9 vs. -xarch=v9a.
1429 # Idea is to reserve for option to produce "universal" binary and let
1430 # programmer detect if current CPU is VIS capable at run-time.
1431 sub unvis {
1432 my ($mnemonic,$rs1,$rs2,$rd)=@_;
1433 my ($ref,$opf);
1434 my %visopf = (  "faligndata"    => 0x048,
1435                 "fxor"          => 0x06c        );
1436
1437     $ref = "$mnemonic\t$rs1,$rs2,$rd";
1438
1439     if ($opf=$visopf{$mnemonic}) {
1440         foreach ($rs1,$rs2,$rd) {
1441             return $ref if (!/%f([0-9]{1,2})/);
1442             $_=$1;
1443             if ($1>=32) {
1444                 return $ref if ($1&1);
1445                 # re-encode for upper double register addressing
1446                 $_=($1|$1>>5)&31;
1447             }
1448         }
1449
1450         return  sprintf ".word\t0x%08x !%s",
1451                         0x81b00000|$rd<<25|$rs1<<14|$opf<<5|$rs2,
1452                         $ref;
1453     } else {
1454         return $ref;
1455     }
1456 }
1457 sub unalignaddr {
1458 my ($mnemonic,$rs1,$rs2,$rd)=@_;
1459 my %bias = ( "g" => 0, "o" => 8, "l" => 16, "i" => 24 );
1460 my $ref = "$mnemonic\t$rs1,$rs2,$rd";
1461 my $opf = $mnemonic =~ /l$/ ? 0x01a :0x18;
1462
1463     foreach ($rs1,$rs2,$rd) {
1464         if (/%([goli])([0-7])/) { $_=$bias{$1}+$2; }
1465         else                    { return $ref; }
1466     }
1467     return  sprintf ".word\t0x%08x !%s",
1468                     0x81b00000|$rd<<25|$rs1<<14|$opf<<5|$rs2,
1469                     $ref;
1470 }
1471
1472 sub unaes_round {       # 4-argument instructions
1473 my ($mnemonic,$rs1,$rs2,$rs3,$rd)=@_;
1474 my ($ref,$opf);
1475 my %aesopf = (  "aes_eround01"  => 0,
1476                 "aes_eround23"  => 1,
1477                 "aes_dround01"  => 2,
1478                 "aes_dround23"  => 3,
1479                 "aes_eround01_l"=> 4,
1480                 "aes_eround23_l"=> 5,
1481                 "aes_dround01_l"=> 6,
1482                 "aes_dround23_l"=> 7,
1483                 "aes_kexpand1"  => 8    );
1484
1485     $ref = "$mnemonic\t$rs1,$rs2,$rs3,$rd";
1486
1487     if (defined($opf=$aesopf{$mnemonic})) {
1488         $rs3 = ($rs3 =~ /%f([0-6]*[02468])/) ? (($1|$1>>5)&31) : $rs3;
1489         foreach ($rs1,$rs2,$rd) {
1490             return $ref if (!/%f([0-9]{1,2})/);
1491             $_=$1;
1492             if ($1>=32) {
1493                 return $ref if ($1&1);
1494                 # re-encode for upper double register addressing
1495                 $_=($1|$1>>5)&31;
1496             }
1497         }
1498
1499         return  sprintf ".word\t0x%08x !%s",
1500                         2<<30|$rd<<25|0x19<<19|$rs1<<14|$rs3<<9|$opf<<5|$rs2,
1501                         $ref;
1502     } else {
1503         return $ref;
1504     }
1505 }
1506
1507 sub unaes_kexpand {     # 3-argument instructions
1508 my ($mnemonic,$rs1,$rs2,$rd)=@_;
1509 my ($ref,$opf);
1510 my %aesopf = (  "aes_kexpand0"  => 0x130,
1511                 "aes_kexpand2"  => 0x131        );
1512
1513     $ref = "$mnemonic\t$rs1,$rs2,$rd";
1514
1515     if (defined($opf=$aesopf{$mnemonic})) {
1516         foreach ($rs1,$rs2,$rd) {
1517             return $ref if (!/%f([0-9]{1,2})/);
1518             $_=$1;
1519             if ($1>=32) {
1520                 return $ref if ($1&1);
1521                 # re-encode for upper double register addressing
1522                 $_=($1|$1>>5)&31;
1523             }
1524         }
1525
1526         return  sprintf ".word\t0x%08x !%s",
1527                         2<<30|$rd<<25|0x36<<19|$rs1<<14|$opf<<5|$rs2,
1528                         $ref;
1529     } else {
1530         return $ref;
1531     }
1532 }
1533
1534 sub unmovxtox {         # 2-argument instructions
1535 my ($mnemonic,$rs,$rd)=@_;
1536 my %bias = ( "g" => 0, "o" => 8, "l" => 16, "i" => 24, "f" => 0 );
1537 my ($ref,$opf);
1538 my %movxopf = ( "movdtox"       => 0x110,
1539                 "movstouw"      => 0x111,
1540                 "movstosw"      => 0x113,
1541                 "movxtod"       => 0x118,
1542                 "movwtos"       => 0x119        );
1543
1544     $ref = "$mnemonic\t$rs,$rd";
1545
1546     if (defined($opf=$movxopf{$mnemonic})) {
1547         foreach ($rs,$rd) {
1548             return $ref if (!/%([fgoli])([0-9]{1,2})/);
1549             $_=$bias{$1}+$2;
1550             if ($2>=32) {
1551                 return $ref if ($2&1);
1552                 # re-encode for upper double register addressing
1553                 $_=($2|$2>>5)&31;
1554             }
1555         }
1556
1557         return  sprintf ".word\t0x%08x !%s",
1558                         2<<30|$rd<<25|0x36<<19|$opf<<5|$rs,
1559                         $ref;
1560     } else {
1561         return $ref;
1562     }
1563 }
1564
1565 foreach (split("\n",$code)) {
1566         s/\`([^\`]*)\`/eval $1/ge;
1567
1568         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})/
1569                 &unaes_round($1,$2,$3,$4,$5)
1570          /ge or
1571         s/\b(aes_kexpand[02])\s+(%f[0-9]{1,2}),\s*(%f[0-9]{1,2}),\s*(%f[0-9]{1,2})/
1572                 &unaes_kexpand($1,$2,$3,$4)
1573          /ge or
1574         s/\b(mov[ds]to\w+)\s+(%f[0-9]{1,2}),\s*(%[goli][0-7])/
1575                 &unmovxtox($1,$2,$3)
1576          /ge or
1577         s/\b(mov[xw]to[ds])\s+(%[goli][0-7]),\s*(%f[0-9]{1,2})/
1578                 &unmovxtox($1,$2,$3)
1579          /ge or
1580         s/\b(f[^\s]*)\s+(%f[0-9]{1,2}),\s*(%f[0-9]{1,2}),\s*(%f[0-9]{1,2})/
1581                 &unvis($1,$2,$3,$4)
1582          /ge or
1583         s/\b(alignaddr[l]*)\s+(%[goli][0-7]),\s*(%[goli][0-7]),\s*(%[goli][0-7])/
1584                 &unalignaddr($1,$2,$3,$4)
1585          /ge;
1586
1587         print $_,"\n";
1588 }
1589
1590 close STDOUT;