Intel AES-NI engine.
[openssl.git] / crypto / aes / asm / aesni-x86_64.pl
1 #!/usr/bin/env perl
2 #
3 # ====================================================================
4 # Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
5 # project. The module is, however, dual licensed under OpenSSL and
6 # CRYPTOGAMS licenses depending on where you obtain it. For further
7 # details see http://www.openssl.org/~appro/cryptogams/.
8 # ====================================================================
9 #
10 # This module implements support for Intel AES-NI extension. In
11 # OpenSSL context it's used with Intel engine, but can also be used as
12 # drop-in replacement for crypto/aes/asm/aes-x86_64.pl [see below for
13 # details].
14 #
15 # TODO:
16 # - Win64 SEH handlers;
17
18 $PREFIX="aesni";        # if $PREFIX is set to "AES", the script
19                         # generates drop-in replacement for
20                         # crypto/aes/asm/aes-x86_64.pl:-)
21
22 $flavour = shift;
23 $output  = shift;
24 if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
25
26 $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
27
28 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
29 ( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
30 ( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
31 die "can't locate x86_64-xlate.pl";
32
33 open STDOUT,"| $^X $xlate $flavour $output";
34
35 $movkey = $PREFIX eq "aesni" ? "movaps" : "movups";
36
37 $code=".text\n";
38
39 $rounds="%eax"; # input to and changed by aesni_[en|de]cryptN !!!
40
41 # this is natural argument order for public $PREFIX_*crypt...
42 $inp="%rdi";
43 $out="%rsi";
44 # ... and for $PREFIX_[ebc|cbc]_encrypt in particular.
45 $len="%rdx";
46 $key="%rcx";    # input to and changed by aesni_[en|de]cryptN !!!
47 $ivp="%r8";     # cbc
48
49 $rnds_="%r10d"; # backup copy for $rounds
50 $key_="%r11";   # backup copy for $key
51
52 # %xmm register layout
53 $inout0="%xmm0";        $inout1="%xmm1";
54 $inout2="%xmm2";        $inout3="%xmm3";
55 $inout4="%xmm4";        $inout5="%xmm5";
56 $rndkey0="%xmm6";       $rndkey1="%xmm7";
57
58 $iv="%xmm8";
59 $in0="%xmm9";   $in1="%xmm10";
60 $in2="%xmm11";  $in3="%xmm12";
61 $in4="%xmm13";  $in5="%xmm14";
62 \f
63 # Inline version of internal aesni_[en|de]crypt1.
64 #
65 # Why folded loop? Because aes[enc|dec] is slow enough to accommodate
66 # cycles which take care of loop variables...
67 { my $sn;
68 sub aesni_encrypt1 {
69 my ($data,$rndkey0,$rndkey1,$key,$rounds)=@_;
70 ++$sn;
71 $code.=<<___;
72         $movkey ($key),$rndkey0
73         $movkey 16($key),$rndkey1
74         lea     16($key),$key
75         pxor    $rndkey0,$data
76         dec     $rounds
77         jmp     .Loop_enc1_$sn
78 .align  16
79 .Loop_enc1_$sn:
80         aesenc  $rndkey1,$data
81         dec     $rounds
82         lea     16($key),$key
83         $movkey ($key),$rndkey1
84         jnz     .Loop_enc1_$sn  # loop body is 16 bytes
85
86         aesenclast      $rndkey1,$data
87 ___
88 }}
89 { my $sn;
90 sub aesni_decrypt1 {
91 my ($data,$rndkey0,$rndkey1,$key,$rounds)=@_;
92 ++$sn;
93 $code.=<<___;
94         $movkey ($key),$rndkey0
95         $movkey 16($key),$rndkey1
96         lea     16($key),$key
97         pxor    $rndkey0,$data
98         dec     $rounds
99         jmp     .Loop_dec1_$sn
100 .align  16
101 .Loop_dec1_$sn:
102         aesdec  $rndkey1,$data
103         dec     $rounds
104         lea     16($key),$key
105         $movkey ($key),$rndkey1
106         jnz     .Loop_dec1_$sn  # loop body is 16 bytes
107
108         aesdeclast      $rndkey1,$data
109 ___
110 }}
111 \f
112 # void $PREFIX_encrypt (const void *inp,void *out,const AES_KEY *key);
113 #
114 $code.=<<___;
115 .globl  ${PREFIX}_encrypt
116 .type   ${PREFIX}_encrypt,\@function,3
117 .align  16
118 ${PREFIX}_encrypt:
119         movups  ($inp),%xmm0            # load input
120         mov     240(%rdx),$rounds       # pull $rounds
121 ___
122         &aesni_encrypt1("%xmm0","%xmm1","%xmm2","%rdx",$rounds);
123 $code.=<<___;
124         movups  %xmm0,(%rsi)            # output
125         ret
126 .size   ${PREFIX}_encrypt,.-${PREFIX}_encrypt
127 ___
128
129 # void $PREFIX_decrypt (const void *inp,void *out,const AES_KEY *key);
130 #
131 $code.=<<___;
132 .globl  ${PREFIX}_decrypt
133 .type   ${PREFIX}_decrypt,\@function,3
134 .align  16
135 ${PREFIX}_decrypt:
136         movups  ($inp),%xmm0            # load input
137         mov     240(%rdx),$rounds       # pull $rounds
138 ___
139         &aesni_decrypt1("%xmm0","%xmm1","%xmm2","%rdx",$rounds);
140 $code.=<<___;
141         movups  %xmm0,($out)            # output
142         ret
143 .size   ${PREFIX}_decrypt, .-${PREFIX}_decrypt
144 ___
145 \f
146 # _aesni_[en|de]crypt6 are private interfaces, 6 denotes interleave
147 # factor. Why 6x? Because aes[enc|dec] latency is 6 and 6x interleave
148 # provides optimal utilization, so that subroutine's throughput is
149 # virtually same for *any* number [naturally up to 6] of input blocks
150 # as for non-interleaved subroutine. This is why it handles even
151 # double-, tripple-, quad- and penta-block inputs. Larger interleave
152 # factor, e.g. 8x, would perform suboptimally on these shorter inputs...
153 sub aesni_generate6 {
154 my $dir=shift;
155 # As already mentioned it takes in $key and $rounds, which are *not*
156 # preserved. $inout[0-5] is cipher/clear text...
157 $code.=<<___;
158 .type   _aesni_${dir}rypt6,\@abi-omnipotent
159 .align  16
160 _aesni_${dir}rypt6:
161         $movkey ($key),$rndkey0
162         $movkey 16($key),$rndkey1
163         shr     \$1,$rounds
164         lea     32($key),$key
165         dec     $rounds
166         pxor    $rndkey0,$inout0
167         pxor    $rndkey0,$inout1
168         pxor    $rndkey0,$inout2
169         pxor    $rndkey0,$inout3
170         pxor    $rndkey0,$inout4
171         pxor    $rndkey0,$inout5
172         jmp     .L${dir}_loop6
173 .align  16
174 .L${dir}_loop6:
175         aes${dir}       $rndkey1,$inout0
176         $movkey         ($key),$rndkey0
177         aes${dir}       $rndkey1,$inout1
178         dec             $rounds
179         aes${dir}       $rndkey1,$inout2
180         aes${dir}       $rndkey1,$inout3
181         aes${dir}       $rndkey1,$inout4
182         aes${dir}       $rndkey1,$inout5
183         aes${dir}       $rndkey0,$inout0
184         $movkey         16($key),$rndkey1
185         aes${dir}       $rndkey0,$inout1
186         lea             32($key),$key
187         aes${dir}       $rndkey0,$inout2
188         aes${dir}       $rndkey0,$inout3
189         aes${dir}       $rndkey0,$inout4
190         aes${dir}       $rndkey0,$inout5
191         jnz             .L${dir}_loop6
192         aes${dir}       $rndkey1,$inout0
193         $movkey         ($key),$rndkey0
194         aes${dir}       $rndkey1,$inout1
195         aes${dir}       $rndkey1,$inout2
196         aes${dir}       $rndkey1,$inout3
197         aes${dir}       $rndkey1,$inout4
198         aes${dir}       $rndkey1,$inout5
199         aes${dir}last   $rndkey0,$inout0
200         aes${dir}last   $rndkey0,$inout1
201         aes${dir}last   $rndkey0,$inout2
202         aes${dir}last   $rndkey0,$inout3
203         aes${dir}last   $rndkey0,$inout4
204         aes${dir}last   $rndkey0,$inout5
205         ret
206 .size   _aesni_${dir}rypt6,.-_aesni_${dir}rypt6
207 ___
208 }
209 &aesni_generate6("enc");
210 &aesni_generate6("dec");
211 \f
212 if ($PREFIX eq "aesni") {
213 # void aesni_ecb_encrypt (const void *in, void *out,
214 #                         size_t length, const AES_KEY *key,
215 #                         int enc);
216 $code.=<<___;
217 .globl  aesni_ecb_encrypt
218 .type   aesni_ecb_encrypt,\@function,5
219 .align  16
220 aesni_ecb_encrypt:
221         cmp     \$16,$len               # check length
222         jb      .Lecb_abort
223 ___
224 $code.=<<___ if ($win64);
225         lea     -0x28(%rsp),%rsp
226         movaps  %xmm6,(%rsp)
227         movaps  %xmm7,16(%rsp)
228 ___
229 $code.=<<___;
230         mov     240($key),$rounds       # pull $rounds
231         and     \$-16,$len
232         mov     $key,$key_              # backup $key
233         test    %r8d,%r8d
234         mov     $rounds,$rnds_          # backup $rounds
235         jz      .Lecb_decrypt
236 #--------------------------- ECB ENCRYPT ------------------------------#
237         sub     \$0x60,$len
238         jc      .Lecb_enc_tail
239         jmp     .Lecb_enc_loop6
240 .align 16
241 .Lecb_enc_loop6:
242         movups  ($inp),$inout0
243         movups  0x10($inp),$inout1
244         movups  0x20($inp),$inout2
245         movups  0x30($inp),$inout3
246         movups  0x40($inp),$inout4
247         movups  0x50($inp),$inout5
248         call    _aesni_encrypt6
249         movups  $inout0,($out)
250         sub     \$0x60,$len
251         movups  $inout1,0x10($out)
252         lea     0x60($inp),$inp
253         movups  $inout2,0x20($out)
254         mov     $rnds_,$rounds          # restore $rounds
255         movups  $inout3,0x30($out)
256         mov     $key_,$key              # restore $key
257         movups  $inout4,0x40($out)
258         movups  $inout5,0x50($out)
259         lea     0x60($out),$out
260         jnc     .Lecb_enc_loop6
261
262 .Lecb_enc_tail:
263         add     \$0x60,$len
264         jz      .Lecb_ret
265
266         cmp     \$0x10,$len
267         movups  ($inp),$inout0
268         je      .Lecb_enc_one
269         cmp     \$0x20,$len
270         movups  0x10($inp),$inout1
271         je      .Lecb_enc_two
272         cmp     \$0x30,$len
273         movups  0x20($inp),$inout2
274         je      .Lecb_enc_three
275         cmp     \$0x40,$len
276         movups  0x30($inp),$inout3
277         je      .Lecb_enc_four
278         movups  0x40($inp),$inout4
279         call    _aesni_encrypt6
280         movups  $inout0,($out)
281         movups  $inout1,0x10($out)
282         movups  $inout2,0x20($out)
283         movups  $inout3,0x30($out)
284         movups  $inout4,0x40($out)
285         jmp     .Lecb_ret
286 .align  16
287 .Lecb_enc_one:
288 ___
289         &aesni_encrypt1($inout0,$rndkey0,$rndkey1,$key,$rounds);
290 $code.=<<___;
291         movups  $inout0,($out)
292         jmp     .Lecb_ret
293 .align  16
294 .Lecb_enc_two:
295         call    _aesni_encrypt6
296         movups  $inout0,($out)
297         movups  $inout1,0x10($out)
298         jmp     .Lecb_ret
299 .align  16
300 .Lecb_enc_three:
301         call    _aesni_encrypt6
302         movups  $inout0,($out)
303         movups  $inout1,0x10($out)
304         movups  $inout2,0x20($out)
305         jmp     .Lecb_ret
306 .align  16
307 .Lecb_enc_four:
308         call    _aesni_encrypt6
309         movups  $inout0,($out)
310         movups  $inout1,0x10($out)
311         movups  $inout2,0x20($out)
312         movups  $inout3,0x30($out)
313         jmp     .Lecb_ret
314 \f#--------------------------- ECB DECRYPT ------------------------------#
315 .align  16
316 .Lecb_decrypt:
317         sub     \$0x60,$len
318         jc      .Lecb_dec_tail
319         jmp     .Lecb_dec_loop6
320 .align 16
321 .Lecb_dec_loop6:
322         movups  ($inp),$inout0
323         movups  0x10($inp),$inout1
324         movups  0x20($inp),$inout2
325         movups  0x30($inp),$inout3
326         movups  0x40($inp),$inout4
327         movups  0x50($inp),$inout5
328         call    _aesni_decrypt6
329         movups  $inout0,($out)
330         sub     \$0x60,$len
331         movups  $inout1,0x10($out)
332         lea     0x60($inp),$inp
333         movups  $inout2,0x20($out)
334         mov     $rnds_,$rounds          # restore $rounds
335         movups  $inout3,0x30($out)
336         mov     $key_,$key              # restore $key
337         movups  $inout4,0x40($out)
338         movups  $inout5,0x50($out)
339         lea     0x60($out),$out
340         jnc     .Lecb_dec_loop6
341
342 .Lecb_dec_tail:
343         add     \$0x60,$len
344         jz      .Lecb_ret
345
346         cmp     \$0x10,$len
347         movups  ($inp),$inout0
348         je      .Lecb_dec_one
349         cmp     \$0x20,$len
350         movups  0x10($inp),$inout1
351         je      .Lecb_dec_two
352         cmp     \$0x30,$len
353         movups  0x20($inp),$inout2
354         je      .Lecb_dec_three
355         cmp     \$0x40,$len
356         movups  0x30($inp),$inout3
357         je      .Lecb_dec_four
358         movups  0x40($inp),$inout4
359         call    _aesni_decrypt6
360         movups  $inout0,($out)
361         movups  $inout1,0x10($out)
362         movups  $inout2,0x20($out)
363         movups  $inout3,0x30($out)
364         movups  $inout4,0x40($out)
365         jmp     .Lecb_ret
366 .align  16
367 .Lecb_dec_one:
368 ___
369         &aesni_decrypt1($inout0,$rndkey0,$rndkey1,$key,$rounds);
370 $code.=<<___;
371         movups  $inout0,($out)
372         jmp     .Lecb_ret
373 .align  16
374 .Lecb_dec_two:
375         call    _aesni_decrypt6
376         movups  $inout0,($out)
377         movups  $inout1,0x10($out)
378         jmp     .Lecb_ret
379 .align  16
380 .Lecb_dec_three:
381         call    _aesni_decrypt6
382         movups  $inout0,($out)
383         movups  $inout1,0x10($out)
384         movups  $inout2,0x20($out)
385         jmp     .Lecb_ret
386 .align  16
387 .Lecb_dec_four:
388         call    _aesni_decrypt6
389         movups  $inout0,($out)
390         movups  $inout1,0x10($out)
391         movups  $inout2,0x20($out)
392         movups  $inout3,0x30($out)
393
394 .Lecb_ret:
395 ___
396 $code.=<<___ if ($win64);
397         movaps  (%rsp),%xmm6
398         movaps  0x10(%rsp),%xmm7
399         lea     0x28(%rsp),%rsp
400 ___
401 $code.=<<___;
402 .Lecb_abort:
403         ret
404 .size   aesni_ecb_encrypt,.-aesni_ecb_encrypt
405 ___
406 }
407 \f
408 # void $PREFIX_cbc_encrypt (const void *inp, void *out,
409 #                           size_t length, const AES_KEY *key,
410 #                           unsigned char *ivp,const int enc);
411 $reserved = $win64?0x90:-0x18;  # used in decrypt
412 $code.=<<___;
413 .globl  ${PREFIX}_cbc_encrypt
414 .type   ${PREFIX}_cbc_encrypt,\@function,6
415 .align  16
416 ${PREFIX}_cbc_encrypt:
417         test    $len,$len               # check length
418         jz      .Lcbc_ret
419         mov     240($key),$rounds       # pull $rounds
420         mov     $key,$key_              # backup $key
421         test    %r9d,%r9d
422         mov     $rounds,$rnds_          # backup $rounds
423         jz      .Lcbc_decrypt
424 #--------------------------- CBC ENCRYPT ------------------------------#
425         movups  ($ivp),%xmm0    # load iv as initial state
426         cmp     \$16,$len
427         jb      .Lcbc_enc_tail
428         sub     \$16,$len
429         jmp     .Lcbc_enc_loop
430 .align 16
431 .Lcbc_enc_loop:
432         movups  ($inp),%xmm2    # load input
433         lea     16($inp),$inp
434         pxor    %xmm2,%xmm0
435 ___
436         &aesni_encrypt1("%xmm0","%xmm1","%xmm2",$key,$rounds);
437 $code.=<<___;
438         movups  %xmm0,($out)    # store output
439         sub     \$16,$len
440         lea     16($out),$out
441         mov     $rnds_,$rounds  # restore $rounds
442         mov     $key_,$key      # restore $key
443         jnc     .Lcbc_enc_loop
444         add     \$16,$len
445         jnz     .Lcbc_enc_tail
446         movups  %xmm0,($ivp)
447         jmp     .Lcbc_ret
448
449 .Lcbc_enc_tail:
450         mov     $len,%rcx       # zaps $key
451         xchg    $inp,$out       # $inp is %rsi and $out is %rdi now
452         .long   0x9066A4F3      # rep movsb
453         mov     \$16,%ecx       # zero tail
454         sub     $len,%rcx
455         xor     %eax,%eax
456         .long   0x9066AAF3      # rep stosb
457         lea     -16(%rdi),%rdi  # rewind $out by 1 block
458         mov     $rnds_,$rounds  # restore $rounds
459         mov     %rdi,%rsi       # $inp and $out are the same
460         mov     $key_,$key      # restore $key
461         xor     $len,$len       # len=16
462         jmp     .Lcbc_enc_loop  # one more spin
463 \f#--------------------------- CBC DECRYPT ------------------------------#
464 .align  16
465 .Lcbc_decrypt:
466 ___
467 $code.=<<___ if ($win64);
468         lea     -0xa8(%rsp),%rsp
469         movaps  %xmm6,(%rsp)
470         movaps  %xmm7,0x10(%rsp)
471         movaps  %xmm8,0x20(%rsp)
472         movaps  %xmm9,0x30(%rsp)
473         movaps  %xmm10,0x40(%rsp)
474         movaps  %xmm11,0x50(%rsp)
475         movaps  %xmm12,0x60(%rsp)
476         movaps  %xmm13,0x70(%rsp)
477         movaps  %xmm14,0x80(%rsp)
478 ___
479 $code.=<<___;
480         movups  ($ivp),$iv
481         sub     \$0x60,$len
482         jc      .Lcbc_dec_tail
483         jmp     .Lcbc_dec_loop6
484 .align 16
485 .Lcbc_dec_loop6:
486         movups  ($inp),$inout0
487         movups  0x10($inp),$inout1
488         movups  0x20($inp),$inout2
489         movups  0x30($inp),$inout3
490         movaps  $inout0,$in0
491         movups  0x40($inp),$inout4
492         movaps  $inout1,$in1
493         movups  0x50($inp),$inout5
494         movaps  $inout2,$in2
495         movaps  $inout3,$in3
496         movaps  $inout4,$in4
497         movaps  $inout5,$in5
498         call    _aesni_decrypt6
499         pxor    $iv,$inout0
500         pxor    $in0,$inout1
501         movups  $inout0,($out)
502         sub     \$0x60,$len
503         pxor    $in1,$inout2
504         movups  $inout1,0x10($out)
505         lea     0x60($inp),$inp
506         pxor    $in2,$inout3
507         movups  $inout2,0x20($out)
508         mov     $rnds_,$rounds  # restore $rounds
509         pxor    $in3,$inout4
510         movups  $inout3,0x30($out)
511         mov     $key_,$key      # restore $key
512         pxor    $in4,$inout5
513         movups  $inout4,0x40($out)
514         movaps  $in5,$iv
515         movups  $inout5,0x50($out)
516         lea     0x60($out),$out
517         jnc     .Lcbc_dec_loop6
518
519 .Lcbc_dec_tail:
520         add     \$0x60,$len
521         movups  $iv,($ivp)
522         jz      .Lcbc_dec_ret
523
524         movups  ($inp),$inout0
525         cmp     \$0x10,$len
526         movaps  $inout0,$in0
527         jbe     .Lcbc_dec_one
528         movups  0x10($inp),$inout1
529         cmp     \$0x20,$len
530         movaps  $inout1,$in1
531         jbe     .Lcbc_dec_two
532         movups  0x20($inp),$inout2
533         cmp     \$0x30,$len
534         movaps  $inout2,$in2
535         jbe     .Lcbc_dec_three
536         movups  0x30($inp),$inout3
537         cmp     \$0x40,$len
538         movaps  $inout3,$in3
539         jbe     .Lcbc_dec_four
540         movups  0x40($inp),$inout4
541         cmp     \$0x50,$len
542         movaps  $inout4,$in4
543         jbe     .Lcbc_dec_five
544         movups  0x50($inp),$inout5
545         movaps  $inout5,$in5
546         call    _aesni_decrypt6
547         pxor    $iv,$inout0
548         pxor    $in0,$inout1
549         movups  $inout0,($out)
550         pxor    $in1,$inout2
551         movups  $inout1,0x10($out)
552         pxor    $in2,$inout3
553         movups  $inout2,0x20($out)
554         pxor    $in3,$inout4
555         movups  $inout3,0x30($out)
556         pxor    $in4,$inout5
557         movups  $inout4,0x40($out)
558         movaps  $in5,$iv
559         movaps  $inout5,$inout0
560         lea     0x50($out),$out
561         jmp     .Lcbc_dec_tail_collected
562 .align  16
563 .Lcbc_dec_one:
564 ___
565         &aesni_decrypt1($inout0,$rndkey0,$rndkey1,$key,$rounds);
566 $code.=<<___;
567         pxor    $iv,$inout0
568         movaps  $in0,$iv
569         jmp     .Lcbc_dec_tail_collected
570 .align  16
571 .Lcbc_dec_two:
572         call    _aesni_decrypt6
573         pxor    $iv,$inout0
574         pxor    $in0,$inout1
575         movups  $inout0,($out)
576         movaps  $in1,$iv
577         movaps  $inout1,$inout0
578         lea     0x10($out),$out
579         jmp     .Lcbc_dec_tail_collected
580 .align  16
581 .Lcbc_dec_three:
582         call    _aesni_decrypt6
583         pxor    $iv,$inout0
584         pxor    $in0,$inout1
585         movups  $inout0,($out)
586         pxor    $in1,$inout2
587         movups  $inout1,0x10($out)
588         movaps  $in2,$iv
589         movaps  $inout2,$inout0
590         lea     0x20($out),$out
591         jmp     .Lcbc_dec_tail_collected
592 .align  16
593 .Lcbc_dec_four:
594         call    _aesni_decrypt6
595         pxor    $iv,$inout0
596         pxor    $in0,$inout1
597         movups  $inout0,($out)
598         pxor    $in1,$inout2
599         movups  $inout1,0x10($out)
600         pxor    $in2,$inout3
601         movups  $inout2,0x20($out)
602         movaps  $in3,$iv
603         movaps  $inout3,$inout0
604         lea     0x30($out),$out
605         jmp     .Lcbc_dec_tail_collected
606 .align  16
607 .Lcbc_dec_five:
608         call    _aesni_decrypt6
609         pxor    $iv,$inout0
610         pxor    $in0,$inout1
611         movups  $inout0,($out)
612         pxor    $in1,$inout2
613         movups  $inout1,0x10($out)
614         pxor    $in2,$inout3
615         movups  $inout2,0x20($out)
616         pxor    $in3,$inout4
617         movups  $inout3,0x30($out)
618         movaps  $in4,$iv
619         movaps  $inout4,$inout0
620         lea     0x40($out),$out
621         jmp     .Lcbc_dec_tail_collected
622 .align  16
623 .Lcbc_dec_tail_collected:
624         and     \$15,$len
625         movups  $iv,($ivp)
626         jnz     .Lcbc_dec_tail_partial
627         movups  $inout0,($out)
628         jmp     .Lcbc_dec_ret
629 .Lcbc_dec_tail_partial:
630         movaps  $inout0,$reserved(%rsp)
631         mov     $out,%rdi
632         mov     $len,%rcx
633         lea     $reserved(%rsp),%rsi
634         .long   0x9066A4F3      # rep movsb
635
636 .Lcbc_dec_ret:
637 ___
638 $code.=<<___ if ($win64);
639         movaps  (%rsp),%xmm6
640         movaps  0x10(%rsp),%xmm7
641         movaps  0x20(%rsp),%xmm8
642         movaps  0x30(%rsp),%xmm9
643         movaps  0x40(%rsp),%xmm10
644         movaps  0x50(%rsp),%xmm11
645         movaps  0x60(%rsp),%xmm12
646         movaps  0x70(%rsp),%xmm13
647         movaps  0x80(%rsp),%xmm14
648         lea     0xa8(%rsp),%rsp
649 ___
650 $code.=<<___;
651 .Lcbc_ret:
652         ret
653 .size   ${PREFIX}_cbc_encrypt,.-${PREFIX}_cbc_encrypt
654 ___
655 \f
656 {
657 # this is natural argument order for $PREFIX_set_[en|de]crypt_key 
658 my $inp="%rdi";
659 my $bits="%esi";
660 my $key="%rdx";
661
662 # int $PREFIX_set_encrypt_key (const unsigned char *userKey, int bits,
663 #                              AES_KEY *key)
664 $code.=<<___;
665 .globl  ${PREFIX}_set_encrypt_key
666 .type   ${PREFIX}_set_encrypt_key,\@function,3
667 .align  16
668 ${PREFIX}_set_encrypt_key:
669         call    _aesni_set_encrypt_key
670         ret
671 .size   ${PREFIX}_set_encrypt_key,.-${PREFIX}_set_encrypt_key
672 ___
673 # int $PREFIX_set_decrypt_key(const unsigned char *userKey, const int bits,
674 #                               AES_KEY *key)
675 $code.=<<___;
676 .globl  ${PREFIX}_set_decrypt_key
677 .type   ${PREFIX}_set_decrypt_key,\@function,3
678 .align  16
679 ${PREFIX}_set_decrypt_key:
680         call    _aesni_set_encrypt_key
681         shl     \$4,%esi        # actually rounds after _aesni_set_encrypt_key
682         test    %eax,%eax
683         jnz     .Ldec_key_ret
684         lea     (%rdx,%rsi),%rsi# points at the end of key schedule
685
686         $movkey (%rdx),%xmm0    # just swap
687         $movkey (%rsi),%xmm1
688         $movkey %xmm0,(%rsi)
689         $movkey %xmm1,(%rdx)
690         lea     16(%rdx),%rdx
691         lea     -16(%rsi),%rsi
692         jmp     .Ldec_key_inverse
693 .align 16
694 .Ldec_key_inverse:
695         $movkey (%rdx),%xmm0    # swap and inverse
696         $movkey (%rsi),%xmm1
697         aesimc  %xmm0,%xmm0
698         aesimc  %xmm1,%xmm1
699         lea     16(%rdx),%rdx
700         lea     -16(%rsi),%rsi
701         cmp     %rdx,%rsi
702         $movkey %xmm0,16(%rsi)
703         $movkey %xmm1,-16(%rdx)
704         ja      .Ldec_key_inverse
705
706         $movkey (%rdx),%xmm0    # inverse middle
707         aesimc  %xmm0,%xmm0
708         $movkey %xmm0,(%rsi)
709 .Ldec_key_ret:
710         ret
711 .size   ${PREFIX}_set_decrypt_key,.-${PREFIX}_set_decrypt_key
712 ___
713 \f
714 # This is based on submission by
715 #
716 #       Huang Ying <ying.huang@intel.com>
717 #       Vinodh Gopal <vinodh.gopal@intel.com>
718 #       Kahraman Akdemir
719 #
720 # Agressively optimized in respect to aeskeygenassist's critical path
721 # and is contained in %xmm0-5 to meet Win64 ABI requirement.
722 #
723 $code.=<<___;
724 .type   _aesni_set_encrypt_key,\@abi-omnipotent
725 .align  16
726 _aesni_set_encrypt_key:
727         test    %rdi,%rdi
728         jz      .Lbad_pointer
729         test    %rdx,%rdx
730         jz      .Lbad_pointer
731
732         movups  (%rdi),%xmm0            # pull first 128 bits of *userKey
733         pxor    %xmm4,%xmm4             # low dword of xmm4 is assumed 0
734         lea     16(%rdx),%rcx
735         cmp     \$256,%esi
736         je      .L14rounds
737         cmp     \$192,%esi
738         je      .L12rounds
739         cmp     \$128,%esi
740         jne     .Lbad_keybits
741 \f
742 .L10rounds:
743         mov     \$10,%esi                       # 10 rounds for 128-bit key
744         $movkey %xmm0,(%rdx)                    # round 0
745         aeskeygenassist \$0x1,%xmm0,%xmm1       # round 1
746         call            .Lkey_expansion_128_cold
747         aeskeygenassist \$0x2,%xmm0,%xmm1       # round 2
748         call            .Lkey_expansion_128
749         aeskeygenassist \$0x4,%xmm0,%xmm1       # round 3
750         call            .Lkey_expansion_128
751         aeskeygenassist \$0x8,%xmm0,%xmm1       # round 4
752         call            .Lkey_expansion_128
753         aeskeygenassist \$0x10,%xmm0,%xmm1      # round 5
754         call            .Lkey_expansion_128
755         aeskeygenassist \$0x20,%xmm0,%xmm1      # round 6
756         call            .Lkey_expansion_128
757         aeskeygenassist \$0x40,%xmm0,%xmm1      # round 7
758         call            .Lkey_expansion_128
759         aeskeygenassist \$0x80,%xmm0,%xmm1      # round 8
760         call            .Lkey_expansion_128
761         aeskeygenassist \$0x1b,%xmm0,%xmm1      # round 9
762         call            .Lkey_expansion_128
763         aeskeygenassist \$0x36,%xmm0,%xmm1      # round 10
764         call            .Lkey_expansion_128
765         $movkey %xmm0,(%rcx)
766         mov     %esi,80(%rcx)   # 240(%rdx)
767         xor     %eax,%eax
768         ret
769
770 .align  16
771 .Lkey_expansion_128:
772         $movkey %xmm0,(%rcx)
773         lea     16(%rcx),%rcx
774 .Lkey_expansion_128_cold:
775         shufps  \$0b00010000,%xmm0,%xmm4
776         pxor    %xmm4, %xmm0
777         shufps  \$0b10001100,%xmm0,%xmm4
778         pxor    %xmm4, %xmm0
779         pshufd  \$0b11111111,%xmm1,%xmm1        # critical path
780         pxor    %xmm1,%xmm0
781         ret
782 \f
783 .align  16
784 .L12rounds:
785         movq    16(%rdi),%xmm2                  # remaining 1/3 of *userKey
786         mov     \$12,%esi                       # 12 rounds for 192
787         $movkey %xmm0,(%rdx)                    # round 0
788         aeskeygenassist \$0x1,%xmm2,%xmm1       # round 1,2
789         call            .Lkey_expansion_192a_cold
790         aeskeygenassist \$0x2,%xmm2,%xmm1       # round 2,3
791         call            .Lkey_expansion_192b
792         aeskeygenassist \$0x4,%xmm2,%xmm1       # round 4,5
793         call            .Lkey_expansion_192a
794         aeskeygenassist \$0x8,%xmm2,%xmm1       # round 5,6
795         call            .Lkey_expansion_192b
796         aeskeygenassist \$0x10,%xmm2,%xmm1      # round 7,8
797         call            .Lkey_expansion_192a
798         aeskeygenassist \$0x20,%xmm2,%xmm1      # round 8,9
799         call            .Lkey_expansion_192b
800         aeskeygenassist \$0x40,%xmm2,%xmm1      # round 10,11
801         call            .Lkey_expansion_192a
802         aeskeygenassist \$0x80,%xmm2,%xmm1      # round 11,12
803         call            .Lkey_expansion_192b
804         $movkey %xmm0,(%rcx)
805         mov     %esi,48(%rcx)   # 240(%rdx)
806         xor     %rax, %rax
807         ret
808
809 .align 16
810 .Lkey_expansion_192a:
811         $movkey %xmm0,(%rcx)
812         lea     16(%rcx),%rcx
813 .Lkey_expansion_192a_cold:
814         movaps  %xmm2, %xmm5
815 .Lkey_expansion_192b_warm:
816         shufps  \$0b00010000,%xmm0,%xmm4
817         movaps  %xmm2,%xmm3
818         pxor    %xmm4,%xmm0
819         shufps  \$0b10001100,%xmm0,%xmm4
820         pslldq  \$4,%xmm3
821         pxor    %xmm4,%xmm0
822         pshufd  \$0b01010101,%xmm1,%xmm1        # critical path
823         pxor    %xmm3,%xmm2
824         pxor    %xmm1,%xmm0
825         pshufd  \$0b11111111,%xmm0,%xmm3
826         pxor    %xmm3,%xmm2
827         ret
828
829 .align 16
830 .Lkey_expansion_192b:
831         movaps  %xmm0,%xmm3
832         shufps  \$0b01000100,%xmm0,%xmm5
833         $movkey %xmm5,(%rcx)
834         shufps  \$0b01001110,%xmm2,%xmm3
835         $movkey %xmm3,16(%rcx)
836         lea     32(%rcx),%rcx
837         jmp     .Lkey_expansion_192b_warm
838 \f
839 .align  16
840 .L14rounds:
841         movups  16(%rdi),%xmm2                  # remaning half of *userKey
842         mov     \$14,%esi                       # 14 rounds for 256
843         lea     16(%rcx),%rcx
844         $movkey %xmm0,(%rdx)                    # round 0
845         $movkey %xmm2,16(%rdx)                  # round 1
846         aeskeygenassist \$0x1,%xmm2,%xmm1       # round 2
847         call            .Lkey_expansion_256a_cold
848         aeskeygenassist \$0x1,%xmm0,%xmm1       # round 3
849         call            .Lkey_expansion_256b
850         aeskeygenassist \$0x2,%xmm2,%xmm1       # round 4
851         call            .Lkey_expansion_256a
852         aeskeygenassist \$0x2,%xmm0,%xmm1       # round 5
853         call            .Lkey_expansion_256b
854         aeskeygenassist \$0x4,%xmm2,%xmm1       # round 6
855         call            .Lkey_expansion_256a
856         aeskeygenassist \$0x4,%xmm0,%xmm1       # round 7
857         call            .Lkey_expansion_256b
858         aeskeygenassist \$0x8,%xmm2,%xmm1       # round 8
859         call            .Lkey_expansion_256a
860         aeskeygenassist \$0x8,%xmm0,%xmm1       # round 9
861         call            .Lkey_expansion_256b
862         aeskeygenassist \$0x10,%xmm2,%xmm1      # round 10
863         call            .Lkey_expansion_256a
864         aeskeygenassist \$0x10,%xmm0,%xmm1      # round 11
865         call            .Lkey_expansion_256b
866         aeskeygenassist \$0x20,%xmm2,%xmm1      # round 12
867         call            .Lkey_expansion_256a
868         aeskeygenassist \$0x20,%xmm0,%xmm1      # round 13
869         call            .Lkey_expansion_256b
870         aeskeygenassist \$0x40,%xmm2,%xmm1      # round 14
871         call            .Lkey_expansion_256a
872         $movkey %xmm0,(%rcx)
873         mov     %esi,16(%rcx)   # 240(%rdx)
874         xor     %rax,%rax
875         ret
876
877 .align  16
878 .Lkey_expansion_256a:
879         $movkey %xmm2,(%rcx)
880         lea     16(%rcx),%rcx
881 .Lkey_expansion_256a_cold:
882         shufps  \$0b00010000,%xmm0,%xmm4
883         pxor    %xmm4,%xmm0
884         shufps  \$0b10001100,%xmm0,%xmm4
885         pxor    %xmm4,%xmm0
886         pshufd  \$0b11111111,%xmm1,%xmm1        # critical path
887         pxor    %xmm1,%xmm0
888         ret
889
890 .align 16
891 .Lkey_expansion_256b:
892         $movkey %xmm0,(%rcx)
893         lea     16(%rcx),%rcx
894
895         shufps  \$0b00010000,%xmm2,%xmm4
896         pxor    %xmm4,%xmm2
897         shufps  \$0b10001100,%xmm2,%xmm4
898         pxor    %xmm4,%xmm2
899         pshufd  \$0b10101010,%xmm1,%xmm1        # critical path
900         pxor    %xmm1,%xmm2
901         ret
902 \f
903 .align  16
904 .Lbad_pointer:
905         mov \$-1, %rax
906         ret
907 .Lbad_keybits:
908         mov \$-2, %rax
909         ret
910 .size   _aesni_set_encrypt_key,.-_aesni_set_encrypt_key
911 ___
912 }
913 \f
914 $code.=<<___;
915 .asciz  "AES for Intel AES-NI, CRYPTOGAMS by <appro\@openssl.org>"
916 .align  64
917 ___
918
919 sub rex {
920  local *opcode=shift;
921  my ($dst,$src)=@_;
922
923    if ($dst>=8 || $src>=8) {
924         $rex=0x40;
925         $rex|=0x04 if($dst>=8);
926         $rex|=0x01 if($src>=8);
927         push @opcode,$rex;
928    }
929 }
930
931 sub aesni {
932   my $line=shift;
933   my @opcode=(0x66);
934
935     if ($line=~/(aeskeygenassist)\s+\$([x0-9a-f]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) {
936         rex(\@opcode,$4,$3);
937         push @opcode,0x0f,0x3a,0xdf;
938         push @opcode,0xc0|($3&7)|(($4&7)<<3);   # ModR/M
939         my $c=$2;
940         push @opcode,$c=~/^0/?oct($c):$c;
941         return ".byte\t".join(',',@opcode);
942     }
943     elsif ($line=~/(aes[a-z]+)\s+%xmm([0-9]+),\s*%xmm([0-9]+)/) {
944         my %opcodelet = (
945                 "aesimc" => 0xdb,
946                 "aesenc" => 0xdc,       "aesenclast" => 0xdd,
947                 "aesdec" => 0xde,       "aesdeclast" => 0xdf
948         );
949         return undef if (!defined($opcodelet{$1}));
950         rex(\@opcode,$3,$2);
951         push @opcode,0x0f,0x38,$opcodelet{$1};
952         push @opcode,0xc0|($2&7)|(($3&7)<<3);   # ModR/M
953         return ".byte\t".join(',',@opcode);
954     }
955     return $line;
956 }
957
958 $code =~ s/\`([^\`]*)\`/eval($1)/gem;
959 $code =~ s/\b(aes.*%xmm[0-9]+).*$/aesni($1)/gem;
960
961 print $code;
962
963 close STDOUT;