Add AES assembly module for Fujitsu SPARC64 X/X+.
[openssl.git] / crypto / aes / asm / aesfx-sparcv9.pl
1 #!/usr/bin/env perl
2 #
3 # ====================================================================
4 # Written by Andy Polyakov <appro@openssl.org> 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 # March 2016
11 #
12 # Initial support for Fujitsu SPARC64 X/X+ comprises minimally
13 # required key setup and single-block procedures.
14
15 $output = pop;
16 open STDOUT,">$output";
17
18 {
19 my ($inp,$out,$key,$rounds,$tmp,$mask) = map("%o$_",(0..5));
20
21 $code.=<<___;
22 .text
23
24 .globl  aes_fx_encrypt
25 .align  32
26 aes_fx_encrypt:
27         and             $inp, 7, $tmp           ! is input aligned?
28         alignaddr       $inp, %g0, $inp
29         ld              [$key + 240], $rounds
30         ldd             [$key +  0], %f6
31         ldd             [$key +  8], %f8
32
33         ldd             [$inp + 0], %f0         ! load input
34         brz,pt          $tmp, .Lenc_inp_aligned
35         ldd             [$inp + 8], %f2
36
37         ldd             [$inp + 16], %f4
38         faligndata      %f0, %f2, %f0
39         faligndata      %f2, %f4, %f2
40
41 .Lenc_inp_aligned:
42         ldd             [$key + 16], %f10
43         ldd             [$key + 24], %f12
44         add             $key, 32, $key
45
46         fxor            %f0, %f6, %f0           ! ^=round[0]
47         fxor            %f2, %f8, %f2
48         ldd             [$key +  0], %f6
49         ldd             [$key +  8], %f8
50         sub             $rounds, 4, $rounds
51
52 .Loop_enc:
53         fmovd           %f0, %f4
54         faesencx        %f2, %f10, %f0
55         faesencx        %f4, %f12, %f2
56         ldd             [$key + 16], %f10
57         ldd             [$key + 24], %f12
58         add             $key, 32, $key
59
60         fmovd           %f0, %f4
61         faesencx        %f2, %f6, %f0
62         faesencx        %f4, %f8, %f2
63         ldd             [$key +  0], %f6
64         ldd             [$key +  8], %f8
65
66         brnz,a          $rounds, .Loop_enc
67         sub             $rounds, 2, $rounds
68
69         andcc           $out, 7, $tmp           ! is output aligned?
70         mov             0xff, $mask
71         alignaddrl      $out, %g0, $out
72         srl             $mask, $tmp, $mask
73
74         fmovd           %f0, %f4
75         faesencx        %f2, %f10, %f0
76         faesencx        %f4, %f12, %f2
77         fmovd           %f0, %f4
78         faesenclx       %f2, %f6, %f0
79         faesenclx       %f4, %f8, %f2
80
81         bnz,pn          %icc, .Lenc_out_unaligned
82         nop
83
84         std             %f0, [$out + 0]
85         retl
86         std             %f2, [$out + 8]
87
88 .Lenc_out_unaligned:
89         faligndata      %f0, %f0, %f4
90         faligndata      %f0, %f2, %f6
91         faligndata      %f2, %f2, %f8
92
93         stda            %f4, [$out + $mask]0xc0 ! partial store
94         std             %f6, [$out + 8]
95         add             $out, 16, $out
96         orn             %g0, $mask, $mask
97         retl
98         stda            %f8, [$out + $mask]0xc0 ! partial store
99 .size   aes_fx_encrypt,.-aes_fx_encrypt
100
101 .globl  aes_fx_decrypt
102 .align  32
103 aes_fx_decrypt:
104         and             $inp, 7, $tmp           ! is input aligned?
105         alignaddr       $inp, %g0, $inp
106         ld              [$key + 240], $rounds
107         ldd             [$key +  0], %f6
108         ldd             [$key +  8], %f8
109
110         ldd             [$inp + 0], %f0         ! load input
111         brz,pt          $tmp, .Ldec_inp_aligned
112         ldd             [$inp + 8], %f2
113
114         ldd             [$inp + 16], %f4
115         faligndata      %f0, %f2, %f0
116         faligndata      %f2, %f4, %f2
117
118 .Ldec_inp_aligned:
119         ldd             [$key + 16], %f10
120         ldd             [$key + 24], %f12
121         add             $key, 32, $key
122
123         fxor            %f0, %f6, %f0           ! ^=round[0]
124         fxor            %f2, %f8, %f2
125         ldd             [$key +  0], %f6
126         ldd             [$key +  8], %f8
127         sub             $rounds, 4, $rounds
128
129 .Loop_dec:
130         fmovd           %f0, %f4
131         faesdecx        %f2, %f10, %f0
132         faesdecx        %f4, %f12, %f2
133         ldd             [$key + 16], %f10
134         ldd             [$key + 24], %f12
135         add             $key, 32, $key
136
137         fmovd           %f0, %f4
138         faesdecx        %f2, %f6, %f0
139         faesdecx        %f4, %f8, %f2
140         ldd             [$key +  0], %f6
141         ldd             [$key +  8], %f8
142
143         brnz,a          $rounds, .Loop_dec
144         sub             $rounds, 2, $rounds
145
146         andcc           $out, 7, $tmp           ! is output aligned?
147         mov             0xff, $mask
148         alignaddrl      $out, %g0, $out
149         srl             $mask, $tmp, $mask
150
151         fmovd           %f0, %f4
152         faesdecx        %f2, %f10, %f0
153         faesdecx        %f4, %f12, %f2
154         fmovd           %f0, %f4
155         faesdeclx       %f2, %f6, %f0
156         faesdeclx       %f4, %f8, %f2
157
158         bnz,pn          %icc, .Ldec_out_unaligned
159         nop
160
161         std             %f0, [$out + 0]
162         retl
163         std             %f2, [$out + 8]
164
165 .Ldec_out_unaligned:
166         faligndata      %f0, %f0, %f4
167         faligndata      %f0, %f2, %f6
168         faligndata      %f2, %f2, %f8
169
170         stda            %f4, [$out + $mask]0xc0 ! partial store
171         std             %f6, [$out + 8]
172         add             $out, 16, $out
173         orn             %g0, $mask, $mask
174         retl
175         stda            %f8, [$out + $mask]0xc0 ! partial store
176 .size   aes_fx_decrypt,.-aes_fx_decrypt
177 ___
178 }
179 {
180 my ($inp,$bits,$out,$tmp,$inc) = map("%o$_",(0..5));
181 $code.=<<___;
182 .globl  aes_fx_set_decrypt_key
183 .align  32
184 aes_fx_set_decrypt_key:
185         b               .Lset_encrypt_key
186         mov             -1, $inc
187         retl
188         nop
189 .size   aes_fx_set_decrypt_key,.-aes_fx_set_decrypt_key
190
191 .globl  aes_fx_set_encrypt_key
192 .align  32
193 aes_fx_set_encrypt_key:
194         mov             1, $inc
195 .Lset_encrypt_key:
196         and             $inp, 7, $tmp
197         alignaddr       $inp, %g0, $inp
198         nop
199
200         cmp             $bits, 192
201         ldd             [$inp + 0], %f0
202         bl,pt           %icc, .L128
203         ldd             [$inp + 8], %f2
204
205         be,pt           %icc, .L192
206         ldd             [$inp + 16], %f4
207         brz,pt          $tmp, .L256aligned
208         ldd             [$inp + 24], %f6
209
210         ldd             [$inp + 32], %f8
211         faligndata      %f0, %f2, %f0
212         faligndata      %f2, %f4, %f2
213         faligndata      %f4, %f6, %f4
214         faligndata      %f6, %f8, %f6
215
216 .L256aligned:
217         mov             14, $bits
218         and             $inc, `14*16`, $tmp
219         st              $bits, [$out + 240]     ! store rounds
220         add             $out, $tmp, $out        ! start or end of key schedule
221         sllx            $inc, 4, $inc           ! 16 or -16
222 ___
223 for ($i=0; $i<6; $i++) {
224     $code.=<<___;
225         std             %f0, [$out + 0]
226         faeskeyx        %f6, `0x10+$i`, %f0
227         std             %f2, [$out + 8]
228         add             $out, $inc, $out
229         faeskeyx        %f0, 0x00, %f2
230         std             %f4, [$out + 0]
231         faeskeyx        %f2, 0x01, %f4
232         std             %f6, [$out + 8]
233         add             $out, $inc, $out
234         faeskeyx        %f4, 0x00, %f6
235 ___
236 }
237 $code.=<<___;
238         std             %f0, [$out + 0]
239         faeskeyx        %f6, `0x10+$i`, %f0
240         std             %f2, [$out + 8]
241         add             $out, $inc, $out
242         faeskeyx        %f0, 0x00, %f2
243         std             %f4,[$out+0]
244         std             %f6,[$out+8]
245         add             $out, $inc, $out
246         std             %f0,[$out+0]
247         std             %f2,[$out+8]
248         retl
249         xor             %o0, %o0, %o0           ! return 0
250
251 .align  16
252 .L192:
253         brz,pt          $tmp, .L192aligned
254         nop
255
256         ldd             [$inp + 24], %f6
257         faligndata      %f0, %f2, %f0
258         faligndata      %f2, %f4, %f2
259         faligndata      %f4, %f6, %f4
260
261 .L192aligned:
262         mov             12, $bits
263         and             $inc, `12*16`, $tmp
264         st              $bits, [$out + 240]     ! store rounds
265         add             $out, $tmp, $out        ! start or end of key schedule
266         sllx            $inc, 4, $inc           ! 16 or -16
267 ___
268 for ($i=0; $i<8; $i+=2) {
269     $code.=<<___;
270         std             %f0, [$out + 0]
271         faeskeyx        %f4, `0x10+$i`, %f0
272         std             %f2, [$out + 8]
273         add             $out, $inc, $out
274         faeskeyx        %f0, 0x00, %f2
275         std             %f4, [$out + 0]
276         faeskeyx        %f2, 0x00, %f4
277         std             %f0, [$out + 8]
278         add             $out, $inc, $out
279         faeskeyx        %f4, `0x10+$i+1`, %f0
280         std             %f2, [$out + 0]
281         faeskeyx        %f0, 0x00, %f2
282         std             %f4, [$out + 8]
283         add             $out, $inc, $out
284 ___
285 $code.=<<___            if ($i<6);
286         faeskeyx        %f2, 0x00, %f4
287 ___
288 }
289 $code.=<<___;
290         std             %f0, [$out + 0]
291         std             %f2, [$out + 8]
292         retl
293         xor             %o0, %o0, %o0           ! return 0
294
295 .align  16
296 .L128:
297         brz,pt          $tmp, .L128aligned
298         nop
299
300         ldd             [$inp + 16], %f4
301         faligndata      %f0, %f2, %f0
302         faligndata      %f2, %f4, %f2
303
304 .L128aligned:
305         mov             10, $bits
306         and             $inc, `10*16`, $tmp
307         st              $bits, [$out + 240]     ! store rounds
308         add             $out, $tmp, $out        ! start or end of key schedule
309         sllx            $inc, 4, $inc           ! 16 or -16
310 ___
311 for ($i=0; $i<10; $i++) {
312     $code.=<<___;
313         std             %f0, [$out + 0]
314         faeskeyx        %f2, `0x10+$i`, %f0
315         std             %f2, [$out + 8]
316         add             $out, $inc, $out
317         faeskeyx        %f0, 0x00, %f2
318 ___
319 }
320 $code.=<<___;
321         std             %f0, [$out + 0]
322         std             %f2, [$out + 8]
323         retl
324         xor             %o0, %o0, %o0           ! return 0
325 .size   aes_fx_set_encrypt_key,.-aes_fx_set_encrypt_key
326 ___
327 }
328
329 # Purpose of these subroutines is to explicitly encode VIS instructions,
330 # so that one can compile the module without having to specify VIS
331 # extensions on compiler command line, e.g. -xarch=v9 vs. -xarch=v9a.
332 # Idea is to reserve for option to produce "universal" binary and let
333 # programmer detect if current CPU is VIS capable at run-time.
334 sub unvis {
335 my ($mnemonic,$rs1,$rs2,$rd)=@_;
336 my ($ref,$opf);
337 my %visopf = (  "faligndata"    => 0x048,
338                 "bshuffle"      => 0x04c,
339                 "fxor"          => 0x06c,
340                 "fsrc2"         => 0x078        );
341
342     $ref = "$mnemonic\t$rs1,$rs2,$rd";
343
344     if ($opf=$visopf{$mnemonic}) {
345         foreach ($rs1,$rs2,$rd) {
346             return $ref if (!/%f([0-9]{1,2})/);
347             $_=$1;
348             if ($1>=32) {
349                 return $ref if ($1&1);
350                 # re-encode for upper double register addressing
351                 $_=($1|$1>>5)&31;
352             }
353         }
354
355         return  sprintf ".word\t0x%08x !%s",
356                         0x81b00000|$rd<<25|$rs1<<14|$opf<<5|$rs2,
357                         $ref;
358     } else {
359         return $ref;
360     }
361 }
362
363 sub unvis3 {
364 my ($mnemonic,$rs1,$rs2,$rd)=@_;
365 my %bias = ( "g" => 0, "o" => 8, "l" => 16, "i" => 24 );
366 my ($ref,$opf);
367 my %visopf = (  "alignaddr"     => 0x018,
368                 "bmask"         => 0x019,
369                 "alignaddrl"    => 0x01a        );
370
371     $ref = "$mnemonic\t$rs1,$rs2,$rd";
372
373     if ($opf=$visopf{$mnemonic}) {
374         foreach ($rs1,$rs2,$rd) {
375             return $ref if (!/%([goli])([0-9])/);
376             $_=$bias{$1}+$2;
377         }
378
379         return  sprintf ".word\t0x%08x !%s",
380                         0x81b00000|$rd<<25|$rs1<<14|$opf<<5|$rs2,
381                         $ref;
382     } else {
383         return $ref;
384     }
385 }
386
387 sub unfx {
388 my ($mnemonic,$rs1,$rs2,$rd)=@_;
389 my ($ref,$opf);
390 my %aesopf = (  "faesencx"      => 0x90,
391                 "faesdecx"      => 0x91,
392                 "faesenclx"     => 0x92,
393                 "faesdeclx"     => 0x93,
394                 "faeskeyx"      => 0x94 );
395
396     $ref = "$mnemonic\t$rs1,$rs2,$rd";
397
398     if (defined($opf=$aesopf{$mnemonic})) {
399         $rs2 = ($rs2 =~ /%f([0-6]*[02468])/) ? (($1|$1>>5)&31) : $rs2;
400         $rs2 = oct($rs2) if ($rs2 =~ /^0/);
401
402         foreach ($rs1,$rd) {
403             return $ref if (!/%f([0-9]{1,2})/);
404             $_=$1;
405             if ($1>=32) {
406                 return $ref if ($1&1);
407                 # re-encode for upper double register addressing
408                 $_=($1|$1>>5)&31;
409             }
410         }
411
412         return  sprintf ".word\t0x%08x !%s",
413                         2<<30|$rd<<25|0x36<<19|$rs1<<14|$opf<<5|$rs2,
414                         $ref;
415     } else {
416         return $ref;
417     }
418 }
419
420 foreach (split("\n",$code)) {
421     s/\`([^\`]*)\`/eval $1/ge;
422
423     s/\b(faes[^x]{3,4}x)\s+(%f[0-9]{1,2}),\s*([%fx0-9]+),\s*(%f[0-9]{1,2})/
424                 &unfx($1,$2,$3,$4,$5)
425      /ge or
426     s/\b([fb][^\s]*)\s+(%f[0-9]{1,2}),\s*(%f[0-9]{1,2}),\s*(%f[0-9]{1,2})/
427                 &unvis($1,$2,$3,$4)
428      /ge or
429     s/\b(alignaddr[l]*)\s+(%[goli][0-7]),\s*(%[goli][0-7]),\s*(%[goli][0-7])/
430                 &unvis3($1,$2,$3,$4)
431      /ge;
432     print $_,"\n";
433 }
434
435 close STDOUT;