diff options
Diffstat (limited to 'comm/third_party/botan/src/lib/utils/cpuid/cpuid_ppc.cpp')
-rw-r--r-- | comm/third_party/botan/src/lib/utils/cpuid/cpuid_ppc.cpp | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/comm/third_party/botan/src/lib/utils/cpuid/cpuid_ppc.cpp b/comm/third_party/botan/src/lib/utils/cpuid/cpuid_ppc.cpp new file mode 100644 index 0000000000..604b97947c --- /dev/null +++ b/comm/third_party/botan/src/lib/utils/cpuid/cpuid_ppc.cpp @@ -0,0 +1,132 @@ +/* +* Runtime CPU detection for POWER/PowerPC +* (C) 2009,2010,2013,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/cpuid.h> +#include <botan/internal/os_utils.h> + +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + +/* +* On macOS and OpenBSD ppc, use sysctl to detect AltiVec +*/ +#if defined(BOTAN_TARGET_OS_IS_MACOS) + #include <sys/sysctl.h> +#elif defined(BOTAN_TARGET_OS_IS_OPENBSD) + #include <sys/param.h> + #include <sys/sysctl.h> + #include <machine/cpu.h> +#endif + +#endif + +namespace Botan { + +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + +/* +* PowerPC specific block: check for AltiVec using either +* sysctl or by reading processor version number register. +*/ +uint64_t CPUID::CPUID_Data::detect_cpu_features(size_t* cache_line_size) + { + BOTAN_UNUSED(cache_line_size); + +#if defined(BOTAN_TARGET_OS_IS_MACOS) || defined(BOTAN_TARGET_OS_IS_OPENBSD) + // On macOS and OpenBSD, use sysctl + + int sels[2] = { +#if defined(BOTAN_TARGET_OS_IS_OPENBSD) + CTL_MACHDEP, CPU_ALTIVEC +#else + CTL_HW, HW_VECTORUNIT +#endif + }; + + int vector_type = 0; + size_t length = sizeof(vector_type); + int error = ::sysctl(sels, 2, &vector_type, &length, NULL, 0); + + if(error == 0 && vector_type > 0) + return CPUID::CPUID_ALTIVEC_BIT; + +#elif (defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) || defined(BOTAN_TARGET_HAS_ELF_AUX_INFO)) && defined(BOTAN_TARGET_ARCH_IS_PPC64) + + enum PPC_hwcap_bit { + ALTIVEC_bit = (1 << 28), + CRYPTO_bit = (1 << 25), + DARN_bit = (1 << 21), + + ARCH_hwcap_altivec = 16, // AT_HWCAP + ARCH_hwcap_crypto = 26, // AT_HWCAP2 + }; + + uint64_t detected_features = 0; + + const unsigned long hwcap_altivec = OS::get_auxval(PPC_hwcap_bit::ARCH_hwcap_altivec); + if(hwcap_altivec & PPC_hwcap_bit::ALTIVEC_bit) + detected_features |= CPUID::CPUID_ALTIVEC_BIT; + + const unsigned long hwcap_crypto = OS::get_auxval(PPC_hwcap_bit::ARCH_hwcap_crypto); + if(hwcap_crypto & PPC_hwcap_bit::CRYPTO_bit) + detected_features |= CPUID::CPUID_POWER_CRYPTO_BIT; + if(hwcap_crypto & PPC_hwcap_bit::DARN_bit) + detected_features |= CPUID::CPUID_DARN_BIT; + + return detected_features; + +#else + + /* + On PowerPC, MSR 287 is PVR, the Processor Version Number + Normally it is only accessible to ring 0, but Linux and NetBSD + (others, too, maybe?) will trap and emulate it for us. + */ + + int pvr = OS::run_cpu_instruction_probe([]() noexcept -> int { + uint32_t pvr = 0; + asm volatile("mfspr %0, 287" : "=r" (pvr)); + // Top 16 bits suffice to identify the model + return static_cast<int>(pvr >> 16); + }); + + if(pvr > 0) + { + const uint16_t ALTIVEC_PVR[] = { + 0x003E, // IBM POWER6 + 0x003F, // IBM POWER7 + 0x004A, // IBM POWER7p + 0x004B, // IBM POWER8E + 0x004C, // IBM POWER8 NVL + 0x004D, // IBM POWER8 + 0x004E, // IBM POWER9 + 0x000C, // G4-7400 + 0x0039, // G5 970 + 0x003C, // G5 970FX + 0x0044, // G5 970MP + 0x0070, // Cell PPU + 0, // end + }; + + for(size_t i = 0; ALTIVEC_PVR[i]; ++i) + { + if(pvr == ALTIVEC_PVR[i]) + return CPUID::CPUID_ALTIVEC_BIT; + } + + return 0; + } + + // TODO try direct instruction probing + +#endif + + return 0; + } + +#endif + +} |