crypto/x86_64cpuid.pl: move extended feature detection upwards.
[openssl.git] / crypto / x86_64cpuid.pl
1 #! /usr/bin/env perl
2 # Copyright 2005-2016 The OpenSSL Project Authors. All Rights Reserved.
3 #
4 # Licensed under the OpenSSL license (the "License").  You may not use
5 # this file except in compliance with the License.  You can obtain a copy
6 # in the file LICENSE in the source distribution or at
7 # https://www.openssl.org/source/license.html
8
9
10 $flavour = shift;
11 $output  = shift;
12 if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
13
14 $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
15
16 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
17 ( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
18 ( $xlate="${dir}perlasm/x86_64-xlate.pl" and -f $xlate) or
19 die "can't locate x86_64-xlate.pl";
20
21 open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
22 *STDOUT=*OUT;
23
24 ($arg1,$arg2,$arg3,$arg4)=$win64?("%rcx","%rdx","%r8", "%r9") : # Win64 order
25                                  ("%rdi","%rsi","%rdx","%rcx"); # Unix order
26
27 print<<___;
28 .extern         OPENSSL_cpuid_setup
29 .hidden         OPENSSL_cpuid_setup
30 .section        .init
31         call    OPENSSL_cpuid_setup
32
33 .hidden OPENSSL_ia32cap_P
34 .comm   OPENSSL_ia32cap_P,16,4
35
36 .text
37
38 .globl  OPENSSL_atomic_add
39 .type   OPENSSL_atomic_add,\@abi-omnipotent
40 .align  16
41 OPENSSL_atomic_add:
42         movl    ($arg1),%eax
43 .Lspin: leaq    ($arg2,%rax),%r8
44         .byte   0xf0            # lock
45         cmpxchgl        %r8d,($arg1)
46         jne     .Lspin
47         movl    %r8d,%eax
48         .byte   0x48,0x98       # cltq/cdqe
49         ret
50 .size   OPENSSL_atomic_add,.-OPENSSL_atomic_add
51
52 .globl  OPENSSL_rdtsc
53 .type   OPENSSL_rdtsc,\@abi-omnipotent
54 .align  16
55 OPENSSL_rdtsc:
56         rdtsc
57         shl     \$32,%rdx
58         or      %rdx,%rax
59         ret
60 .size   OPENSSL_rdtsc,.-OPENSSL_rdtsc
61
62 .globl  OPENSSL_ia32_cpuid
63 .type   OPENSSL_ia32_cpuid,\@function,1
64 .align  16
65 OPENSSL_ia32_cpuid:
66         mov     %rbx,%r8                # save %rbx
67
68         xor     %eax,%eax
69         mov     %eax,8(%rdi)            # clear 3rd word
70         cpuid
71         mov     %eax,%r11d              # max value for standard query level
72
73         cmp     \$7,%eax
74         jb      .Lno_extended_info
75
76         mov     \$7,%eax
77         xor     %ecx,%ecx
78         cpuid
79         mov     %ebx,8(%rdi)
80
81 .Lno_extended_info:
82
83         xor     %eax,%eax
84         cmp     \$0x756e6547,%ebx       # "Genu"
85         setne   %al
86         mov     %eax,%r9d
87         cmp     \$0x49656e69,%edx       # "ineI"
88         setne   %al
89         or      %eax,%r9d
90         cmp     \$0x6c65746e,%ecx       # "ntel"
91         setne   %al
92         or      %eax,%r9d               # 0 indicates Intel CPU
93         jz      .Lintel
94
95         cmp     \$0x68747541,%ebx       # "Auth"
96         setne   %al
97         mov     %eax,%r10d
98         cmp     \$0x69746E65,%edx       # "enti"
99         setne   %al
100         or      %eax,%r10d
101         cmp     \$0x444D4163,%ecx       # "cAMD"
102         setne   %al
103         or      %eax,%r10d              # 0 indicates AMD CPU
104         jnz     .Lintel
105
106         # AMD specific
107         mov     \$0x80000000,%eax
108         cpuid
109         cmp     \$0x80000001,%eax
110         jb      .Lintel
111         mov     %eax,%r10d
112         mov     \$0x80000001,%eax
113         cpuid
114         or      %ecx,%r9d
115         and     \$0x00000801,%r9d       # isolate AMD XOP bit, 1<<11
116
117         cmp     \$0x80000008,%r10d
118         jb      .Lintel
119
120         mov     \$0x80000008,%eax
121         cpuid
122         movzb   %cl,%r10                # number of cores - 1
123         inc     %r10                    # number of cores
124
125         mov     \$1,%eax
126         cpuid
127         bt      \$28,%edx               # test hyper-threading bit
128         jnc     .Lgeneric
129         shr     \$16,%ebx               # number of logical processors
130         cmp     %r10b,%bl
131         ja      .Lgeneric
132         and     \$0xefffffff,%edx       # ~(1<<28)
133         jmp     .Lgeneric
134
135 .Lintel:
136         cmp     \$4,%r11d
137         mov     \$-1,%r10d
138         jb      .Lnocacheinfo
139
140         mov     \$4,%eax
141         mov     \$0,%ecx                # query L1D
142         cpuid
143         mov     %eax,%r10d
144         shr     \$14,%r10d
145         and     \$0xfff,%r10d           # number of cores -1 per L1D
146
147 .Lnocacheinfo:
148         mov     \$1,%eax
149         cpuid
150         and     \$0xbfefffff,%edx       # force reserved bits to 0
151         cmp     \$0,%r9d
152         jne     .Lnotintel
153         or      \$0x40000000,%edx       # set reserved bit#30 on Intel CPUs
154         and     \$15,%ah
155         cmp     \$15,%ah                # examine Family ID
156         jne     .Lnotintel
157         or      \$0x00100000,%edx       # set reserved bit#20 to engage RC4_CHAR
158 .Lnotintel:
159         bt      \$28,%edx               # test hyper-threading bit
160         jnc     .Lgeneric
161         and     \$0xefffffff,%edx       # ~(1<<28)
162         cmp     \$0,%r10d
163         je      .Lgeneric
164
165         or      \$0x10000000,%edx       # 1<<28
166         shr     \$16,%ebx
167         cmp     \$1,%bl                 # see if cache is shared
168         ja      .Lgeneric
169         and     \$0xefffffff,%edx       # ~(1<<28)
170 .Lgeneric:
171         and     \$0x00000800,%r9d       # isolate AMD XOP flag
172         and     \$0xfffff7ff,%ecx
173         or      %ecx,%r9d               # merge AMD XOP flag
174
175         mov     %edx,%r10d              # %r9d:%r10d is copy of %ecx:%edx
176         bt      \$27,%r9d               # check OSXSAVE bit
177         jnc     .Lclear_avx
178         xor     %ecx,%ecx               # XCR0
179         .byte   0x0f,0x01,0xd0          # xgetbv
180         and     \$6,%eax                # isolate XMM and YMM state support
181         cmp     \$6,%eax
182         je      .Ldone
183 .Lclear_avx:
184         mov     \$0xefffe7ff,%eax       # ~(1<<28|1<<12|1<<11)
185         and     %eax,%r9d               # clear AVX, FMA and AMD XOP bits
186         andl    \$0xffffffdf,8(%rdi)    # cleax AVX2, ~(1<<5)
187 .Ldone:
188         shl     \$32,%r9
189         mov     %r10d,%eax
190         mov     %r8,%rbx                # restore %rbx
191         or      %r9,%rax
192         ret
193 .size   OPENSSL_ia32_cpuid,.-OPENSSL_ia32_cpuid
194
195 .globl  OPENSSL_cleanse
196 .type   OPENSSL_cleanse,\@abi-omnipotent
197 .align  16
198 OPENSSL_cleanse:
199         xor     %rax,%rax
200         cmp     \$15,$arg2
201         jae     .Lot
202         cmp     \$0,$arg2
203         je      .Lret
204 .Little:
205         mov     %al,($arg1)
206         sub     \$1,$arg2
207         lea     1($arg1),$arg1
208         jnz     .Little
209 .Lret:
210         ret
211 .align  16
212 .Lot:
213         test    \$7,$arg1
214         jz      .Laligned
215         mov     %al,($arg1)
216         lea     -1($arg2),$arg2
217         lea     1($arg1),$arg1
218         jmp     .Lot
219 .Laligned:
220         mov     %rax,($arg1)
221         lea     -8($arg2),$arg2
222         test    \$-8,$arg2
223         lea     8($arg1),$arg1
224         jnz     .Laligned
225         cmp     \$0,$arg2
226         jne     .Little
227         ret
228 .size   OPENSSL_cleanse,.-OPENSSL_cleanse
229
230 .globl  CRYPTO_memcmp
231 .type   CRYPTO_memcmp,\@abi-omnipotent
232 .align  16
233 CRYPTO_memcmp:
234         xor     %rax,%rax
235         xor     %r10,%r10
236         cmp     \$0,$arg3
237         je      .Lno_data
238 .Loop_cmp:
239         mov     ($arg1),%r10b
240         lea     1($arg1),$arg1
241         xor     ($arg2),%r10b
242         lea     1($arg2),$arg2
243         or      %r10b,%al
244         dec     $arg3
245         jnz     .Loop_cmp
246         neg     %rax
247         shr     \$63,%rax
248 .Lno_data:
249         ret
250 .size   CRYPTO_memcmp,.-CRYPTO_memcmp
251 ___
252
253 print<<___ if (!$win64);
254 .globl  OPENSSL_wipe_cpu
255 .type   OPENSSL_wipe_cpu,\@abi-omnipotent
256 .align  16
257 OPENSSL_wipe_cpu:
258         pxor    %xmm0,%xmm0
259         pxor    %xmm1,%xmm1
260         pxor    %xmm2,%xmm2
261         pxor    %xmm3,%xmm3
262         pxor    %xmm4,%xmm4
263         pxor    %xmm5,%xmm5
264         pxor    %xmm6,%xmm6
265         pxor    %xmm7,%xmm7
266         pxor    %xmm8,%xmm8
267         pxor    %xmm9,%xmm9
268         pxor    %xmm10,%xmm10
269         pxor    %xmm11,%xmm11
270         pxor    %xmm12,%xmm12
271         pxor    %xmm13,%xmm13
272         pxor    %xmm14,%xmm14
273         pxor    %xmm15,%xmm15
274         xorq    %rcx,%rcx
275         xorq    %rdx,%rdx
276         xorq    %rsi,%rsi
277         xorq    %rdi,%rdi
278         xorq    %r8,%r8
279         xorq    %r9,%r9
280         xorq    %r10,%r10
281         xorq    %r11,%r11
282         leaq    8(%rsp),%rax
283         ret
284 .size   OPENSSL_wipe_cpu,.-OPENSSL_wipe_cpu
285 ___
286 print<<___ if ($win64);
287 .globl  OPENSSL_wipe_cpu
288 .type   OPENSSL_wipe_cpu,\@abi-omnipotent
289 .align  16
290 OPENSSL_wipe_cpu:
291         pxor    %xmm0,%xmm0
292         pxor    %xmm1,%xmm1
293         pxor    %xmm2,%xmm2
294         pxor    %xmm3,%xmm3
295         pxor    %xmm4,%xmm4
296         pxor    %xmm5,%xmm5
297         xorq    %rcx,%rcx
298         xorq    %rdx,%rdx
299         xorq    %r8,%r8
300         xorq    %r9,%r9
301         xorq    %r10,%r10
302         xorq    %r11,%r11
303         leaq    8(%rsp),%rax
304         ret
305 .size   OPENSSL_wipe_cpu,.-OPENSSL_wipe_cpu
306 ___
307 {
308 my $out="%r10";
309 my $cnt="%rcx";
310 my $max="%r11";
311 my $lasttick="%r8d";
312 my $lastdiff="%r9d";
313 my $redzone=win64?8:-8;
314
315 print<<___;
316 .globl  OPENSSL_instrument_bus
317 .type   OPENSSL_instrument_bus,\@abi-omnipotent
318 .align  16
319 OPENSSL_instrument_bus:
320         mov     $arg1,$out      # tribute to Win64
321         mov     $arg2,$cnt
322         mov     $arg2,$max
323
324         rdtsc                   # collect 1st tick
325         mov     %eax,$lasttick  # lasttick = tick
326         mov     \$0,$lastdiff   # lastdiff = 0
327         clflush ($out)
328         .byte   0xf0            # lock
329         add     $lastdiff,($out)
330         jmp     .Loop
331 .align  16
332 .Loop:  rdtsc
333         mov     %eax,%edx
334         sub     $lasttick,%eax
335         mov     %edx,$lasttick
336         mov     %eax,$lastdiff
337         clflush ($out)
338         .byte   0xf0            # lock
339         add     %eax,($out)
340         lea     4($out),$out
341         sub     \$1,$cnt
342         jnz     .Loop
343
344         mov     $max,%rax
345         ret
346 .size   OPENSSL_instrument_bus,.-OPENSSL_instrument_bus
347
348 .globl  OPENSSL_instrument_bus2
349 .type   OPENSSL_instrument_bus2,\@abi-omnipotent
350 .align  16
351 OPENSSL_instrument_bus2:
352         mov     $arg1,$out      # tribute to Win64
353         mov     $arg2,$cnt
354         mov     $arg3,$max
355         mov     $cnt,$redzone(%rsp)
356
357         rdtsc                   # collect 1st tick
358         mov     %eax,$lasttick  # lasttick = tick
359         mov     \$0,$lastdiff   # lastdiff = 0
360
361         clflush ($out)
362         .byte   0xf0            # lock
363         add     $lastdiff,($out)
364
365         rdtsc                   # collect 1st diff
366         mov     %eax,%edx
367         sub     $lasttick,%eax  # diff
368         mov     %edx,$lasttick  # lasttick = tick
369         mov     %eax,$lastdiff  # lastdiff = diff
370 .Loop2:
371         clflush ($out)
372         .byte   0xf0            # lock
373         add     %eax,($out)     # accumulate diff
374
375         sub     \$1,$max
376         jz      .Ldone2
377
378         rdtsc
379         mov     %eax,%edx
380         sub     $lasttick,%eax  # diff
381         mov     %edx,$lasttick  # lasttick = tick
382         cmp     $lastdiff,%eax
383         mov     %eax,$lastdiff  # lastdiff = diff
384         mov     \$0,%edx
385         setne   %dl
386         sub     %rdx,$cnt       # conditional --$cnt
387         lea     ($out,%rdx,4),$out      # conditional ++$out
388         jnz     .Loop2
389
390 .Ldone2:
391         mov     $redzone(%rsp),%rax
392         sub     $cnt,%rax
393         ret
394 .size   OPENSSL_instrument_bus2,.-OPENSSL_instrument_bus2
395 ___
396 }
397
398 sub gen_random {
399 my $rdop = shift;
400 print<<___;
401 .globl  OPENSSL_ia32_${rdop}
402 .type   OPENSSL_ia32_${rdop},\@abi-omnipotent
403 .align  16
404 OPENSSL_ia32_${rdop}:
405         mov     \$8,%ecx
406 .Loop_${rdop}:
407         ${rdop} %rax
408         jc      .Lbreak_${rdop}
409         loop    .Loop_${rdop}
410 .Lbreak_${rdop}:
411         cmp     \$0,%rax
412         cmove   %rcx,%rax
413         ret
414 .size   OPENSSL_ia32_${rdop},.-OPENSSL_ia32_${rdop}
415
416 .globl  OPENSSL_ia32_${rdop}_bytes
417 .type   OPENSSL_ia32_${rdop}_bytes,\@abi-omnipotent
418 .align  16
419 OPENSSL_ia32_${rdop}_bytes:
420         xor     %rax, %rax      # return value
421         cmp     \$0,$arg2
422         je      .Ldone_${rdop}_bytes
423
424         mov     \$8,%r11
425 .Loop_${rdop}_bytes:
426         ${rdop} %r10
427         jc      .Lbreak_${rdop}_bytes
428         dec     %r11
429         jnz     .Loop_${rdop}_bytes
430         jmp     .Ldone_${rdop}_bytes
431
432 .align  16
433 .Lbreak_${rdop}_bytes:
434         cmp     \$8,$arg2
435         jb      .Ltail_${rdop}_bytes
436         mov     %r10,($arg1)
437         lea     8($arg1),$arg1
438         add     \$8,%rax
439         sub     \$8,$arg2
440         jz      .Ldone_${rdop}_bytes
441         mov     \$8,%r11
442         jmp     .Loop_${rdop}_bytes
443
444 .align  16
445 .Ltail_${rdop}_bytes:
446         mov     %r10b,($arg1)
447         lea     1($arg1),$arg1
448         inc     %rax
449         shr     \$8,%r8
450         dec     $arg2
451         jnz     .Ltail_${rdop}_bytes
452
453 .Ldone_${rdop}_bytes:
454         ret
455 .size   OPENSSL_ia32_${rdop}_bytes,.-OPENSSL_ia32_${rdop}_bytes
456 ___
457 }
458 gen_random("rdrand");
459 gen_random("rdseed");
460
461 close STDOUT;   # flush