1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
/* 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 <intrin.h> /* 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;
#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 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");
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;
}
#endif /* NSS_X86_OR_X64 */
PRBool
aesni_support()
{
return aesni_support_;
}
PRBool
clmul_support()
{
return clmul_support_;
}
PRBool
avx_support()
{
return avx_support_;
}
static PRStatus
FreeblInit(void)
{
#ifdef NSS_X86_OR_X64
CheckX86CPUSupport();
#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;
}
|