Add CPUID64 for MSVC missing __cpuidex

This commit is contained in:
Jeffrey Walton 2020-02-07 14:19:46 -05:00
parent 9f0b2e27bb
commit 18b535fb5a
No known key found for this signature in database
GPG Key ID: B36AB348921B1838
3 changed files with 59 additions and 27 deletions

View File

@ -166,17 +166,13 @@
// RDRAND uses byte codes. All we need is x86 ASM for it.
// However tie it to AES-NI since SecureKey was available with it.
#if !defined(CRYPTOPP_DISABLE_RDRAND) && defined(CRYPTOPP_AESNI_AVAILABLE) && \
!(defined(__ANDROID__) || defined(ANDROID)) && \
defined(CRYPTOPP_X86_ASM_AVAILABLE)
#if !defined(CRYPTOPP_DISABLE_RDRAND) && defined(CRYPTOPP_AESNI_AVAILABLE)
#define CRYPTOPP_RDRAND_AVAILABLE 1
#endif
// RDSEED uses byte codes. All we need is x86 ASM for it.
// However tie it to AES-NI since SecureKey was available with it.
#if !defined(CRYPTOPP_DISABLE_RDSEED) && defined(CRYPTOPP_AESNI_AVAILABLE) && \
!(defined(__ANDROID__) || defined(ANDROID)) && \
defined(CRYPTOPP_X86_ASM_AVAILABLE)
#if !defined(CRYPTOPP_DISABLE_RDSEED) && defined(CRYPTOPP_AESNI_AVAILABLE)
#define CRYPTOPP_RDSEED_AVAILABLE 1
#endif
@ -200,6 +196,8 @@
# undef CRYPTOPP_CLMUL_AVAILABLE
# undef CRYPTOPP_AESNI_AVAILABLE
# undef CRYPTOPP_SHANI_AVAILABLE
# undef CRYPTOPP_RDRAND_AVAILABLE
# undef CRYPTOPP_RDSEED_AVAILABLE
# undef CRYPTOPP_AVX_AVAILABLE
# undef CRYPTOPP_AVX2_AVAILABLE
# endif
@ -207,6 +205,8 @@
# undef CRYPTOPP_CLMUL_AVAILABLE
# undef CRYPTOPP_AESNI_AVAILABLE
# undef CRYPTOPP_SHANI_AVAILABLE
# undef CRYPTOPP_RDRAND_AVAILABLE
# undef CRYPTOPP_RDSEED_AVAILABLE
# undef CRYPTOPP_AVX_AVAILABLE
# undef CRYPTOPP_AVX2_AVAILABLE
# endif

32
cpu.cpp
View File

@ -56,9 +56,12 @@ unsigned long int getauxval(unsigned long int) { return 0; }
# include <setjmp.h>
#endif
// Visual Studio 2008 and below is missing _xgetbv. See x64dll.asm for the body.
#if defined(_MSC_VER) && _MSC_VER <= 1500 && defined(_M_X64)
// Visual Studio 2008 and below is missing _xgetbv.
// Visual Studio 2008 and below is missing _cpuidex.
// See x64dll.asm for the bodies.
#if defined(_MSC_VER) && defined(_M_X64)
extern "C" unsigned long long __fastcall XGETBV64(unsigned int);
extern "C" unsigned long long __fastcall CPUID64(unsigned int, unsigned int, unsigned int*);
#endif
ANONYMOUS_NAMESPACE_BEGIN
@ -149,14 +152,11 @@ inline bool CpuId(word32 func, word32 subfunc, word32 output[4])
return true;
}
#elif _MSC_VER >= 1400 && CRYPTOPP_BOOL_X64
#elif defined(_MSC_VER) && _MSC_VER < 1600 && defined(_M_X64)
inline bool CpuId(word32 func, word32 subfunc, word32 output[4])
{
if (subfunc != 0)
return false;
__cpuid((int *)output, func);
CPUID64(func, subfunc, output);
return true;
}
@ -193,12 +193,6 @@ bool CpuId(word32 func, word32 subfunc, word32 output[4])
return false;
}
// func = 0 returns the highest basic function understood in EAX. If the CPU does
// not return non-0, then it is mostly useless. The code below converts basic
// function value to a true/false return value.
if(func == 0)
return output[0] != 0;
return true;
#else
// longjmp and clobber warnings. Volatile is required.
@ -410,9 +404,9 @@ void DetectX86Features()
if (CpuId(7, 0, cpuid2))
{
g_hasRDSEED = (cpuid2[1] /*EBX*/ & RDSEED_FLAG) != 0;
g_hasADX = (cpuid2[1] /*EBX*/ & ADX_FLAG) != 0;
g_hasSHA = (cpuid2[1] /*EBX*/ & SHA_FLAG) != 0;
g_hasAVX2 = (cpuid2[1] /*EBX*/ & AVX2_FLAG) != 0;
g_hasADX = (cpuid2[1] /*EBX*/ & ADX_FLAG) != 0;
g_hasSHA = (cpuid2[1] /*EBX*/ & SHA_FLAG) != 0;
g_hasAVX2 = (cpuid2[1] /*EBX*/ & AVX2_FLAG) != 0;
}
}
}
@ -433,9 +427,9 @@ void DetectX86Features()
if (CpuId(7, 0, cpuid2))
{
g_hasRDSEED = (cpuid2[1] /*EBX*/ & RDSEED_FLAG) != 0;
g_hasADX = (cpuid2[1] /*EBX*/ & ADX_FLAG) != 0;
g_hasSHA = (cpuid2[1] /*EBX*/ & SHA_FLAG) != 0;
g_hasAVX2 = (cpuid2[1] /*EBX*/ & AVX2_FLAG) != 0;
g_hasADX = (cpuid2[1] /*EBX*/ & ADX_FLAG) != 0;
g_hasSHA = (cpuid2[1] /*EBX*/ & SHA_FLAG) != 0;
g_hasAVX2 = (cpuid2[1] /*EBX*/ & AVX2_FLAG) != 0;
}
}

View File

@ -1964,10 +1964,23 @@ pop rsi
ret
SHA256_HashMultipleBlocks_SSE2 ENDP
;; https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention
;; The first four integer arguments are passed in registers.
;; Integer values are passed in left-to-right order in RCX,
;; RDX, R8, and R9, respectively. Arguments five and higher
;; are passed on the stack.
;; The registers RAX, RCX, RDX, R8, R9, R10, R11, XMM0-5,
;; and the upper portions of YMM0-15 and ZMM0-15 are
;; considered volatile and must be considered destroyed on
;; function calls
;; http://www.agner.org/optimize/vectorclass/read.php?i=65
;; word64 Xgetbv(word32 ctrl)
;; ctrl = rcx
ALIGN 8
XGETBV64 PROC
;; First paramter is RCX, and xgetbv expects the CTRL in ECX
;; http://www.agner.org/optimize/vectorclass/read.php?i=65
DB 0fh, 01h, 0d0h
;; xcr = (EDX << 32) | EAX
and rax, 0ffffffffh
@ -1976,5 +1989,30 @@ or rax, rdx
ret
XGETBV64 ENDP
;; word64 CpuId(word32 func, word32 subfunc, word32 output[4])
;; func = rcx
;; subfunc = rdx
;; output = r8
ALIGN 8
CPUID64 PROC
;; must be preserved
push rbx
;; eax = func
mov rax, rcx
;; ecx = subfunc
mov rcx, rdx
cpuid
mov [r8+0], eax
mov [r8+4], ebx
mov [r8+8], ecx
mov [r8+12], edx
;; restore
pop rbx
;; return
mov rax, 1
ret
CPUID64 ENDP
_TEXT ENDS
END