diff options
Diffstat (limited to 'security/nss/lib/freebl/blinit.c')
-rw-r--r-- | security/nss/lib/freebl/blinit.c | 160 |
1 files changed, 149 insertions, 11 deletions
diff --git a/security/nss/lib/freebl/blinit.c b/security/nss/lib/freebl/blinit.c index 959109b60..2f2a476d0 100644 --- a/security/nss/lib/freebl/blinit.c +++ b/security/nss/lib/freebl/blinit.c @@ -17,13 +17,25 @@ #include <intrin.h> /* for _xgetbv() */ #endif +#if defined(_WIN64) && defined(__aarch64__) +#include <windows.h> +#endif + +#if defined(DARWIN) +#include <TargetConditionals.h> +#endif + static PRCallOnceType coFreeblInit; /* State variables. */ static PRBool aesni_support_ = PR_FALSE; static PRBool clmul_support_ = PR_FALSE; +static PRBool sha_support_ = PR_FALSE; static PRBool avx_support_ = PR_FALSE; +static PRBool avx2_support_ = PR_FALSE; static PRBool ssse3_support_ = PR_FALSE; +static PRBool sse4_1_support_ = PR_FALSE; +static PRBool sse4_2_support_ = PR_FALSE; static PRBool arm_neon_support_ = PR_FALSE; static PRBool arm_aes_support_ = PR_FALSE; static PRBool arm_sha1_support_ = PR_FALSE; @@ -69,31 +81,57 @@ check_xcr0_ymm() #define ECX_XSAVE (1 << 26) #define ECX_OSXSAVE (1 << 27) #define ECX_AVX (1 << 28) +#define EBX_AVX2 (1 << 5) +#define EBX_BMI1 (1 << 3) +#define EBX_BMI2 (1 << 8) +#define EBX_SHA (1 << 29) +#define ECX_FMA (1 << 12) +#define ECX_MOVBE (1 << 22) #define ECX_SSSE3 (1 << 9) +#define ECX_SSE4_1 (1 << 19) +#define ECX_SSE4_2 (1 << 20) #define AVX_BITS (ECX_XSAVE | ECX_OSXSAVE | ECX_AVX) +#define AVX2_EBX_BITS (EBX_AVX2 | EBX_BMI1 | EBX_BMI2) +#define AVX2_ECX_BITS (ECX_FMA | ECX_MOVBE) void CheckX86CPUSupport() { unsigned long eax, ebx, ecx, edx; + unsigned long eax7, ebx7, ecx7, edx7; char *disable_hw_aes = PR_GetEnvSecure("NSS_DISABLE_HW_AES"); char *disable_pclmul = PR_GetEnvSecure("NSS_DISABLE_PCLMUL"); + char *disable_hw_sha = PR_GetEnvSecure("NSS_DISABLE_HW_SHA"); char *disable_avx = PR_GetEnvSecure("NSS_DISABLE_AVX"); + char *disable_avx2 = PR_GetEnvSecure("NSS_DISABLE_AVX2"); char *disable_ssse3 = PR_GetEnvSecure("NSS_DISABLE_SSSE3"); + char *disable_sse4_1 = PR_GetEnvSecure("NSS_DISABLE_SSE4_1"); + char *disable_sse4_2 = PR_GetEnvSecure("NSS_DISABLE_SSE4_2"); freebl_cpuid(1, &eax, &ebx, &ecx, &edx); + freebl_cpuid(7, &eax7, &ebx7, &ecx7, &edx7); aesni_support_ = (PRBool)((ecx & ECX_AESNI) != 0 && disable_hw_aes == NULL); clmul_support_ = (PRBool)((ecx & ECX_CLMUL) != 0 && disable_pclmul == NULL); + sha_support_ = (PRBool)((ebx7 & EBX_SHA) != 0 && disable_hw_sha == NULL); /* For AVX we check AVX, OSXSAVE, and XSAVE * as well as XMM and YMM state. */ avx_support_ = (PRBool)((ecx & AVX_BITS) == AVX_BITS) && check_xcr0_ymm() && disable_avx == NULL; + /* For AVX2 we check AVX2, BMI1, BMI2, FMA, MOVBE. + * We do not check for AVX above. */ + avx2_support_ = (PRBool)((ebx7 & AVX2_EBX_BITS) == AVX2_EBX_BITS && + (ecx & AVX2_ECX_BITS) == AVX2_ECX_BITS && + disable_avx2 == NULL); ssse3_support_ = (PRBool)((ecx & ECX_SSSE3) != 0 && disable_ssse3 == NULL); + sse4_1_support_ = (PRBool)((ecx & ECX_SSE4_1) != 0 && + disable_sse4_1 == NULL); + sse4_2_support_ = (PRBool)((ecx & ECX_SSE4_2) != 0 && + disable_sse4_2 == NULL); } #endif /* NSS_X86_OR_X64 */ /* clang-format off */ -#if defined(__aarch64__) || defined(__arm__) +#if (defined(__aarch64__) || defined(__arm__)) && !defined(TARGET_OS_IPHONE) #ifndef __has_include #define __has_include(x) 0 #endif @@ -104,10 +142,26 @@ CheckX86CPUSupport() #include <sys/auxv.h> #endif extern unsigned long getauxval(unsigned long type) __attribute__((weak)); -#else +#elif defined(__arm__) || !defined(__OpenBSD__) static unsigned long (*getauxval)(unsigned long) = NULL; #endif /* defined(__GNUC__) && __GNUC__ >= 2 && defined(__ELF__)*/ +#if defined(__FreeBSD__) && !defined(__aarch64__) && __has_include(<sys/auxv.h>) +/* Avoid conflict with static declaration above */ +#define getauxval freebl_getauxval +static unsigned long getauxval(unsigned long type) +{ + /* Only AT_HWCAP* return unsigned long */ + if (type != AT_HWCAP && type != AT_HWCAP2) { + return 0; + } + + unsigned long ret = 0; + elf_aux_info(type, &ret, sizeof(ret)); + return ret; +} +#endif + #ifndef AT_HWCAP2 #define AT_HWCAP2 26 #endif @@ -119,6 +173,8 @@ static unsigned long (*getauxval)(unsigned long) = NULL; /* clang-format on */ #if defined(__aarch64__) + +#if defined(__linux__) // Defines from hwcap.h in Linux kernel - ARM64 #ifndef HWCAP_AES #define HWCAP_AES (1 << 3) @@ -132,22 +188,56 @@ static unsigned long (*getauxval)(unsigned long) = NULL; #ifndef HWCAP_SHA2 #define HWCAP_SHA2 (1 << 6) #endif +#endif /* defined(__linux__) */ + +#if defined(__FreeBSD__) +#include <stdint.h> +#include <machine/armreg.h> +// Support for older version of armreg.h +#ifndef ID_AA64ISAR0_AES_VAL +#define ID_AA64ISAR0_AES_VAL ID_AA64ISAR0_AES +#endif +#ifndef ID_AA64ISAR0_SHA1_VAL +#define ID_AA64ISAR0_SHA1_VAL ID_AA64ISAR0_SHA1 +#endif +#ifndef ID_AA64ISAR0_SHA2_VAL +#define ID_AA64ISAR0_SHA2_VAL ID_AA64ISAR0_SHA2 +#endif +#endif /* defined(__FreeBSD__) */ void CheckARMSupport() { - char *disable_arm_neon = PR_GetEnvSecure("NSS_DISABLE_ARM_NEON"); - char *disable_hw_aes = PR_GetEnvSecure("NSS_DISABLE_HW_AES"); - char *disable_pmull = PR_GetEnvSecure("NSS_DISABLE_PMULL"); +#if defined(_WIN64) + BOOL arm_crypto_support = IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE); + arm_aes_support_ = arm_crypto_support; + arm_pmull_support_ = arm_crypto_support; + arm_sha1_support_ = arm_crypto_support; + arm_sha2_support_ = arm_crypto_support; +#elif defined(__linux__) if (getauxval) { long hwcaps = getauxval(AT_HWCAP); - arm_aes_support_ = hwcaps & HWCAP_AES && disable_hw_aes == NULL; - arm_pmull_support_ = hwcaps & HWCAP_PMULL && disable_pmull == NULL; - arm_sha1_support_ = hwcaps & HWCAP_SHA1; - arm_sha2_support_ = hwcaps & HWCAP_SHA2; + arm_aes_support_ = (hwcaps & HWCAP_AES) == HWCAP_AES; + arm_pmull_support_ = (hwcaps & HWCAP_PMULL) == HWCAP_PMULL; + arm_sha1_support_ = (hwcaps & HWCAP_SHA1) == HWCAP_SHA1; + arm_sha2_support_ = (hwcaps & HWCAP_SHA2) == HWCAP_SHA2; } +#elif defined(__FreeBSD__) + /* qemu-user does not support register access from userspace */ + if (PR_GetEnvSecure("QEMU_EMULATING") == NULL) { + uint64_t isar0 = READ_SPECIALREG(id_aa64isar0_el1); + arm_aes_support_ = ID_AA64ISAR0_AES_VAL(isar0) >= ID_AA64ISAR0_AES_BASE; + arm_pmull_support_ = ID_AA64ISAR0_AES_VAL(isar0) >= ID_AA64ISAR0_AES_PMULL; + arm_sha1_support_ = ID_AA64ISAR0_SHA1_VAL(isar0) >= ID_AA64ISAR0_SHA1_BASE; + arm_sha2_support_ = ID_AA64ISAR0_SHA2_VAL(isar0) >= ID_AA64ISAR0_SHA2_BASE; + } +#endif /* aarch64 must support NEON. */ - arm_neon_support_ = disable_arm_neon == NULL; + arm_neon_support_ = PR_GetEnvSecure("NSS_DISABLE_ARM_NEON") == NULL; + arm_aes_support_ &= PR_GetEnvSecure("NSS_DISABLE_HW_AES") == NULL; + arm_pmull_support_ &= PR_GetEnvSecure("NSS_DISABLE_PMULL") == NULL; + arm_sha1_support_ &= PR_GetEnvSecure("NSS_DISABLE_HW_SHA1") == NULL; + arm_sha2_support_ &= PR_GetEnvSecure("NSS_DISABLE_HW_SHA2") == NULL; } #endif /* defined(__aarch64__) */ @@ -271,6 +361,8 @@ CheckARMSupport() arm_sha2_support_ = hwcaps & HWCAP2_SHA2; } arm_neon_support_ = GetNeonSupport(); + arm_sha1_support_ &= PR_GetEnvSecure("NSS_DISABLE_HW_SHA1") == NULL; + arm_sha2_support_ &= PR_GetEnvSecure("NSS_DISABLE_HW_SHA2") == NULL; } #endif /* defined(__arm__) */ @@ -315,16 +407,36 @@ clmul_support() return clmul_support_; } PRBool +sha_support() +{ + return sha_support_; +} +PRBool avx_support() { return avx_support_; } PRBool +avx2_support() +{ + return avx2_support_; +} +PRBool ssse3_support() { return ssse3_support_; } PRBool +sse4_1_support() +{ + return sse4_1_support_; +} +PRBool +sse4_2_support() +{ + return sse4_2_support_; +} +PRBool arm_neon_support() { return arm_neon_support_; @@ -357,7 +469,18 @@ ppc_crypto_support() #if defined(__powerpc__) +#ifndef __has_include +#define __has_include(x) 0 +#endif + +/* clang-format off */ +#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 12) +#if __has_include(<sys/auxv.h>) #include <sys/auxv.h> +#endif +#elif (defined(__FreeBSD__) && __FreeBSD__ < 12) +#include <sys/sysctl.h> +#endif // Defines from cputable.h in Linux kernel - PPC, letting us build on older kernels #ifndef PPC_FEATURE2_VEC_CRYPTO @@ -369,10 +492,25 @@ CheckPPCSupport() { char *disable_hw_crypto = PR_GetEnvSecure("NSS_DISABLE_PPC_GHASH"); - long hwcaps = getauxval(AT_HWCAP2); + unsigned long hwcaps = 0; +#if defined(__linux__) +#if __has_include(<sys/auxv.h>) + hwcaps = getauxval(AT_HWCAP2); +#endif +#elif defined(__FreeBSD__) +#if __FreeBSD__ >= 12 +#if __has_include(<sys/auxv.h>) + elf_aux_info(AT_HWCAP2, &hwcaps, sizeof(hwcaps)); +#endif +#else + size_t len = sizeof(hwcaps); + sysctlbyname("hw.cpu_features2", &hwcaps, &len, NULL, 0); +#endif +#endif ppc_crypto_support_ = hwcaps & PPC_FEATURE2_VEC_CRYPTO && disable_hw_crypto == NULL; } +/* clang-format on */ #endif /* __powerpc__ */ |