summaryrefslogtreecommitdiff
path: root/lib/freebl/blinit.c
diff options
context:
space:
mode:
authorFranziskus Kiefer <franziskuskiefer@gmail.com>2017-05-03 12:56:08 +0200
committerFranziskus Kiefer <franziskuskiefer@gmail.com>2017-05-03 12:56:08 +0200
commite580b085b7333b97e3963a0b4dcbdd7790236737 (patch)
tree3e11c45482e10eb88fb5f98319591ac5e791b40f /lib/freebl/blinit.c
parentc4c122e836d121d8d5b5263b4e09aa8833949c4c (diff)
downloadnss-hg-e580b085b7333b97e3963a0b4dcbdd7790236737.tar.gz
Bug 1361687 - make improved x86 feature detection available to all of freebl, r=mt
Differential Revision: https://nss-review.dev.mozaws.net/D290
Diffstat (limited to 'lib/freebl/blinit.c')
-rw-r--r--lib/freebl/blinit.c115
1 files changed, 115 insertions, 0 deletions
diff --git a/lib/freebl/blinit.c b/lib/freebl/blinit.c
new file mode 100644
index 000000000..2f167efd2
--- /dev/null
+++ b/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;
+}