tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

blinit.c (17541B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #ifdef FREEBL_NO_DEPEND
      6 #include "stubs.h"
      7 #endif
      8 
      9 #include "blapii.h"
     10 #include "mpi.h"
     11 #include "secerr.h"
     12 #include "prtypes.h"
     13 #include "prinit.h"
     14 #include "prenv.h"
     15 
     16 #if defined(_MSC_VER) && !defined(_M_IX86)
     17 #include <intrin.h> /* for _xgetbv() */
     18 #endif
     19 
     20 #if defined(_WIN64) && defined(__aarch64__)
     21 #include <windows.h>
     22 #endif
     23 
     24 #if defined(DARWIN)
     25 #include <TargetConditionals.h>
     26 #endif
     27 
     28 static PRCallOnceType coFreeblInit;
     29 
     30 /* State variables. */
     31 static PRBool aesni_support_ = PR_FALSE;
     32 static PRBool clmul_support_ = PR_FALSE;
     33 static PRBool sha_support_ = PR_FALSE;
     34 static PRBool avx_support_ = PR_FALSE;
     35 static PRBool avx2_support_ = PR_FALSE;
     36 static PRBool adx_support_ = PR_FALSE;
     37 static PRBool ssse3_support_ = PR_FALSE;
     38 static PRBool sse4_1_support_ = PR_FALSE;
     39 static PRBool sse4_2_support_ = PR_FALSE;
     40 static PRBool arm_neon_support_ = PR_FALSE;
     41 static PRBool arm_aes_support_ = PR_FALSE;
     42 static PRBool arm_sha1_support_ = PR_FALSE;
     43 static PRBool arm_sha2_support_ = PR_FALSE;
     44 static PRBool arm_pmull_support_ = PR_FALSE;
     45 static PRBool ppc_crypto_support_ = PR_FALSE;
     46 
     47 #ifdef NSS_X86_OR_X64
     48 /*
     49 * Adapted from the example code in "How to detect New Instruction support in
     50 * the 4th generation Intel Core processor family" by Max Locktyukhin.
     51 * https://www.intel.com/content/dam/develop/external/us/en/documents/how-to-detect-new-instruction-support-in-the-4th-generation-intel-core-processor-family.pdf
     52 *
     53 * XGETBV:
     54 *   Reads an extended control register (XCR) specified by ECX into EDX:EAX.
     55 */
     56 static PRBool
     57 check_xcr0_ymm()
     58 {
     59    PRUint32 xcr0;
     60 #if defined(_MSC_VER)
     61 #if defined(_M_IX86)
     62    __asm {
     63        mov ecx, 0
     64        xgetbv
     65        mov xcr0, eax
     66    }
     67 #else
     68    xcr0 = (PRUint32)_xgetbv(0); /* Requires VS2010 SP1 or later. */
     69 #endif /* _M_IX86 */
     70 #else  /* _MSC_VER */
     71    /* Old OSX compilers don't support xgetbv. Use byte form. */
     72    __asm__(".byte 0x0F, 0x01, 0xd0"
     73            : "=a"(xcr0)
     74            : "c"(0)
     75            : "%edx");
     76 #endif /* _MSC_VER */
     77    /* Check if xmm and ymm state are enabled in XCR0. */
     78    return (xcr0 & 6) == 6;
     79 }
     80 
     81 #define ECX_AESNI (1 << 25)
     82 #define ECX_CLMUL (1 << 1)
     83 #define ECX_XSAVE (1 << 26)
     84 #define ECX_OSXSAVE (1 << 27)
     85 #define ECX_AVX (1 << 28)
     86 #define EBX_AVX2 (1 << 5)
     87 #define EBX_ADX (1 << 19)
     88 #define EBX_BMI1 (1 << 3)
     89 #define EBX_BMI2 (1 << 8)
     90 #define EBX_SHA (1 << 29)
     91 #define ECX_FMA (1 << 12)
     92 #define ECX_MOVBE (1 << 22)
     93 #define ECX_SSSE3 (1 << 9)
     94 #define ECX_SSE4_1 (1 << 19)
     95 #define ECX_SSE4_2 (1 << 20)
     96 #define AVX_BITS (ECX_XSAVE | ECX_OSXSAVE | ECX_AVX)
     97 #define AVX2_EBX_BITS (EBX_AVX2 | EBX_BMI1 | EBX_BMI2)
     98 #define AVX2_ECX_BITS (ECX_FMA | ECX_MOVBE)
     99 
    100 void
    101 CheckX86CPUSupport()
    102 {
    103    unsigned long eax, ebx, ecx, edx;
    104    unsigned long eax7, ebx7, ecx7, edx7;
    105    char *disable_hw_aes = PR_GetEnvSecure("NSS_DISABLE_HW_AES");
    106    char *disable_pclmul = PR_GetEnvSecure("NSS_DISABLE_PCLMUL");
    107    char *disable_hw_sha = PR_GetEnvSecure("NSS_DISABLE_HW_SHA");
    108    char *disable_avx = PR_GetEnvSecure("NSS_DISABLE_AVX");
    109    char *disable_avx2 = PR_GetEnvSecure("NSS_DISABLE_AVX2");
    110    char *disable_adx = PR_GetEnvSecure("NSS_DISABLE_ADX");
    111    char *disable_ssse3 = PR_GetEnvSecure("NSS_DISABLE_SSSE3");
    112    char *disable_sse4_1 = PR_GetEnvSecure("NSS_DISABLE_SSE4_1");
    113    char *disable_sse4_2 = PR_GetEnvSecure("NSS_DISABLE_SSE4_2");
    114    freebl_cpuid(1, &eax, &ebx, &ecx, &edx);
    115    freebl_cpuid(7, &eax7, &ebx7, &ecx7, &edx7);
    116    aesni_support_ = (PRBool)((ecx & ECX_AESNI) != 0 && disable_hw_aes == NULL);
    117    clmul_support_ = (PRBool)((ecx & ECX_CLMUL) != 0 && disable_pclmul == NULL);
    118    sha_support_ = (PRBool)((ebx7 & EBX_SHA) != 0 && disable_hw_sha == NULL);
    119    /* For AVX we ensure that:
    120     *  - The AVX, OSXSAVE, and XSAVE bits of ECX from CPUID(EAX=1) are set, and
    121     *  - the SSE and AVX state bits of XCR0 are set (check_xcr0_ymm).
    122     */
    123    avx_support_ = (PRBool)((ecx & AVX_BITS) == AVX_BITS) && check_xcr0_ymm() &&
    124                   disable_avx == NULL;
    125    /* For AVX2 we ensure that:
    126     *  - AVX is supported,
    127     *  - the AVX2, BMI1, and BMI2 bits of EBX from CPUID(EAX=7) are set, and
    128     *  - the FMA, and MOVBE bits of ECX from CPUID(EAX=1) are set.
    129     * We do not check for LZCNT support.
    130     */
    131    avx2_support_ = (PRBool)(avx_support_ == PR_TRUE &&
    132                             (ebx7 & AVX2_EBX_BITS) == AVX2_EBX_BITS &&
    133                             (ecx & AVX2_ECX_BITS) == AVX2_ECX_BITS &&
    134                             disable_avx2 == NULL);
    135    /* CPUID.(EAX=07H, ECX=0H):EBX.ADX[bit 19]=1 indicates
    136    the processor supports ADCX and ADOX instructions.*/
    137    adx_support_ = (PRBool)((ebx7 & EBX_ADX) != 0 && disable_adx == NULL);
    138    ssse3_support_ = (PRBool)((ecx & ECX_SSSE3) != 0 &&
    139                              disable_ssse3 == NULL);
    140    sse4_1_support_ = (PRBool)((ecx & ECX_SSE4_1) != 0 &&
    141                               disable_sse4_1 == NULL);
    142    sse4_2_support_ = (PRBool)((ecx & ECX_SSE4_2) != 0 &&
    143                               disable_sse4_2 == NULL);
    144 }
    145 #endif /* NSS_X86_OR_X64 */
    146 
    147 /* clang-format off */
    148 #if (defined(__aarch64__) || defined(__arm__)) && !defined(TARGET_OS_IPHONE)
    149 #ifndef __has_include
    150 #define __has_include(x) 0
    151 #endif
    152 #if (__has_include(<sys/auxv.h>) || defined(__linux__)) && \
    153    defined(__GNUC__) && __GNUC__ >= 2 && defined(__ELF__)
    154 /* This might be conflict with host compiler */
    155 #if !defined(__ANDROID__)
    156 #include <sys/auxv.h>
    157 #endif
    158 extern unsigned long getauxval(unsigned long type) __attribute__((weak));
    159 #elif defined(__arm__) || (!defined(__OpenBSD__) && !defined(_WIN64))
    160 static unsigned long (*getauxval)(unsigned long) = NULL;
    161 #endif /* defined(__GNUC__) && __GNUC__ >= 2 && defined(__ELF__)*/
    162 
    163 #if defined(__FreeBSD__) && !defined(__aarch64__) && __has_include(<sys/auxv.h>)
    164 /* Avoid conflict with static declaration above */
    165 #define getauxval freebl_getauxval
    166 static unsigned long getauxval(unsigned long type)
    167 {
    168    /* Only AT_HWCAP* return unsigned long */
    169    if (type != AT_HWCAP && type != AT_HWCAP2) {
    170        return 0;
    171    }
    172 
    173    unsigned long ret = 0;
    174    elf_aux_info(type, &ret, sizeof(ret));
    175    return ret;
    176 }
    177 #endif
    178 
    179 #ifndef AT_HWCAP2
    180 #define AT_HWCAP2 26
    181 #endif
    182 #ifndef AT_HWCAP
    183 #define AT_HWCAP 16
    184 #endif
    185 
    186 #endif /* defined(__aarch64__) || defined(__arm__) */
    187 /* clang-format on */
    188 
    189 #if defined(__aarch64__)
    190 
    191 #if defined(__linux__)
    192 // Defines from hwcap.h in Linux kernel - ARM64
    193 #ifndef HWCAP_AES
    194 #define HWCAP_AES (1 << 3)
    195 #endif
    196 #ifndef HWCAP_PMULL
    197 #define HWCAP_PMULL (1 << 4)
    198 #endif
    199 #ifndef HWCAP_SHA1
    200 #define HWCAP_SHA1 (1 << 5)
    201 #endif
    202 #ifndef HWCAP_SHA2
    203 #define HWCAP_SHA2 (1 << 6)
    204 #endif
    205 #endif /* defined(__linux__) */
    206 
    207 #if defined(__FreeBSD__)
    208 #include <stdint.h>
    209 #include <machine/armreg.h>
    210 // Support for older version of armreg.h
    211 #ifndef ID_AA64ISAR0_AES_VAL
    212 #define ID_AA64ISAR0_AES_VAL ID_AA64ISAR0_AES
    213 #endif
    214 #ifndef ID_AA64ISAR0_SHA1_VAL
    215 #define ID_AA64ISAR0_SHA1_VAL ID_AA64ISAR0_SHA1
    216 #endif
    217 #ifndef ID_AA64ISAR0_SHA2_VAL
    218 #define ID_AA64ISAR0_SHA2_VAL ID_AA64ISAR0_SHA2
    219 #endif
    220 #endif /* defined(__FreeBSD__) */
    221 
    222 #if defined(__OpenBSD__)
    223 #include <sys/sysctl.h>
    224 #include <machine/cpu.h>
    225 #include <machine/armreg.h>
    226 #endif /* defined(__OpenBSD__) */
    227 
    228 void
    229 CheckARMSupport()
    230 {
    231 #if defined(_WIN64)
    232    BOOL arm_crypto_support = IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
    233    arm_aes_support_ = arm_crypto_support;
    234    arm_pmull_support_ = arm_crypto_support;
    235    arm_sha1_support_ = arm_crypto_support;
    236    arm_sha2_support_ = arm_crypto_support;
    237 #elif defined(__linux__)
    238    if (getauxval) {
    239        long hwcaps = getauxval(AT_HWCAP);
    240        arm_aes_support_ = (hwcaps & HWCAP_AES) == HWCAP_AES;
    241        arm_pmull_support_ = (hwcaps & HWCAP_PMULL) == HWCAP_PMULL;
    242        arm_sha1_support_ = (hwcaps & HWCAP_SHA1) == HWCAP_SHA1;
    243        arm_sha2_support_ = (hwcaps & HWCAP_SHA2) == HWCAP_SHA2;
    244    }
    245 #elif defined(__FreeBSD__)
    246    /* qemu-user does not support register access from userspace */
    247    if (PR_GetEnvSecure("QEMU_EMULATING") == NULL) {
    248        uint64_t isar0 = READ_SPECIALREG(id_aa64isar0_el1);
    249        arm_aes_support_ = ID_AA64ISAR0_AES_VAL(isar0) >= ID_AA64ISAR0_AES_BASE;
    250        arm_pmull_support_ = ID_AA64ISAR0_AES_VAL(isar0) >= ID_AA64ISAR0_AES_PMULL;
    251        arm_sha1_support_ = ID_AA64ISAR0_SHA1_VAL(isar0) >= ID_AA64ISAR0_SHA1_BASE;
    252        arm_sha2_support_ = ID_AA64ISAR0_SHA2_VAL(isar0) >= ID_AA64ISAR0_SHA2_BASE;
    253    }
    254 #elif defined(__OpenBSD__)
    255    const int isar0_mib[] = { CTL_MACHDEP, CPU_ID_AA64ISAR0 };
    256    uint64_t isar0;
    257    size_t len = sizeof(isar0);
    258    if (sysctl(isar0_mib, 2, &isar0, &len, NULL, 0) < 0)
    259        return;
    260    arm_aes_support_ = ID_AA64ISAR0_AES(isar0) >= ID_AA64ISAR0_AES_BASE;
    261    arm_pmull_support_ = ID_AA64ISAR0_AES(isar0) >= ID_AA64ISAR0_AES_PMULL;
    262    arm_sha1_support_ = ID_AA64ISAR0_SHA1(isar0) >= ID_AA64ISAR0_SHA1_BASE;
    263    arm_sha2_support_ = ID_AA64ISAR0_SHA2(isar0) >= ID_AA64ISAR0_SHA2_BASE;
    264 #elif defined(__ARM_FEATURE_CRYPTO)
    265    /*
    266     * Although no feature detection, default compiler option allows ARM
    267     * Crypto Extension.
    268     */
    269    arm_aes_support_ = PR_TRUE;
    270    arm_pmull_support_ = PR_TRUE;
    271    arm_sha1_support_ = PR_TRUE;
    272    arm_sha2_support_ = PR_TRUE;
    273 #endif
    274    /* aarch64 must support NEON. */
    275    arm_neon_support_ = PR_GetEnvSecure("NSS_DISABLE_ARM_NEON") == NULL;
    276    arm_aes_support_ &= PR_GetEnvSecure("NSS_DISABLE_HW_AES") == NULL;
    277    arm_pmull_support_ &= PR_GetEnvSecure("NSS_DISABLE_PMULL") == NULL;
    278    arm_sha1_support_ &= PR_GetEnvSecure("NSS_DISABLE_HW_SHA1") == NULL;
    279    arm_sha2_support_ &= PR_GetEnvSecure("NSS_DISABLE_HW_SHA2") == NULL;
    280 }
    281 #endif /* defined(__aarch64__) */
    282 
    283 #if defined(__arm__)
    284 // Defines from hwcap.h in Linux kernel - ARM
    285 /*
    286 * HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP
    287 */
    288 #ifndef HWCAP_NEON
    289 #define HWCAP_NEON (1 << 12)
    290 #endif
    291 
    292 /*
    293 * HWCAP2 flags - for elf_hwcap2 (in kernel) and AT_HWCAP2
    294 */
    295 #ifndef HWCAP2_AES
    296 #define HWCAP2_AES (1 << 0)
    297 #endif
    298 #ifndef HWCAP2_PMULL
    299 #define HWCAP2_PMULL (1 << 1)
    300 #endif
    301 #ifndef HWCAP2_SHA1
    302 #define HWCAP2_SHA1 (1 << 2)
    303 #endif
    304 #ifndef HWCAP2_SHA2
    305 #define HWCAP2_SHA2 (1 << 3)
    306 #endif
    307 
    308 PRBool
    309 GetNeonSupport()
    310 {
    311    char *disable_arm_neon = PR_GetEnvSecure("NSS_DISABLE_ARM_NEON");
    312    if (disable_arm_neon) {
    313        return PR_FALSE;
    314    }
    315 #if defined(__ARM_NEON) || defined(__ARM_NEON__)
    316    // Compiler generates NEON instruction as default option.
    317    // If no getauxval, compiler generate NEON instruction by default,
    318    // we should allow NOEN support.
    319    return PR_TRUE;
    320 #elif !defined(__ANDROID__)
    321    // Android's cpu-features.c detects features by the following logic
    322    //
    323    // - Call getauxval(AT_HWCAP)
    324    // - Parse /proc/self/auxv if getauxval is nothing or returns 0
    325    // - Parse /proc/cpuinfo if both cannot detect features
    326    //
    327    // But we don't use it for Android since Android document
    328    // (https://developer.android.com/ndk/guides/cpu-features) says
    329    // one problem with AT_HWCAP sometimes devices (Nexus 4 and emulator)
    330    // are mistaken for IDIV.
    331    if (getauxval) {
    332        return (getauxval(AT_HWCAP) & HWCAP_NEON);
    333    }
    334 #endif /* defined(__ARM_NEON) || defined(__ARM_NEON__) */
    335    return PR_FALSE;
    336 }
    337 
    338 #ifdef __linux__
    339 static long
    340 ReadCPUInfoForHWCAP2()
    341 {
    342    FILE *cpuinfo;
    343    char buf[512];
    344    char *p;
    345    long hwcap2 = 0;
    346 
    347    cpuinfo = fopen("/proc/cpuinfo", "r");
    348    if (!cpuinfo) {
    349        return 0;
    350    }
    351    while (fgets(buf, 511, cpuinfo)) {
    352        if (!memcmp(buf, "Features", 8)) {
    353            p = strstr(buf, " aes");
    354            if (p && (p[4] == ' ' || p[4] == '\n')) {
    355                hwcap2 |= HWCAP2_AES;
    356            }
    357            p = strstr(buf, " sha1");
    358            if (p && (p[5] == ' ' || p[5] == '\n')) {
    359                hwcap2 |= HWCAP2_SHA1;
    360            }
    361            p = strstr(buf, " sha2");
    362            if (p && (p[5] == ' ' || p[5] == '\n')) {
    363                hwcap2 |= HWCAP2_SHA2;
    364            }
    365            p = strstr(buf, " pmull");
    366            if (p && (p[6] == ' ' || p[6] == '\n')) {
    367                hwcap2 |= HWCAP2_PMULL;
    368            }
    369            break;
    370        }
    371    }
    372 
    373    fclose(cpuinfo);
    374    return hwcap2;
    375 }
    376 #endif /* __linux__ */
    377 
    378 void
    379 CheckARMSupport()
    380 {
    381    char *disable_hw_aes = PR_GetEnvSecure("NSS_DISABLE_HW_AES");
    382    if (getauxval) {
    383        // Android's cpu-features.c uses AT_HWCAP2 for newer features.
    384        // AT_HWCAP2 is implemented on newer devices / kernel, so we can trust
    385        // it since cpu-features.c doesn't have workaround / fallback.
    386        // Also, AT_HWCAP2 is supported by glibc 2.18+ on Linux/arm, If
    387        // AT_HWCAP2 isn't supported by glibc or Linux kernel, getauxval will
    388        // returns 0.
    389        long hwcaps = getauxval(AT_HWCAP2);
    390 #ifdef __linux__
    391        if (!hwcaps) {
    392            // Some ARMv8 devices may not implement AT_HWCAP2. So we also
    393            // read /proc/cpuinfo if AT_HWCAP2 is 0.
    394            hwcaps = ReadCPUInfoForHWCAP2();
    395        }
    396 #endif
    397        arm_aes_support_ = hwcaps & HWCAP2_AES && disable_hw_aes == NULL;
    398        arm_pmull_support_ = hwcaps & HWCAP2_PMULL;
    399        arm_sha1_support_ = hwcaps & HWCAP2_SHA1;
    400        arm_sha2_support_ = hwcaps & HWCAP2_SHA2;
    401    }
    402    arm_neon_support_ = GetNeonSupport();
    403    arm_sha1_support_ &= PR_GetEnvSecure("NSS_DISABLE_HW_SHA1") == NULL;
    404    arm_sha2_support_ &= PR_GetEnvSecure("NSS_DISABLE_HW_SHA2") == NULL;
    405 }
    406 #endif /* defined(__arm__) */
    407 
    408 // Enable when Firefox can use it for Android API 16 and 17.
    409 // #if defined(__ANDROID__) && (defined(__arm__) || defined(__aarch64__))
    410 // #include <cpu-features.h>
    411 // void
    412 // CheckARMSupport()
    413 // {
    414 //     char *disable_arm_neon = PR_GetEnvSecure("NSS_DISABLE_ARM_NEON");
    415 //     char *disable_hw_aes = PR_GetEnvSecure("NSS_DISABLE_HW_AES");
    416 //     AndroidCpuFamily family = android_getCpuFamily();
    417 //     uint64_t features = android_getCpuFeatures();
    418 //     if (family == ANDROID_CPU_FAMILY_ARM64) {
    419 //         arm_aes_support_ = features & ANDROID_CPU_ARM64_FEATURE_AES &&
    420 //                            disable_hw_aes == NULL;
    421 //         arm_pmull_support_ = features & ANDROID_CPU_ARM64_FEATURE_PMULL;
    422 //         arm_sha1_support_ = features & ANDROID_CPU_ARM64_FEATURE_SHA1;
    423 //         arm_sha2_support_ = features & ANDROID_CPU_ARM64_FEATURE_SHA2;
    424 //         arm_neon_support_ = disable_arm_neon == NULL;
    425 //     }
    426 //     if (family == ANDROID_CPU_FAMILY_ARM) {
    427 //         arm_aes_support_ = features & ANDROID_CPU_ARM_FEATURE_AES &&
    428 //                            disable_hw_aes == NULL;
    429 //         arm_pmull_support_ = features & ANDROID_CPU_ARM_FEATURE_PMULL;
    430 //         arm_sha1_support_ = features & ANDROID_CPU_ARM_FEATURE_SHA1;
    431 //         arm_sha2_support_ = features & ANDROID_CPU_ARM_FEATURE_SHA2;
    432 //         arm_neon_support_ = hwcaps & ANDROID_CPU_ARM_FEATURE_NEON &&
    433 //                             disable_arm_neon == NULL;
    434 //     }
    435 // }
    436 // #endif /* defined(__ANDROID__) && (defined(__arm__) || defined(__aarch64__)) */
    437 
    438 PRBool
    439 aesni_support()
    440 {
    441    return aesni_support_;
    442 }
    443 PRBool
    444 clmul_support()
    445 {
    446    return clmul_support_;
    447 }
    448 PRBool
    449 sha_support()
    450 {
    451    return sha_support_;
    452 }
    453 PRBool
    454 avx_support()
    455 {
    456    return avx_support_;
    457 }
    458 PRBool
    459 avx2_support()
    460 {
    461    return avx2_support_;
    462 }
    463 PRBool
    464 adx_support()
    465 {
    466    return adx_support_;
    467 }
    468 PRBool
    469 ssse3_support()
    470 {
    471    return ssse3_support_;
    472 }
    473 PRBool
    474 sse4_1_support()
    475 {
    476    return sse4_1_support_;
    477 }
    478 PRBool
    479 sse4_2_support()
    480 {
    481    return sse4_2_support_;
    482 }
    483 PRBool
    484 arm_neon_support()
    485 {
    486    return arm_neon_support_;
    487 }
    488 PRBool
    489 arm_aes_support()
    490 {
    491    return arm_aes_support_;
    492 }
    493 PRBool
    494 arm_pmull_support()
    495 {
    496    return arm_pmull_support_;
    497 }
    498 PRBool
    499 arm_sha1_support()
    500 {
    501    return arm_sha1_support_;
    502 }
    503 PRBool
    504 arm_sha2_support()
    505 {
    506    return arm_sha2_support_;
    507 }
    508 PRBool
    509 ppc_crypto_support()
    510 {
    511    return ppc_crypto_support_;
    512 }
    513 
    514 #if defined(__powerpc__)
    515 
    516 #ifndef __has_include
    517 #define __has_include(x) 0
    518 #endif
    519 
    520 /* clang-format off */
    521 #if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 12)
    522 #if __has_include(<sys/auxv.h>)
    523 #include <sys/auxv.h>
    524 #endif
    525 #elif (defined(__FreeBSD__) && __FreeBSD__ < 12)
    526 #include <sys/sysctl.h>
    527 #endif
    528 
    529 // Defines from cputable.h in Linux kernel - PPC, letting us build on older kernels
    530 #ifndef PPC_FEATURE2_VEC_CRYPTO
    531 #define PPC_FEATURE2_VEC_CRYPTO 0x02000000
    532 #endif
    533 
    534 static void
    535 CheckPPCSupport()
    536 {
    537    char *disable_hw_crypto = PR_GetEnvSecure("NSS_DISABLE_PPC_GHASH");
    538 
    539    unsigned long hwcaps = 0;
    540 #if defined(__linux__)
    541 #if __has_include(<sys/auxv.h>)
    542    hwcaps = getauxval(AT_HWCAP2);
    543 #endif
    544 #elif defined(__FreeBSD__)
    545 #if __FreeBSD__ >= 12
    546 #if __has_include(<sys/auxv.h>)
    547    elf_aux_info(AT_HWCAP2, &hwcaps, sizeof(hwcaps));
    548 #endif
    549 #else
    550    size_t len = sizeof(hwcaps);
    551    sysctlbyname("hw.cpu_features2", &hwcaps, &len, NULL, 0);
    552 #endif
    553 #endif
    554 
    555    ppc_crypto_support_ = hwcaps & PPC_FEATURE2_VEC_CRYPTO && disable_hw_crypto == NULL;
    556 }
    557 /* clang-format on */
    558 
    559 #endif /* __powerpc__ */
    560 
    561 static PRStatus
    562 FreeblInit(void)
    563 {
    564 #ifdef NSS_X86_OR_X64
    565    CheckX86CPUSupport();
    566 #elif (defined(__aarch64__) || defined(__arm__))
    567    CheckARMSupport();
    568 #elif (defined(__powerpc__))
    569    CheckPPCSupport();
    570 #endif
    571    return PR_SUCCESS;
    572 }
    573 
    574 SECStatus
    575 BL_Init(void)
    576 {
    577    if (PR_CallOnce(&coFreeblInit, FreeblInit) != PR_SUCCESS) {
    578        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    579        return SECFailure;
    580    }
    581    RSA_Init();
    582 
    583    return SECSuccess;
    584 }