Path: blob/a-new-beginning/SharedDependencies/Sources/cryptopp/cpu.cpp
2 views
// cpu.cpp - originally written and placed in the public domain by Wei Dai1// modified by Jeffrey Walton and the community over the years.23#include "pch.h"4#include "config.h"56#ifndef EXCEPTION_EXECUTE_HANDLER7# define EXCEPTION_EXECUTE_HANDLER 18#endif910#ifndef CRYPTOPP_IMPORTS1112#include "cpu.h"13#include "misc.h"14#include "stdcpp.h"1516// For _xgetbv on Microsoft 32-bit and 64-bit Intel platforms17// https://github.com/weidai11/cryptopp/issues/97218#if (CRYPTOPP_MSC_VERSION >= 1600) && (defined(_M_IX86) || defined(_M_X64))19# include <immintrin.h>20#endif2122// For IsProcessorFeaturePresent on Microsoft Arm64 platforms,23// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent24#if defined(_WIN32) && defined(_M_ARM64)25# include <Windows.h>26# include <processthreadsapi.h>27#endif2829#ifdef _AIX30# include <sys/systemcfg.h>31#endif3233#ifdef __linux__34# include <unistd.h>35#endif3637// Capability queries, requires Glibc 2.16, http://lwn.net/Articles/519085/38// CRYPTOPP_GLIBC_VERSION not used because config.h is missing <feature.h>39#if (((__GLIBC__ * 100) + __GLIBC_MINOR__) >= 216)40# define CRYPTOPP_GETAUXV_AVAILABLE 141#endif4243#if CRYPTOPP_GETAUXV_AVAILABLE44# include <sys/auxv.h>45#else46#ifndef AT_HWCAP47# define AT_HWCAP 1648#endif49#ifndef AT_HWCAP250# define AT_HWCAP2 2651#endif52unsigned long int getauxval(unsigned long int) { return 0; }53#endif5455#if defined(__APPLE__)56# include <sys/utsname.h>57# include <sys/sysctl.h>58#endif5960// FreeBSD headers are giving us trouble...61// https://github.com/weidai11/cryptopp/pull/102962#if defined(__FreeBSD__)63# include <sys/auxv.h>64# include <sys/elf_common.h>65#endif6667// The cpu-features header and source file are located in68// "$ANDROID_NDK_ROOT/sources/android/cpufeatures".69// setenv-android.sh will copy the header and source file70// into PWD and the makefile will build it in place.71#if defined(__ANDROID__)72# include "cpu-features.h"73#endif7475#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY76# include <signal.h>77# include <setjmp.h>78#endif7980// Required by Visual Studio 2008 and below and Clang on Windows.81// Use it for all MSVC-compatible compilers.82// XGETBV64 and CPUID64 are in x64dll.asm.83#if defined(_M_X64) && defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)84extern "C" unsigned long long __fastcall XGETBV64(unsigned int);85extern "C" unsigned long long __fastcall CPUID64(unsigned int, unsigned int, unsigned int*);86#endif8788#ifdef CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY89extern "C" {90typedef void (*SigHandler)(int);91}9293extern "C"94{95static jmp_buf s_jmpNoCPUID;96static void SigIllHandler(int)97{98longjmp(s_jmpNoCPUID, 1);99}100}101#endif // CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY102103ANONYMOUS_NAMESPACE_BEGIN104105#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)106107using CryptoPP::word32;108109inline bool IsIntel(const word32 output[4])110{111// This is the "GenuineIntel" string112return (output[1] /*EBX*/ == 0x756e6547) &&113(output[2] /*ECX*/ == 0x6c65746e) &&114(output[3] /*EDX*/ == 0x49656e69);115}116117inline bool IsAMD(const word32 output[4])118{119// This is the "AuthenticAMD" string.120return ((output[1] /*EBX*/ == 0x68747541) &&121(output[2] /*ECX*/ == 0x444D4163) &&122(output[3] /*EDX*/ == 0x69746E65)) ||123// Early K5's can return "AMDisbetter!"124((output[1] /*EBX*/ == 0x69444d41) &&125(output[2] /*ECX*/ == 0x74656273) &&126(output[3] /*EDX*/ == 0x21726574));127}128129inline bool IsHygon(const word32 output[4])130{131// This is the "HygonGenuine" string.132return (output[1] /*EBX*/ == 0x6f677948) &&133(output[2] /*ECX*/ == 0x656e6975) &&134(output[3] /*EDX*/ == 0x6e65476e);135}136137inline bool IsVIA(const word32 output[4])138{139// This is the "CentaurHauls" string.140return ((output[1] /*EBX*/ == 0x746e6543) &&141(output[2] /*ECX*/ == 0x736c7561) &&142(output[3] /*EDX*/ == 0x48727561)) ||143// Some non-PadLock's return "VIA VIA VIA "144((output[1] /*EBX*/ == 0x32414956) &&145(output[2] /*ECX*/ == 0x32414956) &&146(output[3] /*EDX*/ == 0x32414956));147}148149#endif // X86, X32 and X64150151#if defined(__APPLE__)152153// http://stackoverflow.com/questions/45637888/how-to-determine-armv8-features-at-runtime-on-ios154class AppleMachineInfo155{156public:157enum { PowerMac=1, Mac, iPhone, iPod, iPad, AppleTV, AppleWatch };158enum { PowerPC=1, I386, I686, X86_64, ARM32, ARMV8, ARMV82, ARMV83 };159160AppleMachineInfo() : m_device(0), m_version(0), m_arch(0)161{162struct utsname systemInfo;163systemInfo.machine[0] = '\0';164uname(&systemInfo);165166std::string machine(systemInfo.machine);167168std::string::size_type pos = machine.find_first_of("0123456789");169if (pos != std::string::npos)170m_version = std::atoi(machine.substr(pos).c_str());171172if (machine.find("iPhone") != std::string::npos)173{174m_device = iPhone;175if (m_version >= 6) { m_arch = ARMV8; }176else { m_arch = ARM32; }177}178else if (machine.find("iPod") != std::string::npos)179{180m_device = iPod;181if (m_version >= 6) { m_arch = ARMV8; }182else { m_arch = ARM32; }183}184else if (machine.find("iPad") != std::string::npos)185{186m_device = iPad;187if (m_version >= 5) { m_arch = ARMV8; }188else { m_arch = ARM32; }189}190else if (machine.find("PowerMac") != std::string::npos ||191machine.find("Power Macintosh") != std::string::npos)192{193m_device = PowerMac;194m_arch = PowerPC;195}196else if (machine.find("Mac") != std::string::npos ||197machine.find("Macintosh") != std::string::npos)198{199#if defined(__x86_64) || defined(__amd64)200m_device = Mac;201m_arch = X86_64;202#elif defined(__i386)203m_device = Mac;204m_arch = I386;205#elif defined(__i686)206m_device = Mac;207m_arch = I686;208#else209// Should never get here210m_device = Mac;211m_arch = 0;212#endif213}214else if (machine.find("AppleTV") != std::string::npos)215{216m_device = AppleTV;217if (m_version >= 4) { m_arch = ARMV8; }218else { m_arch = ARM32; }219}220else if (machine.find("AppleWatch") != std::string::npos)221{222m_device = AppleWatch;223if (m_version >= 4) { m_arch = ARMV8; }224else { m_arch = ARM32; }225}226else if (machine.find("arm64") != std::string::npos)227{228// M1 machine?229std::string brand;230size_t size = 32;231232// Supply an oversized buffer, and avoid233// an extra call to sysctlbyname.234brand.resize(size);235if (sysctlbyname("machdep.cpu.brand_string", &brand[0], &size, NULL, 0) == 0 && size > 0)236{237if (brand[size-1] == '\0')238size--;239brand.resize(size);240}241242if (brand == "Apple M1")243{244m_device = Mac;245m_arch = ARMV82;246}247else248{249// ???250m_device = 0;251m_arch = ARMV8;252}253}254else255{256CRYPTOPP_ASSERT(0);257}258}259260unsigned int Device() const {261return m_device;262}263264unsigned int Version() const {265return m_version;266}267268unsigned int Arch() const {269return m_arch;270}271272bool IsARM32() const {273return m_arch == ARM32;274}275276bool IsARMv8() const {277return m_arch >= ARMV8;278}279280bool IsARMv82() const {281return m_arch >= ARMV82;282}283284bool IsARMv83() const {285return m_arch >= ARMV83;286}287288private:289unsigned int m_device, m_version, m_arch;290};291292void GetAppleMachineInfo(unsigned int& device, unsigned int& version, unsigned int& arch)293{294#if CRYPTOPP_CXX11_STATIC_INIT295static const AppleMachineInfo info;296#else297using CryptoPP::Singleton;298const AppleMachineInfo& info = Singleton<AppleMachineInfo>().Ref();299#endif300301device = info.Device();302version = info.Version();303arch = info.Arch();304}305306inline bool IsAppleMachineARM32()307{308static unsigned int arch;309if (arch == 0)310{311unsigned int unused;312GetAppleMachineInfo(unused, unused, arch);313}314return arch == AppleMachineInfo::ARM32;315}316317inline bool IsAppleMachineARMv8()318{319static unsigned int arch;320if (arch == 0)321{322unsigned int unused;323GetAppleMachineInfo(unused, unused, arch);324}325return arch >= AppleMachineInfo::ARMV8;326}327328inline bool IsAppleMachineARMv82()329{330static unsigned int arch;331if (arch == 0)332{333unsigned int unused;334GetAppleMachineInfo(unused, unused, arch);335}336return arch >= AppleMachineInfo::ARMV82;337}338339inline bool IsAppleMachineARMv83()340{341static unsigned int arch;342if (arch == 0)343{344unsigned int unused;345GetAppleMachineInfo(unused, unused, arch);346}347return arch >= AppleMachineInfo::ARMV83;348}349350#endif // __APPLE__351352ANONYMOUS_NAMESPACE_END353354NAMESPACE_BEGIN(CryptoPP)355356// *************************** IA-32 CPUs ***************************357358#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)359360bool CRYPTOPP_SECTION_INIT g_x86DetectionDone = false;361bool CRYPTOPP_SECTION_INIT g_hasSSE2 = false;362bool CRYPTOPP_SECTION_INIT g_hasSSSE3 = false;363bool CRYPTOPP_SECTION_INIT g_hasSSE41 = false;364bool CRYPTOPP_SECTION_INIT g_hasSSE42 = false;365bool CRYPTOPP_SECTION_INIT g_hasAESNI = false;366bool CRYPTOPP_SECTION_INIT g_hasCLMUL = false;367bool CRYPTOPP_SECTION_INIT g_hasMOVBE = false;368bool CRYPTOPP_SECTION_INIT g_hasAVX = false;369bool CRYPTOPP_SECTION_INIT g_hasAVX2 = false;370bool CRYPTOPP_SECTION_INIT g_hasADX = false;371bool CRYPTOPP_SECTION_INIT g_hasSHA = false;372bool CRYPTOPP_SECTION_INIT g_hasRDRAND = false;373bool CRYPTOPP_SECTION_INIT g_hasRDSEED = false;374bool CRYPTOPP_SECTION_INIT g_isP4 = false;375bool CRYPTOPP_SECTION_INIT g_hasPadlockRNG = false;376bool CRYPTOPP_SECTION_INIT g_hasPadlockACE = false;377bool CRYPTOPP_SECTION_INIT g_hasPadlockACE2 = false;378bool CRYPTOPP_SECTION_INIT g_hasPadlockPHE = false;379bool CRYPTOPP_SECTION_INIT g_hasPadlockPMM = false;380word32 CRYPTOPP_SECTION_INIT g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;381382// For Solaris 11383extern bool CPU_ProbeSSE2();384385// xcr0 is available when xgetbv is present.386// The intrinsic is broke on GCC 8.1 and earlier. Also see387// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85684.388word64 XGetBV(word32 num)389{390// Explicitly handle CRYPTOPP_DISABLE_ASM case.391// https://github.com/weidai11/cryptopp/issues/1240392#if defined(CRYPTOPP_DISABLE_ASM)393return 0;394395// Required by Visual Studio 2008 and below and Clang on Windows.396// Use it for all MSVC-compatible compilers.397#elif defined(_M_X64) && defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)398399return XGETBV64(num);400401// Required by Visual Studio 2008 and below and Clang on Windows.402// Use it for all MSVC-compatible compilers.403#elif defined(_M_IX86) && defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)404405word32 a=0, d=0;406__asm {407push eax408push edx409push ecx410mov ecx, num411_emit 0x0f412_emit 0x01413_emit 0xd0414mov a, eax415mov d, edx416pop ecx417pop edx418pop eax419}420return (static_cast<word64>(d) << 32) | a;421422// GCC 4.4 and above423#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4))424425word32 a=0, d=0;426__asm__427(428"xgetbv" : "=a"(a), "=d"(d) : "c"(num) : "cc"429);430return (static_cast<word64>(d) << 32) | a;431432// Remainder of GCC and compatibles.433#elif defined(__GNUC__) || defined(__clang__) || defined(__SUNPRO_CC)434435// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71659 and436// http://www.agner.org/optimize/vectorclass/read.php?i=65437word32 a=0, d=0;438__asm__439(440".byte 0x0f, 0x01, 0xd0" "\n\t"441: "=a"(a), "=d"(d) : "c"(num) : "cc"442);443return (static_cast<word64>(d) << 32) | a;444#else445# error "Need an xgetbv function"446#endif447}448449// No inline due to Borland/Embarcadero and Issue 498450// cpu.cpp (131): E2211 Inline assembly not allowed in inline and template functions451bool CpuId(word32 func, word32 subfunc, word32 output[4])452{453// Explicitly handle CRYPTOPP_DISABLE_ASM case.454// https://github.com/weidai11/cryptopp/issues/1240455#if defined(CRYPTOPP_DISABLE_ASM)456output[0] = output[1] = output[2] = output[3] = 0;457return false;458459// Required by Visual Studio 2008 and below and Clang on Windows.460// Use it for all MSVC-compatible compilers.461#elif defined(_M_X64) && defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)462463CPUID64(func, subfunc, output);464return true;465466// Required by Visual Studio 2008 and below and Clang on Windows.467// Use it for all MSVC-compatible compilers.468#elif defined(_M_IX86) && defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)469470__try471{472// Borland/Embarcadero and Issue 500473// Local variables for cpuid output474word32 a, b, c, d;475__asm476{477push ebx478mov eax, func479mov ecx, subfunc480cpuid481mov [a], eax482mov [b], ebx483mov [c], ecx484mov [d], edx485pop ebx486}487output[0] = a;488output[1] = b;489output[2] = c;490output[3] = d;491}492__except (EXCEPTION_EXECUTE_HANDLER)493{494return false;495}496497return true;498499// Linux, Unix, OS X, Solaris, Cygwin, MinGW500#else501502// longjmp and clobber warnings. Volatile is required.503// http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854504volatile bool result = true;505506volatile SigHandler oldHandler = signal(SIGILL, SigIllHandler);507if (oldHandler == SIG_ERR)508return false;509510# ifndef __MINGW32__511volatile sigset_t oldMask;512if (sigprocmask(0, NULLPTR, (sigset_t*)&oldMask) != 0)513{514signal(SIGILL, oldHandler);515return false;516}517# endif518519if (setjmp(s_jmpNoCPUID))520result = false;521else522{523asm volatile524(525// save ebx in case -fPIC is being used526# if CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64527"pushq %%rbx; cpuid; mov %%ebx, %%edi; popq %%rbx"528# else529"push %%ebx; cpuid; mov %%ebx, %%edi; pop %%ebx"530# endif531: "=a" (output[0]), "=D" (output[1]), "=c" (output[2]), "=d" (output[3])532: "a" (func), "c" (subfunc)533: "cc"534);535}536537# ifndef __MINGW32__538sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULLPTR);539# endif540541signal(SIGILL, oldHandler);542return result;543#endif544}545546void DetectX86Features()547{548// Coverity finding CID 171239. Initialize arrays.549// Indexes: EAX=0, EBX=1, ECX=2, EDX=3550word32 cpuid0[4]={0}, cpuid1[4]={0}, cpuid2[4]={0};551552#if defined(CRYPTOPP_DISABLE_ASM)553// Not available554goto done;555#else556if (!CpuId(0, 0, cpuid0))557goto done;558if (!CpuId(1, 0, cpuid1))559goto done;560#endif561562CRYPTOPP_CONSTANT(EAX_REG = 0);563CRYPTOPP_CONSTANT(EBX_REG = 1);564CRYPTOPP_CONSTANT(ECX_REG = 2);565CRYPTOPP_CONSTANT(EDX_REG = 3);566567CRYPTOPP_CONSTANT(MMX_FLAG = (1 << 24)); // EDX568CRYPTOPP_CONSTANT(SSE_FLAG = (1 << 25)); // EDX569CRYPTOPP_CONSTANT(SSE2_FLAG = (1 << 26)); // EDX570571CRYPTOPP_CONSTANT(SSE3_FLAG = (1 << 0)); // ECX572CRYPTOPP_CONSTANT(SSSE3_FLAG = (1 << 9)); // ECX573CRYPTOPP_CONSTANT(SSE41_FLAG = (1 << 19)); // ECX574CRYPTOPP_CONSTANT(SSE42_FLAG = (1 << 20)); // ECX575CRYPTOPP_CONSTANT(MOVBE_FLAG = (1 << 22)); // ECX576CRYPTOPP_CONSTANT(AESNI_FLAG = (1 << 25)); // ECX577CRYPTOPP_CONSTANT(CLMUL_FLAG = (1 << 1)); // ECX578579CRYPTOPP_CONSTANT(XSAVE_FLAG = (1 << 26)); // ECX580CRYPTOPP_CONSTANT(OSXSAVE_FLAG = (1 << 27)); // ECX581582CRYPTOPP_CONSTANT(AVX_FLAG = (3 << 27)); // ECX583CRYPTOPP_CONSTANT(YMM_FLAG = (3 << 1)); // CR0584585// x86_64 machines don't check some flags because SSE2586// is part of the core instruction set architecture587CRYPTOPP_UNUSED(MMX_FLAG); CRYPTOPP_UNUSED(SSE_FLAG);588CRYPTOPP_UNUSED(SSE2_FLAG); CRYPTOPP_UNUSED(SSE3_FLAG);589CRYPTOPP_UNUSED(XSAVE_FLAG);590591#if (CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)592// 64-bit core instruction set includes SSE2. Just check593// the OS enabled SSE2 support using OSXSAVE.594g_hasSSE2 = (cpuid1[ECX_REG] & OSXSAVE_FLAG) != 0;595#else596// Check the processor supports SSE2. Then use OSXSAVE to597// signal OS support for SSE2 to avoid probes.598// Also see http://stackoverflow.com/a/22521619/608639599// and http://github.com/weidai11/cryptopp/issues/511.600if ((cpuid1[EDX_REG] & SSE2_FLAG) == SSE2_FLAG)601g_hasSSE2 = (cpuid1[ECX_REG] & XSAVE_FLAG) != 0 &&602(cpuid1[ECX_REG] & OSXSAVE_FLAG) != 0;603#endif604605// Solaris 11 i86pc does not signal SSE support using606// OSXSAVE. Additionally, Fedora 38 on a 2015 Celeron607// N3700 does not set OSXSAVE. So we need to explicitly608// probe for SSE support on rare occasions. Ugh...609if (g_hasSSE2 == false)610{611g_hasSSE2 = CPU_ProbeSSE2();612if (g_hasSSE2 == false)613goto done;614}615616g_hasSSSE3 = (cpuid1[ECX_REG] & SSSE3_FLAG) != 0;617g_hasSSE41 = (cpuid1[ECX_REG] & SSE41_FLAG) != 0;618g_hasSSE42 = (cpuid1[ECX_REG] & SSE42_FLAG) != 0;619g_hasMOVBE = (cpuid1[ECX_REG] & MOVBE_FLAG) != 0;620g_hasAESNI = (cpuid1[ECX_REG] & AESNI_FLAG) != 0;621g_hasCLMUL = (cpuid1[ECX_REG] & CLMUL_FLAG) != 0;622623// AVX is similar to SSE. Check if AVX is available on the cpu, then624// check if the OS enabled XSAVE/XRESTORE for the extended registers.625// https://software.intel.com/en-us/blogs/2011/04/14/is-avx-enabled626if ((cpuid1[ECX_REG] & AVX_FLAG) == AVX_FLAG)627{628word64 xcr0 = XGetBV(0);629g_hasAVX = (xcr0 & YMM_FLAG) == YMM_FLAG;630}631632if (IsIntel(cpuid0))633{634CRYPTOPP_CONSTANT(RDRAND_FLAG = (1 << 30));635CRYPTOPP_CONSTANT(RDSEED_FLAG = (1 << 18));636CRYPTOPP_CONSTANT( ADX_FLAG = (1 << 19));637CRYPTOPP_CONSTANT( SHA_FLAG = (1 << 29));638CRYPTOPP_CONSTANT( AVX2_FLAG = (1 << 5));639640g_isP4 = ((cpuid1[0] >> 8) & 0xf) == 0xf;641g_cacheLineSize = 8 * GETBYTE(cpuid1[1], 1);642g_hasRDRAND = (cpuid1[ECX_REG] & RDRAND_FLAG) != 0;643644if (cpuid0[EAX_REG] >= 7)645{646if (CpuId(7, 0, cpuid2))647{648g_hasRDSEED = (cpuid2[EBX_REG] & RDSEED_FLAG) != 0;649g_hasADX = (cpuid2[EBX_REG] & ADX_FLAG) != 0;650g_hasSHA = (cpuid2[EBX_REG] & SHA_FLAG) != 0;651g_hasAVX2 = (cpuid2[EBX_REG] & AVX2_FLAG) != 0;652}653}654}655else if (IsAMD(cpuid0) || IsHygon(cpuid0))656{657CRYPTOPP_CONSTANT(RDRAND_FLAG = (1 << 30));658CRYPTOPP_CONSTANT(RDSEED_FLAG = (1 << 18));659CRYPTOPP_CONSTANT( ADX_FLAG = (1 << 19));660CRYPTOPP_CONSTANT( SHA_FLAG = (1 << 29));661CRYPTOPP_CONSTANT( AVX2_FLAG = (1 << 5));662663CpuId(0x80000005, 0, cpuid2);664g_cacheLineSize = GETBYTE(cpuid2[ECX_REG], 0);665g_hasRDRAND = (cpuid1[ECX_REG] & RDRAND_FLAG) != 0;666667if (cpuid0[EAX_REG] >= 7)668{669if (CpuId(7, 0, cpuid2))670{671g_hasRDSEED = (cpuid2[EBX_REG] & RDSEED_FLAG) != 0;672g_hasADX = (cpuid2[EBX_REG] & ADX_FLAG) != 0;673g_hasSHA = (cpuid2[EBX_REG] & SHA_FLAG) != 0;674g_hasAVX2 = (cpuid2[EBX_REG] & AVX2_FLAG) != 0;675}676}677678// Unconditionally disable RDRAND and RDSEED on AMD cpu's with family 15h or 16h.679// See Crypto++ Issue 924, https://github.com/weidai11/cryptopp/issues/924,680// Clear RDRAND CPUID bit on AMD family 15h/16h, https://lore.kernel.org/patchwork/patch/1115413/,681// and AMD CPUID Specification, https://www.amd.com/system/files/TechDocs/25481.pdf682{683CRYPTOPP_CONSTANT(FAMILY_BASE_FLAG = (0x0f << 8));684CRYPTOPP_CONSTANT(FAMILY_EXT_FLAG = (0xff << 20));685686word32 family = (cpuid1[0] & FAMILY_BASE_FLAG) >> 8;687if (family == 0xf)688family += (cpuid1[0] & FAMILY_EXT_FLAG) >> 20;689if (family == 0x15 || family == 0x16)690{691g_hasRDRAND = false;692g_hasRDSEED = false;693}694}695}696else if (IsVIA(cpuid0))697{698// Two bits: available and enabled699CRYPTOPP_CONSTANT( RNG_FLAGS = (0x3 << 2));700CRYPTOPP_CONSTANT( ACE_FLAGS = (0x3 << 6));701CRYPTOPP_CONSTANT(ACE2_FLAGS = (0x3 << 8));702CRYPTOPP_CONSTANT( PHE_FLAGS = (0x3 << 10));703CRYPTOPP_CONSTANT( PMM_FLAGS = (0x3 << 12));704705CpuId(0xC0000000, 0, cpuid2);706word32 extendedFeatures = cpuid2[0];707708if (extendedFeatures >= 0xC0000001)709{710CpuId(0xC0000001, 0, cpuid2);711g_hasPadlockRNG = (cpuid2[EDX_REG] & RNG_FLAGS) != 0;712g_hasPadlockACE = (cpuid2[EDX_REG] & ACE_FLAGS) != 0;713g_hasPadlockACE2 = (cpuid2[EDX_REG] & ACE2_FLAGS) != 0;714g_hasPadlockPHE = (cpuid2[EDX_REG] & PHE_FLAGS) != 0;715g_hasPadlockPMM = (cpuid2[EDX_REG] & PMM_FLAGS) != 0;716}717718if (extendedFeatures >= 0xC0000005)719{720CpuId(0xC0000005, 0, cpuid2);721g_cacheLineSize = GETBYTE(cpuid2[ECX_REG], 0);722}723}724725// Keep AVX2 in sync with OS support for AVX. AVX tests both726// cpu support and OS support, while AVX2 only tests cpu support.727g_hasAVX2 &= g_hasAVX;728729done:730731#if defined(_SC_LEVEL1_DCACHE_LINESIZE)732// Glibc does not implement on some platforms. The runtime returns 0 instead of error.733// https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/posix/sysconf.c734int cacheLineSize = (int)sysconf(_SC_LEVEL1_DCACHE_LINESIZE);735if (g_cacheLineSize == 0 && cacheLineSize > 0)736g_cacheLineSize = cacheLineSize;737#endif738739if (g_cacheLineSize == 0)740g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;741742*const_cast<volatile bool*>(&g_x86DetectionDone) = true;743}744745// *************************** ARM-32, Aarch32 and Aarch64 ***************************746747#elif (CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV8)748749bool CRYPTOPP_SECTION_INIT g_ArmDetectionDone = false;750bool CRYPTOPP_SECTION_INIT g_hasARMv7 = false;751bool CRYPTOPP_SECTION_INIT g_hasNEON = false;752bool CRYPTOPP_SECTION_INIT g_hasPMULL = false;753bool CRYPTOPP_SECTION_INIT g_hasCRC32 = false;754bool CRYPTOPP_SECTION_INIT g_hasAES = false;755bool CRYPTOPP_SECTION_INIT g_hasSHA1 = false;756bool CRYPTOPP_SECTION_INIT g_hasSHA2 = false;757bool CRYPTOPP_SECTION_INIT g_hasSHA512 = false;758bool CRYPTOPP_SECTION_INIT g_hasSHA3 = false;759bool CRYPTOPP_SECTION_INIT g_hasSM3 = false;760bool CRYPTOPP_SECTION_INIT g_hasSM4 = false;761word32 CRYPTOPP_SECTION_INIT g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;762763// ARM does not have an unprivileged equivalent to CPUID on IA-32. We have to764// jump through some hoops to detect features on a wide array of platforms.765// Our strategy is two part. First, attempt to *Query* the OS for a feature,766// like using getauxval on Linux. If that fails, then *Probe* the cpu767// executing an instruction and an observe a SIGILL if unsupported. The probes768// are in source files where compilation options like -march=armv8-a+crc make769// intrinsics available. They are expensive when compared to a standard OS770// feature query. Always perform the feature query first. For Linux see771// http://sourceware.org/ml/libc-help/2017-08/msg00012.html772// Avoid probes on Apple platforms because Apple's signal handling for SIGILLs773// appears broken. We are trying to figure out a way to feature test without774// probes. Also see http://stackoverflow.com/a/11197770/608639 and775// http://gist.github.com/erkanyildiz/390a480f27e86f8cd6ba.776777extern bool CPU_ProbeARMv7();778extern bool CPU_ProbeNEON();779extern bool CPU_ProbeCRC32();780extern bool CPU_ProbeAES();781extern bool CPU_ProbeSHA1();782extern bool CPU_ProbeSHA256();783extern bool CPU_ProbeSHA512();784extern bool CPU_ProbeSHA3();785extern bool CPU_ProbeSM3();786extern bool CPU_ProbeSM4();787extern bool CPU_ProbePMULL();788789// https://github.com/torvalds/linux/blob/master/arch/arm/include/uapi/asm/hwcap.h790// https://github.com/torvalds/linux/blob/master/arch/arm64/include/uapi/asm/hwcap.h791#ifndef HWCAP_ARMv7792# define HWCAP_ARMv7 (1 << 29)793#endif794#ifndef HWCAP_ASIMD795# define HWCAP_ASIMD (1 << 1)796#endif797#ifndef HWCAP_NEON798# define HWCAP_NEON (1 << 12)799#endif800#ifndef HWCAP_CRC32801# define HWCAP_CRC32 (1 << 7)802#endif803#ifndef HWCAP2_CRC32804# define HWCAP2_CRC32 (1 << 4)805#endif806#ifndef HWCAP_PMULL807# define HWCAP_PMULL (1 << 4)808#endif809#ifndef HWCAP2_PMULL810# define HWCAP2_PMULL (1 << 1)811#endif812#ifndef HWCAP_AES813# define HWCAP_AES (1 << 3)814#endif815#ifndef HWCAP2_AES816# define HWCAP2_AES (1 << 0)817#endif818#ifndef HWCAP_SHA1819# define HWCAP_SHA1 (1 << 5)820#endif821#ifndef HWCAP_SHA2822# define HWCAP_SHA2 (1 << 6)823#endif824#ifndef HWCAP2_SHA1825# define HWCAP2_SHA1 (1 << 2)826#endif827#ifndef HWCAP2_SHA2828# define HWCAP2_SHA2 (1 << 3)829#endif830#ifndef HWCAP_SHA3831# define HWCAP_SHA3 (1 << 17)832#endif833#ifndef HWCAP_SM3834# define HWCAP_SM3 (1 << 18)835#endif836#ifndef HWCAP_SM4837# define HWCAP_SM4 (1 << 19)838#endif839#ifndef HWCAP_SHA512840# define HWCAP_SHA512 (1 << 21)841#endif842843inline bool CPU_QueryARMv7()844{845#if defined(__ANDROID__) && defined(__arm__)846if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) &&847((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_ARMv7) != 0))848return true;849#elif defined(__linux__) && defined(__arm__)850if ((getauxval(AT_HWCAP) & HWCAP_ARMv7) != 0 ||851(getauxval(AT_HWCAP) & HWCAP_NEON) != 0)852return true;853#elif defined(__APPLE__) && defined(__arm__)854// Apple hardware is ARMv7 or above.855return true;856#elif defined(_WIN32) && defined(_M_ARM64)857// Windows 10 ARM64 is only supported on Armv8a and above858return true;859#endif860return false;861}862863inline bool CPU_QueryNEON()864{865#if defined(__ANDROID__) && defined(__aarch64__)866if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) &&867((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_ASIMD) != 0))868return true;869#elif defined(__ANDROID__) && defined(__arm__)870if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) &&871((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0))872return true;873#elif defined(__linux__) && defined(__aarch64__)874if ((getauxval(AT_HWCAP) & HWCAP_ASIMD) != 0)875return true;876#elif defined(__linux__) && defined(__aarch32__)877if ((getauxval(AT_HWCAP2) & HWCAP2_ASIMD) != 0)878return true;879#elif defined(__linux__) && defined(__arm__)880if ((getauxval(AT_HWCAP) & HWCAP_NEON) != 0)881return true;882#elif defined(__APPLE__) && defined(__aarch64__)883// Core feature set for Aarch32 and Aarch64.884if (IsAppleMachineARMv8())885return true;886#elif defined(_WIN32) && defined(_M_ARM64)887// Windows 10 ARM64 is only supported on Armv8a and above888if (IsProcessorFeaturePresent(PF_ARM_V8_INSTRUCTIONS_AVAILABLE) != 0)889return true;890#endif891return false;892}893894inline bool CPU_QueryCRC32()895{896#if defined(__ANDROID__) && defined(__aarch64__)897if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) &&898((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_CRC32) != 0))899return true;900#elif defined(__ANDROID__) && defined(__aarch32__)901if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) &&902((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_CRC32) != 0))903return true;904#elif defined(__linux__) && defined(__aarch64__)905if ((getauxval(AT_HWCAP) & HWCAP_CRC32) != 0)906return true;907#elif defined(__linux__) && defined(__aarch32__)908if ((getauxval(AT_HWCAP2) & HWCAP2_CRC32) != 0)909return true;910#elif defined(__APPLE__) && defined(__aarch64__)911// M1 processor912if (IsAppleMachineARMv82())913return true;914#elif defined(_WIN32) && defined(_M_ARM64)915if (IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE) != 0)916return true;917#endif918return false;919}920921inline bool CPU_QueryPMULL()922{923#if defined(__ANDROID__) && defined(__aarch64__)924if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) &&925((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_PMULL) != 0))926return true;927#elif defined(__ANDROID__) && defined(__aarch32__)928if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) &&929((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_PMULL) != 0))930return true;931#elif defined(__linux__) && defined(__aarch64__)932if ((getauxval(AT_HWCAP) & HWCAP_PMULL) != 0)933return true;934#elif defined(__linux__) && defined(__aarch32__)935if ((getauxval(AT_HWCAP2) & HWCAP2_PMULL) != 0)936return true;937#elif defined(__APPLE__) && defined(__aarch64__)938// M1 processor939if (IsAppleMachineARMv82())940return true;941#elif defined(_WIN32) && defined(_M_ARM64)942if (IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) != 0)943return true;944#endif945return false;946}947948inline bool CPU_QueryAES()949{950#if defined(__ANDROID__) && defined(__aarch64__)951if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) &&952((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_AES) != 0))953return true;954#elif defined(__ANDROID__) && defined(__aarch32__)955if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) &&956((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_AES) != 0))957return true;958#elif defined(__linux__) && defined(__aarch64__)959if ((getauxval(AT_HWCAP) & HWCAP_AES) != 0)960return true;961#elif defined(__linux__) && defined(__aarch32__)962if ((getauxval(AT_HWCAP2) & HWCAP2_AES) != 0)963return true;964#elif defined(__APPLE__) && defined(__aarch64__)965// M1 processor966if (IsAppleMachineARMv82())967return true;968#elif defined(_WIN32) && defined(_M_ARM64)969if (IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) != 0)970return true;971#endif972return false;973}974975inline bool CPU_QuerySHA1()976{977#if defined(__ANDROID__) && defined(__aarch64__)978if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) &&979((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_SHA1) != 0))980return true;981#elif defined(__ANDROID__) && defined(__aarch32__)982if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) &&983((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_SHA1) != 0))984return true;985#elif defined(__linux__) && defined(__aarch64__)986if ((getauxval(AT_HWCAP) & HWCAP_SHA1) != 0)987return true;988#elif defined(__linux__) && defined(__aarch32__)989if ((getauxval(AT_HWCAP2) & HWCAP2_SHA1) != 0)990return true;991#elif defined(__APPLE__) && defined(__aarch64__)992// M1 processor993if (IsAppleMachineARMv82())994return true;995#elif defined(_WIN32) && defined(_M_ARM64)996if (IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) != 0)997return true;998#endif999return false;1000}10011002inline bool CPU_QuerySHA256()1003{1004#if defined(__ANDROID__) && defined(__aarch64__)1005if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) &&1006((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_SHA2) != 0))1007return true;1008#elif defined(__ANDROID__) && defined(__aarch32__)1009if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) &&1010((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_SHA2) != 0))1011return true;1012#elif defined(__linux__) && defined(__aarch64__)1013if ((getauxval(AT_HWCAP) & HWCAP_SHA2) != 0)1014return true;1015#elif defined(__linux__) && defined(__aarch32__)1016if ((getauxval(AT_HWCAP2) & HWCAP2_SHA2) != 0)1017return true;1018#elif defined(__APPLE__) && defined(__aarch64__)1019// M1 processor1020if (IsAppleMachineARMv82())1021return true;1022#elif defined(_WIN32) && defined(_M_ARM64)1023if (IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) != 0)1024return true;1025#endif1026return false;1027}10281029// Some ARMv8.2 features are disabled at the moment1030inline bool CPU_QuerySHA3()1031{1032// According to the ARM manual, SHA3 depends upon SHA1 and SHA2.1033// If SHA1 and SHA2 are not present, then SHA3 and SHA512 are1034// not present. Also see Arm A64 Instruction Set Architecture,1035// https://developer.arm.com/documentation/ddi0596/2020-12/1036if (!g_hasSHA1 || !g_hasSHA2) { return false; }10371038#if defined(__ANDROID__) && defined(__aarch64__) && 01039if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) &&1040((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_SHA3) != 0))1041return true;1042#elif defined(__ANDROID__) && defined(__aarch32__) && 01043if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) &&1044((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_SHA3) != 0))1045return true;1046#elif defined(__linux__) && defined(__aarch64__)1047if ((getauxval(AT_HWCAP) & HWCAP_SHA3) != 0)1048return true;1049#elif defined(__linux__) && defined(__aarch32__)1050if ((getauxval(AT_HWCAP2) & HWCAP2_SHA3) != 0)1051return true;1052#elif defined(__APPLE__) && defined(__aarch64__)1053// M1 processor1054if (IsAppleMachineARMv82())1055return true;1056#endif1057return false;1058}10591060// Some ARMv8.2 features are disabled at the moment1061inline bool CPU_QuerySHA512()1062{1063// According to the ARM manual, SHA512 depends upon SHA1 and SHA2.1064// If SHA1 and SHA2 are not present, then SHA3 and SHA512 are1065// not present. Also see Arm A64 Instruction Set Architecture,1066// https://developer.arm.com/documentation/ddi0596/2020-12/1067if (!g_hasSHA1 || !g_hasSHA2) { return false; }10681069#if defined(__ANDROID__) && defined(__aarch64__) && 01070if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) &&1071((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_SHA512) != 0))1072return true;1073#elif defined(__ANDROID__) && defined(__aarch32__) && 01074if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) &&1075((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_SHA512) != 0))1076return true;1077#elif defined(__linux__) && defined(__aarch64__)1078if ((getauxval(AT_HWCAP) & HWCAP_SHA512) != 0)1079return true;1080#elif defined(__linux__) && defined(__aarch32__)1081if ((getauxval(AT_HWCAP2) & HWCAP2_SHA512) != 0)1082return true;1083#elif defined(__APPLE__) && defined(__aarch64__)1084// M1 processor1085if (IsAppleMachineARMv82())1086return true;1087#endif1088return false;1089}10901091// Some ARMv8.2 features are disabled at the moment1092inline bool CPU_QuerySM3()1093{1094#if defined(__ANDROID__) && defined(__aarch64__) && 01095if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) &&1096((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_SM3) != 0))1097return true;1098#elif defined(__ANDROID__) && defined(__aarch32__) && 01099if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) &&1100((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_SM3) != 0))1101return true;1102#elif defined(__linux__) && defined(__aarch64__)1103if ((getauxval(AT_HWCAP) & HWCAP_SM3) != 0)1104return true;1105#elif defined(__linux__) && defined(__aarch32__)1106if ((getauxval(AT_HWCAP2) & HWCAP2_SM3) != 0)1107return true;1108#elif defined(__APPLE__) && defined(__aarch64__) && 01109// No Apple support yet.1110#endif1111return false;1112}11131114// Some ARMv8.2 features are disabled at the moment1115inline bool CPU_QuerySM4()1116{1117#if defined(__ANDROID__) && defined(__aarch64__) && 01118if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM64) != 0) &&1119((android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_SM4) != 0))1120return true;1121#elif defined(__ANDROID__) && defined(__aarch32__) && 01122if (((android_getCpuFamily() & ANDROID_CPU_FAMILY_ARM) != 0) &&1123((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_SM4) != 0))1124return true;1125#elif defined(__linux__) && defined(__aarch64__)1126if ((getauxval(AT_HWCAP) & HWCAP_SM4) != 0)1127return true;1128#elif defined(__linux__) && defined(__aarch32__)1129if ((getauxval(AT_HWCAP2) & HWCAP2_SM4) != 0)1130return true;1131#elif defined(__APPLE__) && defined(__aarch64__) && 01132// No Apple support yet.1133#endif1134return false;1135}11361137void DetectArmFeatures()1138{1139#ifndef CRYPTOPP_DISABLE_ASM11401141// The CPU_ProbeXXX's return false for OSes which1142// can't tolerate SIGILL-based probes1143g_hasARMv7 = CPU_QueryARMv7() || CPU_ProbeARMv7();1144g_hasNEON = CPU_QueryNEON() || CPU_ProbeNEON();1145g_hasCRC32 = CPU_QueryCRC32() || CPU_ProbeCRC32();1146g_hasPMULL = CPU_QueryPMULL() || CPU_ProbePMULL();1147g_hasAES = CPU_QueryAES() || CPU_ProbeAES();1148g_hasSHA1 = CPU_QuerySHA1() || CPU_ProbeSHA1();1149g_hasSHA2 = CPU_QuerySHA256() || CPU_ProbeSHA256();1150g_hasSHA512 = CPU_QuerySHA512(); // || CPU_ProbeSHA512();1151g_hasSHA3 = CPU_QuerySHA3(); // || CPU_ProbeSHA3();1152g_hasSM3 = CPU_QuerySM3(); // || CPU_ProbeSM3();1153g_hasSM4 = CPU_QuerySM4(); // || CPU_ProbeSM4();11541155#if defined(_SC_LEVEL1_DCACHE_LINESIZE)1156// Glibc does not implement on some platforms. The runtime returns 0 instead of error.1157// https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/posix/sysconf.c1158int cacheLineSize = (int)sysconf(_SC_LEVEL1_DCACHE_LINESIZE);1159if (cacheLineSize > 0)1160g_cacheLineSize = cacheLineSize;1161#endif11621163if (g_cacheLineSize == 0)1164g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;11651166#endif // CRYPTOPP_DISABLE_ASM11671168*const_cast<volatile bool*>(&g_ArmDetectionDone) = true;1169}11701171// *************************** PowerPC and PowerPC64 ***************************11721173#elif (CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64)11741175bool CRYPTOPP_SECTION_INIT g_PowerPcDetectionDone = false;1176bool CRYPTOPP_SECTION_INIT g_hasAltivec = false;1177bool CRYPTOPP_SECTION_INIT g_hasPower7 = false;1178bool CRYPTOPP_SECTION_INIT g_hasPower8 = false;1179bool CRYPTOPP_SECTION_INIT g_hasPower9 = false;1180bool CRYPTOPP_SECTION_INIT g_hasAES = false;1181bool CRYPTOPP_SECTION_INIT g_hasPMULL = false;1182bool CRYPTOPP_SECTION_INIT g_hasSHA256 = false;1183bool CRYPTOPP_SECTION_INIT g_hasSHA512 = false;1184bool CRYPTOPP_SECTION_INIT g_hasDARN = false;1185word32 CRYPTOPP_SECTION_INIT g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;11861187extern bool CPU_ProbeAltivec();1188extern bool CPU_ProbePower7();1189extern bool CPU_ProbePower8();1190extern bool CPU_ProbePower9();1191extern bool CPU_ProbeAES();1192extern bool CPU_ProbePMULL();1193extern bool CPU_ProbeSHA256();1194extern bool CPU_ProbeSHA512();1195extern bool CPU_ProbeDARN();11961197// AIX defines. We used to just call __power_7_andup()1198// and friends but at Power9, too many compilers were1199// missing __power_9_andup(). Instead we switched to1200// a pattern similar to OpenSSL caps testing.1201#ifndef __power_6_andup1202# define __power_6_andup() __power_set(0xffffffffU<<14)1203#endif1204#ifndef __power_7_andup1205# define __power_7_andup() __power_set(0xffffffffU<<15)1206#endif1207#ifndef __power_8_andup1208# define __power_8_andup() __power_set(0xffffffffU<<16)1209#endif1210#ifndef __power_9_andup1211# define __power_9_andup() __power_set(0xffffffffU<<17)1212#endif12131214// AIX first supported Altivec at Power6, though it1215// was available much earlier for other vendors.1216inline bool CPU_QueryAltivec()1217{1218#if defined(__linux__) && defined(PPC_FEATURE_HAS_ALTIVEC)1219if ((getauxval(AT_HWCAP) & PPC_FEATURE_HAS_ALTIVEC) != 0)1220return true;1221#elif defined(_AIX)1222if (__power_6_andup() != 0)1223return true;1224#elif defined(__APPLE__) && defined(__POWERPC__)1225unsigned int unused, arch;1226GetAppleMachineInfo(unused, unused, arch);1227return arch == AppleMachineInfo::PowerMac;1228#elif defined(__FreeBSD__) && defined(PPC_FEATURE_HAS_ALTIVEC)1229unsigned long cpufeatures;1230if (elf_aux_info(AT_HWCAP, &cpufeatures, sizeof(cpufeatures)) == 0)1231if ((cpufeatures & PPC_FEATURE_HAS_ALTIVEC) != 0)1232return true;1233#endif1234return false;1235}12361237inline bool CPU_QueryPower7()1238{1239// Power7 and ISA 2.061240#if defined(__linux__) && defined(PPC_FEATURE_ARCH_2_06)1241if ((getauxval(AT_HWCAP) & PPC_FEATURE_ARCH_2_06) != 0)1242return true;1243#elif defined(_AIX)1244if (__power_7_andup() != 0)1245return true;1246#elif defined(__FreeBSD__) && defined(PPC_FEATURE_ARCH_2_06)1247unsigned long cpufeatures;1248if (elf_aux_info(AT_HWCAP, &cpufeatures, sizeof(cpufeatures)) == 0)1249if ((cpufeatures & PPC_FEATURE_ARCH_2_06) != 0)1250return true;1251#endif1252return false;1253}12541255inline bool CPU_QueryPower8()1256{1257// Power8 and ISA 2.07 provide in-core crypto.1258#if defined(__linux__) && defined(PPC_FEATURE2_ARCH_2_07)1259if ((getauxval(AT_HWCAP2) & PPC_FEATURE2_ARCH_2_07) != 0)1260return true;1261#elif defined(_AIX)1262if (__power_8_andup() != 0)1263return true;1264#elif defined(__FreeBSD__) && defined(PPC_FEATURE2_ARCH_2_07)1265unsigned long cpufeatures;1266if (elf_aux_info(AT_HWCAP, &cpufeatures, sizeof(cpufeatures)) == 0)1267if ((cpufeatures & PPC_FEATURE_ARCH_2_07) != 0)1268return true;1269#endif1270return false;1271}12721273inline bool CPU_QueryPower9()1274{1275// Power9 and ISA 3.0.1276#if defined(__linux__) && defined(PPC_FEATURE2_ARCH_3_00)1277if ((getauxval(AT_HWCAP2) & PPC_FEATURE2_ARCH_3_00) != 0)1278return true;1279#elif defined(_AIX)1280if (__power_9_andup() != 0)1281return true;1282#elif defined(__FreeBSD__) && defined(PPC_FEATURE2_ARCH_3_00)1283unsigned long cpufeatures;1284if (elf_aux_info(AT_HWCAP, &cpufeatures, sizeof(cpufeatures)) == 0)1285if ((cpufeatures & PPC_FEATURE_ARCH2_3_00) != 0)1286return true;1287#endif1288return false;1289}12901291inline bool CPU_QueryAES()1292{1293// Power8 and ISA 2.07 provide in-core crypto. Glibc1294// 2.24 or higher is required for PPC_FEATURE2_VEC_CRYPTO.1295#if defined(__linux__) && defined(PPC_FEATURE2_VEC_CRYPTO)1296if ((getauxval(AT_HWCAP2) & PPC_FEATURE2_VEC_CRYPTO) != 0)1297return true;1298#elif defined(_AIX)1299if (__power_8_andup() != 0)1300return true;1301#elif defined(__FreeBSD__) && defined(PPC_FEATURE2_HAS_VEC_CRYPTO)1302unsigned long cpufeatures;1303if (elf_aux_info(AT_HWCAP2, &cpufeatures, sizeof(cpufeatures)) == 0)1304if ((cpufeatures & PPC_FEATURE2_HAS_VEC_CRYPTO != 0)1305return true;1306#endif1307return false;1308}13091310inline bool CPU_QueryPMULL()1311{1312// Power8 and ISA 2.07 provide in-core crypto. Glibc1313// 2.24 or higher is required for PPC_FEATURE2_VEC_CRYPTO.1314#if defined(__linux__) && defined(PPC_FEATURE2_VEC_CRYPTO)1315if ((getauxval(AT_HWCAP2) & PPC_FEATURE2_VEC_CRYPTO) != 0)1316return true;1317#elif defined(_AIX)1318if (__power_8_andup() != 0)1319return true;1320#elif defined(__FreeBSD__) && defined(PPC_FEATURE2_HAS_VEC_CRYPTO)1321unsigned long cpufeatures;1322if (elf_aux_info(AT_HWCAP2, &cpufeatures, sizeof(cpufeatures)) == 0)1323if ((cpufeatures & PPC_FEATURE2_HAS_VEC_CRYPTO != 0)1324return true;1325#endif1326return false;1327}13281329inline bool CPU_QuerySHA256()1330{1331// Power8 and ISA 2.07 provide in-core crypto. Glibc1332// 2.24 or higher is required for PPC_FEATURE2_VEC_CRYPTO.1333#if defined(__linux__) && defined(PPC_FEATURE2_VEC_CRYPTO)1334if ((getauxval(AT_HWCAP2) & PPC_FEATURE2_VEC_CRYPTO) != 0)1335return true;1336#elif defined(_AIX)1337if (__power_8_andup() != 0)1338return true;1339#elif defined(__FreeBSD__) && defined(PPC_FEATURE2_HAS_VEC_CRYPTO)1340unsigned long cpufeatures;1341if (elf_aux_info(AT_HWCAP2, &cpufeatures, sizeof(cpufeatures)) == 0)1342if ((cpufeatures & PPC_FEATURE2_HAS_VEC_CRYPTO != 0)1343return true;1344#endif1345return false;1346}1347inline bool CPU_QuerySHA512()1348{1349// Power8 and ISA 2.07 provide in-core crypto. Glibc1350// 2.24 or higher is required for PPC_FEATURE2_VEC_CRYPTO.1351#if defined(__linux__) && defined(PPC_FEATURE2_VEC_CRYPTO)1352if ((getauxval(AT_HWCAP2) & PPC_FEATURE2_VEC_CRYPTO) != 0)1353return true;1354#elif defined(_AIX)1355if (__power_8_andup() != 0)1356return true;1357#elif defined(__FreeBSD__) && defined(PPC_FEATURE2_HAS_VEC_CRYPTO)1358unsigned long cpufeatures;1359if (elf_aux_info(AT_HWCAP2, &cpufeatures, sizeof(cpufeatures)) == 0)1360if ((cpufeatures & PPC_FEATURE2_HAS_VEC_CRYPTO != 0)1361return true;1362#endif1363return false;1364}13651366// Power9 random number generator1367inline bool CPU_QueryDARN()1368{1369// Power9 and ISA 3.0 provide DARN. It looks like1370// Glibc offers PPC_FEATURE2_DARN.1371#if defined(__linux__) && defined(PPC_FEATURE2_ARCH_3_00)1372if ((getauxval(AT_HWCAP2) & PPC_FEATURE2_ARCH_3_00) != 0)1373return true;1374#elif defined(_AIX)1375if (__power_9_andup() != 0)1376return true;1377#elif defined(__FreeBSD__) && defined(PPC_FEATURE2_ARCH_3_00)1378unsigned long cpufeatures;1379if (elf_aux_info(AT_HWCAP2, &cpufeatures, sizeof(cpufeatures)) == 0)1380if ((cpufeatures & PPC_FEATURE2_ARCH_3_00) != 0)1381return true;1382#endif1383return false;1384}13851386void DetectPowerPcFeatures()1387{1388// GCC 10 is giving us trouble in CPU_ProbePower9() and CPU_ProbeDARN().1389// GCC is generating POWER9 instructions on POWER8 for ppc_power9.cpp.1390// The compiler idiots did not think through the consequences of1391// requiring us to use -mcpu=power9 to unlock the ISA. Epic fail.1392// https://github.com/weidai11/cryptopp/issues/98613931394#ifndef CRYPTOPP_DISABLE_ASM13951396// The CPU_ProbeXXX's return false for OSes which1397// can't tolerate SIGILL-based probes, like Apple1398g_hasAltivec = CPU_QueryAltivec() || CPU_ProbeAltivec();1399g_hasPower7 = CPU_QueryPower7() || CPU_ProbePower7();1400g_hasPower8 = CPU_QueryPower8() || CPU_ProbePower8();1401g_hasPower9 = CPU_QueryPower9() || CPU_ProbePower9();1402g_hasPMULL = CPU_QueryPMULL() || CPU_ProbePMULL();1403g_hasAES = CPU_QueryAES() || CPU_ProbeAES();1404g_hasSHA256 = CPU_QuerySHA256() || CPU_ProbeSHA256();1405g_hasSHA512 = CPU_QuerySHA512() || CPU_ProbeSHA512();1406g_hasDARN = CPU_QueryDARN() || CPU_ProbeDARN();14071408#if defined(_AIX) && defined(SC_L1C_DLS)1409// /usr/include/sys/systemcfg.h1410int cacheLineSize = getsystemcfg(SC_L1C_DLS);1411if (cacheLineSize > 0)1412g_cacheLineSize = cacheLineSize;1413#elif defined(_SC_LEVEL1_DCACHE_LINESIZE)1414// Glibc does not implement on some platforms. The runtime returns 0 instead of error.1415// https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/posix/sysconf.c1416int cacheLineSize = (int)sysconf(_SC_LEVEL1_DCACHE_LINESIZE);1417if (cacheLineSize > 0)1418g_cacheLineSize = cacheLineSize;1419#endif14201421if (g_cacheLineSize == 0)1422g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;14231424#endif // CRYPTOPP_DISABLE_ASM14251426*const_cast<volatile bool*>(&g_PowerPcDetectionDone) = true;1427}14281429#endif1430NAMESPACE_END14311432// *************************** C++ Static Initialization ***************************14331434ANONYMOUS_NAMESPACE_BEGIN14351436class InitCpu1437{1438public:1439InitCpu()1440{1441#if CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X641442CryptoPP::DetectX86Features();1443#elif CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV81444CryptoPP::DetectArmFeatures();1445#elif CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC641446CryptoPP::DetectPowerPcFeatures();1447#endif1448}1449};14501451// This is not really needed because HasSSE() and friends can dynamically initialize.1452// Everything depends on CPU features so we initialize it once at load time.1453// Dynamic initialization will be used if init priorities are not available.14541455#if HAVE_GCC_INIT_PRIORITY1456const InitCpu s_init __attribute__ ((init_priority (CRYPTOPP_INIT_PRIORITY + 10))) = InitCpu();1457#elif HAVE_MSC_INIT_PRIORITY1458#pragma warning(disable: 4075)1459#pragma init_seg(".CRT$XCU")1460const InitCpu s_init;1461#pragma warning(default: 4075)1462#elif HAVE_XLC_INIT_PRIORITY1463// XLC needs constant, not a define1464#pragma priority(270)1465const InitCpu s_init;1466#else1467const InitCpu s_init;1468#endif14691470ANONYMOUS_NAMESPACE_END14711472#endif // CRYPTOPP_IMPORTS147314741475