Skip to content

Commit

Permalink
Bug 1361687 - make improved x86 feature detection available to all of…
Browse files Browse the repository at this point in the history
… freebl, r=mt

Differential Revision: https://nss-review.dev.mozaws.net/D290

--HG--
extra : rebase_source : 5b78af45282ea8d45a6c9399bdf7dbaefb15bfea
  • Loading branch information
franziskuskiefer committed May 3, 2017
1 parent ad7d63c commit 0997a52
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 72 deletions.
7 changes: 7 additions & 0 deletions lib/freebl/blapii.h
Expand Up @@ -58,4 +58,11 @@ SEC_END_PROTOS

#undef HAVE_NO_SANITIZE_ATTR

SECStatus RSA_Init();

/* Freebl state. */
PRBool aesni_support();
PRBool clmul_support();
PRBool avx_support();

#endif /* _BLAPII_H_ */
115 changes: 115 additions & 0 deletions lib/freebl/blinit.c
@@ -0,0 +1,115 @@
/* 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 */
__asm__("xgetbv"
: "=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");
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);
/* 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();
}
#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;
}
1 change: 1 addition & 0 deletions lib/freebl/freebl_base.gypi
Expand Up @@ -33,6 +33,7 @@
'ecl/ecp_jm.c',
'ecl/ecp_mont.c',
'fipsfreebl.c',
'blinit.c',
'freeblver.c',
'gcm.c',
'hmacct.c',
Expand Down
1 change: 1 addition & 0 deletions lib/freebl/manifest.mn
Expand Up @@ -132,6 +132,7 @@ CSRCS = \
chacha20poly1305.c \
cts.c \
ctr.c \
blinit.c \
fipsfreebl.c \
gcm.c \
hmacct.c \
Expand Down
67 changes: 2 additions & 65 deletions lib/freebl/rijndael.c
Expand Up @@ -26,17 +26,11 @@
#include "mpi.h"

#ifdef USE_HW_AES
static int has_intel_aes = 0;
static PRBool use_hw_aes = PR_FALSE;

#ifdef INTEL_GCM
#include "intel-gcm.h"
static int has_intel_avx = 0;
static int has_intel_clmul = 0;
static PRBool use_hw_gcm = PR_FALSE;
#if defined(_MSC_VER) && !defined(_M_IX86)
#include <intrin.h> /* for _xgetbv() */
#endif
#endif
#endif /* USE_HW_AES */

Expand Down Expand Up @@ -999,39 +993,6 @@ AES_AllocateContext(void)
return PORT_ZNew(AESContext);
}

#ifdef INTEL_GCM
/*
* 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
#else
__asm__("xgetbv"
: "=a"(xcr0)
: "c"(0)
: "%edx");
#endif
/* Check if xmm and ymm state are enabled in XCR0. */
return (xcr0 & 6) == 6;
}
#endif

/*
** Initialize a new AES context suitable for AES encryption/decryption in
** the ECB or CBC mode.
Expand Down Expand Up @@ -1070,33 +1031,9 @@ aes_InitContext(AESContext *cx, const unsigned char *key, unsigned int keysize,
return SECFailure;
}
#ifdef USE_HW_AES
if (has_intel_aes == 0) {
unsigned long eax, ebx, ecx, edx;
char *disable_hw_aes = PR_GetEnvSecure("NSS_DISABLE_HW_AES");

if (disable_hw_aes == NULL) {
freebl_cpuid(1, &eax, &ebx, &ecx, &edx);
has_intel_aes = (ecx & (1 << 25)) != 0 ? 1 : -1;
#ifdef INTEL_GCM
has_intel_clmul = (ecx & (1 << 1)) != 0 ? 1 : -1;
if ((ecx & (1 << 27)) != 0 && (ecx & (1 << 28)) != 0 &&
check_xcr0_ymm()) {
has_intel_avx = 1;
} else {
has_intel_avx = -1;
}
#endif
} else {
has_intel_aes = -1;
#ifdef INTEL_GCM
has_intel_avx = -1;
has_intel_clmul = -1;
#endif
}
}
use_hw_aes = (PRBool)(has_intel_aes > 0 && (keysize % 8) == 0 && blocksize == 16);
use_hw_aes = aesni_support() && (keysize % 8) == 0 && blocksize == 16;
#ifdef INTEL_GCM
use_hw_gcm = (PRBool)(use_hw_aes && has_intel_avx > 0 && has_intel_clmul > 0);
use_hw_gcm = use_hw_aes && avx_support() && clmul_support();
#endif
#endif /* USE_HW_AES */
/* Nb = (block size in bits) / 32 */
Expand Down
8 changes: 1 addition & 7 deletions lib/freebl/rsa.c
Expand Up @@ -1551,7 +1551,7 @@ RSA_PrivateKeyCheck(const RSAPrivateKey *key)
return rv;
}

static SECStatus
SECStatus
RSA_Init(void)
{
if (PR_CallOnce(&coBPInit, init_blinding_params_list) != PR_SUCCESS) {
Expand All @@ -1561,12 +1561,6 @@ RSA_Init(void)
return SECSuccess;
}

SECStatus
BL_Init(void)
{
return RSA_Init();
}

/* cleanup at shutdown */
void
RSA_Cleanup(void)
Expand Down

0 comments on commit 0997a52

Please sign in to comment.