/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifdef FREEBL_NO_DEPEND #include "stubs.h" #endif #include "blapii.h" #include "mpi.h" #include "secerr.h" #include "prtypes.h" #include "prinit.h" #include "prenv.h" #if defined(_MSC_VER) && !defined(_M_IX86) #include /* for _xgetbv() */ #endif static PRCallOnceType coFreeblInit; /* State variables. */ static PRBool aesni_support_ = PR_FALSE; static PRBool clmul_support_ = PR_FALSE; static PRBool avx_support_ = PR_FALSE; static PRBool ssse3_support_ = PR_FALSE; static PRBool arm_neon_support_ = PR_FALSE; static PRBool arm_aes_support_ = PR_FALSE; static PRBool arm_sha1_support_ = PR_FALSE; static PRBool arm_sha2_support_ = PR_FALSE; static PRBool arm_pmull_support_ = PR_FALSE; #ifdef NSS_X86_OR_X64 /* * Adapted from the example code in "How to detect New Instruction support in * the 4th generation Intel Core processor family" by Max Locktyukhin. * * XGETBV: * Reads an extended control register (XCR) specified by ECX into EDX:EAX. */ static PRBool check_xcr0_ymm() { PRUint32 xcr0; #if defined(_MSC_VER) #if defined(_M_IX86) __asm { mov ecx, 0 xgetbv mov xcr0, eax } #else xcr0 = (PRUint32)_xgetbv(0); /* Requires VS2010 SP1 or later. */ #endif /* _M_IX86 */ #else /* _MSC_VER */ /* Old OSX compilers don't support xgetbv. Use byte form. */ __asm__(".byte 0x0F, 0x01, 0xd0" : "=a"(xcr0) : "c"(0) : "%edx"); #endif /* _MSC_VER */ /* Check if xmm and ymm state are enabled in XCR0. */ return (xcr0 & 6) == 6; } #define ECX_AESNI (1 << 25) #define ECX_CLMUL (1 << 1) #define ECX_XSAVE (1 << 26) #define ECX_OSXSAVE (1 << 27) #define ECX_AVX (1 << 28) #define ECX_SSSE3 (1 << 9) #define AVX_BITS (ECX_XSAVE | ECX_OSXSAVE | ECX_AVX) void CheckX86CPUSupport() { unsigned long eax, ebx, ecx, edx; char *disable_hw_aes = PR_GetEnvSecure("NSS_DISABLE_HW_AES"); char *disable_pclmul = PR_GetEnvSecure("NSS_DISABLE_PCLMUL"); char *disable_avx = PR_GetEnvSecure("NSS_DISABLE_AVX"); char *disable_ssse3 = PR_GetEnvSecure("NSS_DISABLE_SSSE3"); freebl_cpuid(1, &eax, &ebx, &ecx, &edx); aesni_support_ = (PRBool)((ecx & ECX_AESNI) != 0 && disable_hw_aes == NULL); clmul_support_ = (PRBool)((ecx & ECX_CLMUL) != 0 && disable_pclmul == 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; ssse3_support_ = (PRBool)((ecx & ECX_SSSE3) != 0 && disable_ssse3 == NULL); } #endif /* NSS_X86_OR_X64 */ /* clang-format off */ #if (defined(__aarch64__) || defined(__arm__)) && !defined(__ANDROID__) #ifndef __has_include #define __has_include(x) 0 #endif #if (__has_include() || defined(__linux__)) && \ defined(__GNUC__) && __GNUC__ >= 2 && defined(__ELF__) #include extern unsigned long getauxval(unsigned long type) __attribute__((weak)); #else static unsigned long (*getauxval)(unsigned long) = NULL; #define AT_HWCAP2 0 #define AT_HWCAP 0 #endif /* defined(__GNUC__) && __GNUC__ >= 2 && defined(__ELF__)*/ #endif /* (defined(__aarch64__) || defined(__arm__)) && !defined(__ANDROID__) */ /* clang-format on */ #if defined(__aarch64__) && !defined(__ANDROID__) // Defines from hwcap.h in Linux kernel - ARM64 #ifndef HWCAP_AES #define HWCAP_AES (1 << 3) #endif #ifndef HWCAP_PMULL #define HWCAP_PMULL (1 << 4) #endif #ifndef HWCAP_SHA1 #define HWCAP_SHA1 (1 << 5) #endif #ifndef HWCAP_SHA2 #define HWCAP_SHA2 (1 << 6) #endif void CheckARMSupport() { char *disable_arm_neon = PR_GetEnvSecure("NSS_DISABLE_ARM_NEON"); char *disable_hw_aes = PR_GetEnvSecure("NSS_DISABLE_HW_AES"); if (getauxval) { long hwcaps = getauxval(AT_HWCAP); arm_aes_support_ = hwcaps & HWCAP_AES && disable_hw_aes == NULL; arm_pmull_support_ = hwcaps & HWCAP_PMULL; arm_sha1_support_ = hwcaps & HWCAP_SHA1; arm_sha2_support_ = hwcaps & HWCAP_SHA2; } /* aarch64 must support NEON. */ arm_neon_support_ = disable_arm_neon == NULL; } #endif /* defined(__aarch64__) && !defined(__ANDROID__) */ #if defined(__arm__) && !defined(__ANDROID__) // Defines from hwcap.h in Linux kernel - ARM /* * HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP */ #ifndef HWCAP_NEON #define HWCAP_NEON (1 << 12) #endif /* * HWCAP2 flags - for elf_hwcap2 (in kernel) and AT_HWCAP2 */ #ifndef HWCAP2_AES #define HWCAP2_AES (1 << 0) #endif #ifndef HWCAP2_PMULL #define HWCAP2_PMULL (1 << 1) #endif #ifndef HWCAP2_SHA1 #define HWCAP2_SHA1 (1 << 2) #endif #ifndef HWCAP2_SHA2 #define HWCAP2_SHA2 (1 << 3) #endif void CheckARMSupport() { char *disable_arm_neon = PR_GetEnvSecure("NSS_DISABLE_ARM_NEON"); char *disable_hw_aes = PR_GetEnvSecure("NSS_DISABLE_HW_AES"); if (getauxval) { long hwcaps = getauxval(AT_HWCAP2); arm_aes_support_ = hwcaps & HWCAP2_AES && disable_hw_aes == NULL; arm_pmull_support_ = hwcaps & HWCAP2_PMULL; arm_sha1_support_ = hwcaps & HWCAP2_SHA1; arm_sha2_support_ = hwcaps & HWCAP2_SHA2; arm_neon_support_ = hwcaps & HWCAP_NEON && disable_arm_neon == NULL; } } #endif /* defined(__arm__) && !defined(__ANDROID__) */ // Enable when Firefox can use it. // #if defined(__ANDROID__) && (defined(__arm__) || defined(__aarch64__)) // #include // void // CheckARMSupport() // { // char *disable_arm_neon = PR_GetEnvSecure("NSS_DISABLE_ARM_NEON"); // char *disable_hw_aes = PR_GetEnvSecure("NSS_DISABLE_HW_AES"); // AndroidCpuFamily family = android_getCpuFamily(); // uint64_t features = android_getCpuFeatures(); // if (family == ANDROID_CPU_FAMILY_ARM64) { // arm_aes_support_ = features & ANDROID_CPU_ARM64_FEATURE_AES && // disable_hw_aes == NULL; // arm_pmull_support_ = features & ANDROID_CPU_ARM64_FEATURE_PMULL; // arm_sha1_support_ = features & ANDROID_CPU_ARM64_FEATURE_SHA1; // arm_sha2_support_ = features & ANDROID_CPU_ARM64_FEATURE_SHA2; // arm_neon_support_ = disable_arm_neon == NULL; // } // if (family == ANDROID_CPU_FAMILY_ARM) { // arm_aes_support_ = features & ANDROID_CPU_ARM_FEATURE_AES && // disable_hw_aes == NULL; // arm_pmull_support_ = features & ANDROID_CPU_ARM_FEATURE_PMULL; // arm_sha1_support_ = features & ANDROID_CPU_ARM_FEATURE_SHA1; // arm_sha2_support_ = features & ANDROID_CPU_ARM_FEATURE_SHA2; // arm_neon_support_ = hwcaps & ANDROID_CPU_ARM_FEATURE_NEON && // disable_arm_neon == NULL; // } // } // #endif /* defined(__ANDROID__) && (defined(__arm__) || defined(__aarch64__)) */ PRBool aesni_support() { return aesni_support_; } PRBool clmul_support() { return clmul_support_; } PRBool avx_support() { return avx_support_; } PRBool ssse3_support() { return ssse3_support_; } PRBool arm_neon_support() { return arm_neon_support_; } PRBool arm_aes_support() { return arm_aes_support_; } PRBool arm_pmull_support() { return arm_pmull_support_; } PRBool arm_sha1_support() { return arm_sha1_support_; } PRBool arm_sha2_support() { return arm_sha2_support_; } static PRStatus FreeblInit(void) { #ifdef NSS_X86_OR_X64 CheckX86CPUSupport(); #elif (defined(__aarch64__) || defined(__arm__)) && !defined(__ANDROID__) CheckARMSupport(); #endif return PR_SUCCESS; } SECStatus BL_Init() { if (PR_CallOnce(&coFreeblInit, FreeblInit) != PR_SUCCESS) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } RSA_Init(); return SECSuccess; }