X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fx86cpuid.pl;h=1266d7634c152777f98896f4ca89a86c679ee2ea;hp=0513398739f0dc04a2f8e2c2fa514bee31fe62ee;hb=43a0449fe6ce18b750803be8a115a412a7235496;hpb=5fabb88a7816f19090384e45bb8f2a22c7f290fb diff --git a/crypto/x86cpuid.pl b/crypto/x86cpuid.pl index 0513398739..1266d7634c 100644 --- a/crypto/x86cpuid.pl +++ b/crypto/x86cpuid.pl @@ -1,10 +1,20 @@ -#!/usr/bin/env perl +#! /usr/bin/env perl +# Copyright 2004-2016 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the OpenSSL license (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; push(@INC, "${dir}perlasm", "perlasm"); require "x86asm.pl"; -&asm_init($ARGV[0],"x86cpuid"); +$output = pop; +open OUT,">$output"; +*STDOUT=*OUT; + +&asm_init($ARGV[0]); for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); } @@ -19,9 +29,11 @@ for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); } &pushf (); &pop ("eax"); &xor ("ecx","eax"); - &bt ("ecx",21); - &jnc (&label("done")); &xor ("eax","eax"); + &mov ("esi",&wparam(0)); + &mov (&DWP(8,"esi"),"eax"); # clear extended feature flags + &bt ("ecx",21); + &jnc (&label("nocpuid")); &cpuid (); &mov ("edi","eax"); # max value for standard query level @@ -51,7 +63,14 @@ for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); } # AMD specific &mov ("eax",0x80000000); &cpuid (); - &cmp ("eax",0x80000008); + &cmp ("eax",0x80000001); + &jb (&label("intel")); + &mov ("esi","eax"); + &mov ("eax",0x80000001); + &cpuid (); + &or ("ebp","ecx"); + &and ("ebp",1<<11|1); # isolate XOP bit + &cmp ("esi",0x80000008); &jb (&label("intel")); &mov ("eax",0x80000008); @@ -60,52 +79,88 @@ for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); } &inc ("esi"); # number of cores &mov ("eax",1); + &xor ("ecx","ecx"); &cpuid (); &bt ("edx",28); - &jnc (&label("done")); + &jnc (&label("generic")); &shr ("ebx",16); &and ("ebx",0xff); &cmp ("ebx","esi"); - &ja (&label("done")); + &ja (&label("generic")); &and ("edx",0xefffffff); # clear hyper-threading bit - &jmp (&label("done")); - + &jmp (&label("generic")); + &set_label("intel"); &cmp ("edi",4); - &mov ("edi",-1); + &mov ("esi",-1); &jb (&label("nocacheinfo")); &mov ("eax",4); &mov ("ecx",0); # query L1D &cpuid (); - &mov ("edi","eax"); - &shr ("edi",14); - &and ("edi",0xfff); # number of cores -1 per L1D + &mov ("esi","eax"); + &shr ("esi",14); + &and ("esi",0xfff); # number of cores -1 per L1D &set_label("nocacheinfo"); &mov ("eax",1); + &xor ("ecx","ecx"); &cpuid (); + &and ("edx",0xbfefffff); # force reserved bits #20, #30 to 0 &cmp ("ebp",0); - &jne (&label("notP4")); + &jne (&label("notintel")); + &or ("edx",1<<30); # set reserved bit#30 on Intel CPUs &and (&HB("eax"),15); # familiy ID &cmp (&HB("eax"),15); # P4? - &jne (&label("notP4")); - &or ("edx",1<<20); # use reserved bit to engage RC4_CHAR -&set_label("notP4"); + &jne (&label("notintel")); + &or ("edx",1<<20); # set reserved bit#20 to engage RC4_CHAR +&set_label("notintel"); &bt ("edx",28); # test hyper-threading bit - &jnc (&label("done")); + &jnc (&label("generic")); &and ("edx",0xefffffff); - &cmp ("edi",0); - &je (&label("done")); + &cmp ("esi",0); + &je (&label("generic")); &or ("edx",0x10000000); &shr ("ebx",16); &cmp (&LB("ebx"),1); - &ja (&label("done")); + &ja (&label("generic")); &and ("edx",0xefffffff); # clear hyper-threading bit if not + +&set_label("generic"); + &and ("ebp",1<<11); # isolate AMD XOP flag + &and ("ecx",0xfffff7ff); # force 11th bit to 0 + &mov ("esi","edx"); # %ebp:%esi is copy of %ecx:%edx + &or ("ebp","ecx"); # merge AMD XOP flag + + &cmp ("edi",7); + &mov ("edi",&wparam(0)); + &jb (&label("no_extended_info")); + &mov ("eax",7); + &xor ("ecx","ecx"); + &cpuid (); + &mov (&DWP(8,"edi"),"ebx"); # save extended feature flag +&set_label("no_extended_info"); + + &bt ("ebp",27); # check OSXSAVE bit + &jnc (&label("clear_avx")); + &xor ("ecx","ecx"); + &data_byte(0x0f,0x01,0xd0); # xgetbv + &and ("eax",6); + &cmp ("eax",6); + &je (&label("done")); + &cmp ("eax",2); + &je (&label("clear_avx")); +&set_label("clear_xmm"); + &and ("ebp",0xfdfffffd); # clear AESNI and PCLMULQDQ bits + &and ("esi",0xfeffffff); # clear FXSR +&set_label("clear_avx"); + &and ("ebp",0xefffe7ff); # clear AVX, FMA and AMD XOP bits + &and (&DWP(8,"edi"),0xffffffdf); # clear AVX2 &set_label("done"); - &mov ("eax","edx"); - &mov ("edx","ecx"); + &mov ("eax","esi"); + &mov ("edx","ebp"); +&set_label("nocpuid"); &function_end("OPENSSL_ia32_cpuid"); &external_label("OPENSSL_ia32cap_P"); @@ -134,7 +189,7 @@ for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); } &jnz (&label("nohalt")); # not enough privileges &pushf (); - &pop ("eax") + &pop ("eax"); &bt ("eax",9); &jnc (&label("nohalt")); # interrupts are disabled @@ -165,7 +220,7 @@ for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); } &function_begin_B("OPENSSL_far_spin"); &pushf (); - &pop ("eax") + &pop ("eax"); &bt ("eax",9); &jnc (&label("nospin")); # interrupts are disabled @@ -199,8 +254,9 @@ for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); } &bt (&DWP(0,"ecx"),1); &jnc (&label("no_x87")); if ($sse2) { - &bt (&DWP(0,"ecx"),26); - &jnc (&label("no_sse2")); + &and ("ecx",1<<26|1<<24); # check SSE2 and FXSR bits + &cmp ("ecx",1<<26|1<<24); + &jne (&label("no_sse2")); &pxor ("xmm0","xmm0"); &pxor ("xmm1","xmm1"); &pxor ("xmm2","xmm2"); @@ -227,52 +283,13 @@ for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); } &set_label("spin"); &lea ("ebx",&DWP(0,"eax","ecx")); &nop (); - &data_word(0x1ab10ff0); # lock; cmpxchg %ebx,(%edx) # %eax is envolved and is always reloaded + &data_word(0x1ab10ff0); # lock; cmpxchg %ebx,(%edx) # %eax is involved and is always reloaded &jne (&label("spin")); &mov ("eax","ebx"); # OpenSSL expects the new value &pop ("ebx"); &ret (); &function_end_B("OPENSSL_atomic_add"); -# This function can become handy under Win32 in situations when -# we don't know which calling convention, __stdcall or __cdecl(*), -# indirect callee is using. In C it can be deployed as -# -#ifdef OPENSSL_CPUID_OBJ -# type OPENSSL_indirect_call(void *f,...); -# ... -# OPENSSL_indirect_call(func,[up to $max arguments]); -#endif -# -# (*) it's designed to work even for __fastcall if number of -# arguments is 1 or 2! -&function_begin_B("OPENSSL_indirect_call"); - { - my $i,$max=7; # $max has to be chosen as 4*n-1 - # in order to preserve eventual - # stack alignment - &push ("ebp"); - &mov ("ebp","esp"); - &sub ("esp",$max*4); - &mov ("ecx",&DWP(12,"ebp")); - &mov (&DWP(0,"esp"),"ecx"); - &mov ("edx",&DWP(16,"ebp")); - &mov (&DWP(4,"esp"),"edx"); - for($i=2;$i<$max;$i++) - { - # Some copies will be redundant/bogus... - &mov ("eax",&DWP(12+$i*4,"ebp")); - &mov (&DWP(0+$i*4,"esp"),"eax"); - } - &call_ptr (&DWP(8,"ebp"));# make the call... - &mov ("esp","ebp"); # ... and just restore the stack pointer - # without paying attention to what we called, - # (__cdecl *func) or (__stdcall *one). - &pop ("ebp"); - &ret (); - } -&function_end_B("OPENSSL_indirect_call"); - &function_begin_B("OPENSSL_cleanse"); &mov ("edx",&wparam(0)); &mov ("ecx",&wparam(1)); @@ -307,6 +324,31 @@ for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); } &ret (); &function_end_B("OPENSSL_cleanse"); +&function_begin_B("CRYPTO_memcmp"); + &push ("esi"); + &push ("edi"); + &mov ("esi",&wparam(0)); + &mov ("edi",&wparam(1)); + &mov ("ecx",&wparam(2)); + &xor ("eax","eax"); + &xor ("edx","edx"); + &cmp ("ecx",0); + &je (&label("no_data")); +&set_label("loop"); + &mov ("dl",&BP(0,"esi")); + &lea ("esi",&DWP(1,"esi")); + &xor ("dl",&BP(0,"edi")); + &lea ("edi",&DWP(1,"edi")); + &or ("al","dl"); + &dec ("ecx"); + &jnz (&label("loop")); + &neg ("eax"); + &shr ("eax",31); +&set_label("no_data"); + &pop ("edi"); + &pop ("esi"); + &ret (); +&function_end_B("CRYPTO_memcmp"); { my $lasttick = "esi"; my $lastdiff = "ebx"; @@ -331,7 +373,7 @@ my $max = "ebp"; &mov ($lasttick,"eax"); # lasttick = tick &mov ($lastdiff,0); # lastdiff = 0 &clflush(&DWP(0,$out)); - &lock (); + &data_byte(0xf0); # lock &add (&DWP(0,$out),$lastdiff); &jmp (&label("loop")); @@ -342,7 +384,7 @@ my $max = "ebp"; &mov ($lasttick,"edx"); # lasttick = tick &mov ($lastdiff,"eax"); # lastdiff = diff &clflush(&DWP(0,$out)); - &lock (); + &data_byte(0xf0); # lock &add (&DWP(0,$out),"eax"); # accumulate diff &lea ($out,&DWP(4,$out)); # ++$out &sub ($cnt,1); # --$cnt @@ -371,7 +413,7 @@ my $max = "ebp"; &mov ($lastdiff,0); # lastdiff = 0 &clflush(&DWP(0,$out)); - &lock (); + &data_byte(0xf0); # lock &add (&DWP(0,$out),$lastdiff); &rdtsc (); # collect 1st diff @@ -383,7 +425,7 @@ my $max = "ebp"; &set_label("loop2",16); &clflush(&DWP(0,$out)); - &lock (); + &data_byte(0xf0); # lock &add (&DWP(0,$out),"eax"); # accumulate diff &sub ($max,1); @@ -409,6 +451,70 @@ my $max = "ebp"; &function_end("OPENSSL_instrument_bus2"); } +sub gen_random { +my $rdop = shift; +&function_begin_B("OPENSSL_ia32_${rdop}"); + &mov ("ecx",8); +&set_label("loop"); + &${rdop}("eax"); + &jc (&label("break")); + &loop (&label("loop")); +&set_label("break"); + &cmp ("eax",0); + &cmove ("eax","ecx"); + &ret (); +&function_end_B("OPENSSL_ia32_${rdop}"); + +&function_begin_B("OPENSSL_ia32_${rdop}_bytes"); + &push ("edi"); + &push ("ebx"); + &xor ("eax","eax"); # return value + &mov ("edi",&wparam(0)); + &mov ("ebx",&wparam(1)); + + &cmp ("ebx",0); + &je (&label("done")); + + &mov ("ecx",8); +&set_label("loop"); + &${rdop}("edx"); + &jc (&label("break")); + &loop (&label("loop")); + &jmp (&label("done")); + +&set_label("break",16); + &cmp ("ebx",4); + &jb (&label("tail")); + &mov (&DWP(0,"edi"),"edx"); + &lea ("edi",&DWP(4,"edi")); + &add ("eax",4); + &sub ("ebx",4); + &jz (&label("done")); + &mov ("ecx",8); + &jmp (&label("loop")); + +&set_label("tail",16); + &mov (&BP(0,"edi"),"dl"); + &lea ("edi",&DWP(1,"edi")); + &inc ("eax"); + &shr ("edx",8); + &dec ("ebx"); + &jnz (&label("tail")); + +&set_label("done"); + &pop ("ebx"); + &pop ("edi"); + &ret (); +&function_end_B("OPENSSL_ia32_${rdop}_bytes"); +} +&gen_random("rdrand"); +&gen_random("rdseed"); + &initseg("OPENSSL_cpuid_setup"); +&hidden("OPENSSL_cpuid_setup"); +&hidden("OPENSSL_ia32cap_P"); + &asm_finish(); + +close STDOUT;