Coverage Report

Created: 2025-07-01 06:26

/src/nss/lib/freebl/blinit.c
Line
Count
Source (jump to first uncovered line)
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
4
{
59
4
    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
4
    __asm__(".byte 0x0F, 0x01, 0xd0"
73
4
            : "=a"(xcr0)
74
4
            : "c"(0)
75
4
            : "%edx");
76
4
#endif /* _MSC_VER */
77
    /* Check if xmm and ymm state are enabled in XCR0. */
78
4
    return (xcr0 & 6) == 6;
79
4
}
80
81
4
#define ECX_AESNI (1 << 25)
82
4
#define ECX_CLMUL (1 << 1)
83
8
#define ECX_XSAVE (1 << 26)
84
8
#define ECX_OSXSAVE (1 << 27)
85
8
#define ECX_AVX (1 << 28)
86
8
#define EBX_AVX2 (1 << 5)
87
4
#define EBX_ADX (1 << 19)
88
8
#define EBX_BMI1 (1 << 3)
89
8
#define EBX_BMI2 (1 << 8)
90
4
#define EBX_SHA (1 << 29)
91
8
#define ECX_FMA (1 << 12)
92
8
#define ECX_MOVBE (1 << 22)
93
4
#define ECX_SSSE3 (1 << 9)
94
4
#define ECX_SSE4_1 (1 << 19)
95
4
#define ECX_SSE4_2 (1 << 20)
96
8
#define AVX_BITS (ECX_XSAVE | ECX_OSXSAVE | ECX_AVX)
97
12
#define AVX2_EBX_BITS (EBX_AVX2 | EBX_BMI1 | EBX_BMI2)
98
12
#define AVX2_ECX_BITS (ECX_FMA | ECX_MOVBE)
99
100
void
101
CheckX86CPUSupport()
102
4
{
103
4
    unsigned long eax, ebx, ecx, edx;
104
4
    unsigned long eax7, ebx7, ecx7, edx7;
105
4
    char *disable_hw_aes = PR_GetEnvSecure("NSS_DISABLE_HW_AES");
106
4
    char *disable_pclmul = PR_GetEnvSecure("NSS_DISABLE_PCLMUL");
107
4
    char *disable_hw_sha = PR_GetEnvSecure("NSS_DISABLE_HW_SHA");
108
4
    char *disable_avx = PR_GetEnvSecure("NSS_DISABLE_AVX");
109
4
    char *disable_avx2 = PR_GetEnvSecure("NSS_DISABLE_AVX2");
110
4
    char *disable_adx = PR_GetEnvSecure("NSS_DISABLE_ADX");
111
4
    char *disable_ssse3 = PR_GetEnvSecure("NSS_DISABLE_SSSE3");
112
4
    char *disable_sse4_1 = PR_GetEnvSecure("NSS_DISABLE_SSE4_1");
113
4
    char *disable_sse4_2 = PR_GetEnvSecure("NSS_DISABLE_SSE4_2");
114
4
    freebl_cpuid(1, &eax, &ebx, &ecx, &edx);
115
4
    freebl_cpuid(7, &eax7, &ebx7, &ecx7, &edx7);
116
4
    aesni_support_ = (PRBool)((ecx & ECX_AESNI) != 0 && disable_hw_aes == NULL);
117
4
    clmul_support_ = (PRBool)((ecx & ECX_CLMUL) != 0 && disable_pclmul == NULL);
118
4
    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
4
    avx_support_ = (PRBool)((ecx & AVX_BITS) == AVX_BITS) && check_xcr0_ymm() &&
124
4
                   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
4
    avx2_support_ = (PRBool)(avx_support_ == PR_TRUE &&
132
4
                             (ebx7 & AVX2_EBX_BITS) == AVX2_EBX_BITS &&
133
4
                             (ecx & AVX2_ECX_BITS) == AVX2_ECX_BITS &&
134
4
                             disable_avx2 == NULL);
135
    /* CPUID.(EAX=07H, ECX=0H):EBX.ADX[bit 19]=1 indicates
136
    the processor supports ADCX and ADOX instructions.*/
137
4
    adx_support_ = (PRBool)((ebx7 & EBX_ADX) != 0 && disable_adx == NULL);
138
4
    ssse3_support_ = (PRBool)((ecx & ECX_SSSE3) != 0 &&
139
4
                              disable_ssse3 == NULL);
140
4
    sse4_1_support_ = (PRBool)((ecx & ECX_SSE4_1) != 0 &&
141
4
                               disable_sse4_1 == NULL);
142
4
    sse4_2_support_ = (PRBool)((ecx & ECX_SSE4_2) != 0 &&
143
4
                               disable_sse4_2 == NULL);
144
4
}
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
378k
{
441
378k
    return aesni_support_;
442
378k
}
443
PRBool
444
clmul_support()
445
54.6k
{
446
54.6k
    return clmul_support_;
447
54.6k
}
448
PRBool
449
sha_support()
450
1.55M
{
451
1.55M
    return sha_support_;
452
1.55M
}
453
PRBool
454
avx_support()
455
0
{
456
0
    return avx_support_;
457
0
}
458
PRBool
459
avx2_support()
460
19.7k
{
461
19.7k
    return avx2_support_;
462
19.7k
}
463
PRBool
464
adx_support()
465
0
{
466
0
    return adx_support_;
467
0
}
468
PRBool
469
ssse3_support()
470
0
{
471
0
    return ssse3_support_;
472
0
}
473
PRBool
474
sse4_1_support()
475
0
{
476
0
    return sse4_1_support_;
477
0
}
478
PRBool
479
sse4_2_support()
480
0
{
481
0
    return sse4_2_support_;
482
0
}
483
PRBool
484
arm_neon_support()
485
0
{
486
0
    return arm_neon_support_;
487
0
}
488
PRBool
489
arm_aes_support()
490
0
{
491
0
    return arm_aes_support_;
492
0
}
493
PRBool
494
arm_pmull_support()
495
0
{
496
0
    return arm_pmull_support_;
497
0
}
498
PRBool
499
arm_sha1_support()
500
0
{
501
0
    return arm_sha1_support_;
502
0
}
503
PRBool
504
arm_sha2_support()
505
1.55M
{
506
1.55M
    return arm_sha2_support_;
507
1.55M
}
508
PRBool
509
ppc_crypto_support()
510
0
{
511
0
    return ppc_crypto_support_;
512
0
}
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
4
{
564
4
#ifdef NSS_X86_OR_X64
565
4
    CheckX86CPUSupport();
566
#elif (defined(__aarch64__) || defined(__arm__))
567
    CheckARMSupport();
568
#elif (defined(__powerpc__))
569
    CheckPPCSupport();
570
#endif
571
4
    return PR_SUCCESS;
572
4
}
573
574
SECStatus
575
BL_Init(void)
576
4
{
577
4
    if (PR_CallOnce(&coFreeblInit, FreeblInit) != PR_SUCCESS) {
578
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
579
0
        return SECFailure;
580
0
    }
581
4
    RSA_Init();
582
583
4
    return SECSuccess;
584
4
}