From cb8544715bd4566c63f53cd01827410b0ca45694 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Fri, 2 May 2014 14:40:39 -0700 Subject: [PATCH] Check for SSE2/SSE3/NEON support at runtime. --- configure.ac | 23 +++--- src/libsodium/Makefile.am | 1 + src/libsodium/include/Makefile.am | 1 + src/libsodium/include/sodium.h | 1 + src/libsodium/include/sodium/runtime.h | 19 +++++ src/libsodium/sodium/core.c | 2 + src/libsodium/sodium/runtime.c | 100 +++++++++++++++++++++++++ 7 files changed, 136 insertions(+), 11 deletions(-) create mode 100644 src/libsodium/include/sodium/runtime.h create mode 100644 src/libsodium/sodium/runtime.c diff --git a/configure.ac b/configure.ac index 97247d0a..095dce23 100644 --- a/configure.ac +++ b/configure.ac @@ -323,18 +323,19 @@ void fcontract(uint128_t *t) { AM_CONDITIONAL([HAVE_TI_MODE], [test $HAVE_TI_MODE_V = 1]) AC_SUBST(HAVE_TI_MODE_V) -AC_MSG_CHECKING(for cpuid instruction) HAVE_CPUID_V=0 -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ ]], [[ -__asm__("movl %ebx,%esi\n" - "cpuid\n" - "movl %esi,%ebx"); -]])], -[AC_MSG_RESULT(yes) - AC_DEFINE([HAVE_CPUID], [1], [cpuid instruction is available]) - HAVE_CPUID_V=1], -[AC_MSG_RESULT(no)]) -AM_CONDITIONAL([HAVE_CPUID], [test $HAVE_CPUID_V = 1]) +AS_IF([test "$enable_asm" != "no"],[ + AC_MSG_CHECKING(for cpuid instruction) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ ]], [[ +unsigned int a; +__asm__ __volatile__("cpuid" : "=a" (a) : "a" (0U), "c" (0U)); + ]])], + [AC_MSG_RESULT(yes) + AC_DEFINE([HAVE_CPUID], [1], [cpuid instruction is available]) + HAVE_CPUID_V=1], + [AC_MSG_RESULT(no)]) + AM_CONDITIONAL([HAVE_CPUID], [test $HAVE_CPUID_V = 1]) + ]) AC_SUBST(HAVE_CPUID_V) AS_CASE([$host_cpu], diff --git a/src/libsodium/Makefile.am b/src/libsodium/Makefile.am index d76a01de..6f7f6842 100644 --- a/src/libsodium/Makefile.am +++ b/src/libsodium/Makefile.am @@ -193,6 +193,7 @@ libsodium_la_SOURCES = \ randombytes/sysrandom/randombytes_sysrandom.c \ sodium/compat.c \ sodium/core.c \ + sodium/runtime.c \ sodium/utils.c \ sodium/version.c diff --git a/src/libsodium/include/Makefile.am b/src/libsodium/include/Makefile.am index c8348bc2..7081f4d7 100644 --- a/src/libsodium/include/Makefile.am +++ b/src/libsodium/include/Makefile.am @@ -49,6 +49,7 @@ SODIUM_EXPORT = \ sodium/randombytes.h \ sodium/randombytes_salsa20_random.h \ sodium/randombytes_sysrandom.h \ + sodium/runtime.h sodium/utils.h EXTRA_SRC = $(SODIUM_EXPORT) \ diff --git a/src/libsodium/include/sodium.h b/src/libsodium/include/sodium.h index 4b2022e4..3032638e 100644 --- a/src/libsodium/include/sodium.h +++ b/src/libsodium/include/sodium.h @@ -41,6 +41,7 @@ #include #include #include +#include #include #include diff --git a/src/libsodium/include/sodium/runtime.h b/src/libsodium/include/sodium/runtime.h new file mode 100644 index 00000000..bf966d5c --- /dev/null +++ b/src/libsodium/include/sodium/runtime.h @@ -0,0 +1,19 @@ + +#ifndef __SODIUM_RUNTIME_H__ +#define __SODIUM_RUNTIME_H__ 1 + +#include "export.h" + +SODIUM_EXPORT +int sodium_runtime_get_cpu_features(void); + +SODIUM_EXPORT +int sodium_runtime_have_neon(void); + +SODIUM_EXPORT +int sodium_runtime_have_sse2(void); + +SODIUM_EXPORT +int sodium_runtime_have_sse3(void); + +#endif diff --git a/src/libsodium/sodium/core.c b/src/libsodium/sodium/core.c index 9ab858b3..652f31e1 100644 --- a/src/libsodium/sodium/core.c +++ b/src/libsodium/sodium/core.c @@ -2,6 +2,7 @@ #include "core.h" #include "crypto_onetimeauth.h" #include "randombytes.h" +#include "runtime.h" static int initialized; @@ -11,6 +12,7 @@ sodium_init(void) if (initialized != 0) { return 1; } + sodium_runtime_get_cpu_features(); if (crypto_onetimeauth_pick_best_implementation() == NULL) { return -1; } diff --git a/src/libsodium/sodium/runtime.c b/src/libsodium/sodium/runtime.c new file mode 100644 index 00000000..6f7f36da --- /dev/null +++ b/src/libsodium/sodium/runtime.c @@ -0,0 +1,100 @@ + +#ifdef HAVE_ANDROID_GETCPUFEATURES +# include +#endif + +#include "runtime.h" + +typedef struct CPUFeatures_ { + int initialized; + int have_neon; + int have_sse2; + int have_sse3; +} CPUFeatures; + +static CPUFeatures cpu_features; + +#define CPUID_SSE2 0x04000000 +#define CPUIDECX_SSE3 0x00000001 + +static int +_sodium_runtime_arm_cpu_features(CPUFeatures * const cpu_features) +{ +#ifndef __arm__ + cpu_features->have_neon = 0; + return -1; +#else +# ifdef __APPLE__ +# ifdef __ARM_NEON__ + cpu_features->have_neon = 1; +# else + cpu_features->have_neon = 0; +# endif +# elif defined(HAVE_ANDROID_GETCPUFEATURES) && defined(ANDROID_CPU_ARM_FEATURE_NEON) + cpu_features->have_neon = + (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0x0; +# else + cpu_features->have_neon = 0; +# endif + return 0; +#endif +} + +static void +_cpuid(unsigned int cpu_info[4U], const unsigned int cpu_info_type) +{ +#ifdef _MSC_VER + __cpuidex((int *) cpu_info, cpu_info_type, 0); +#elif defined(HAVE_CPUID) + __asm__ __volatile__ ("cpuid" : + "=a" (cpu_info[0]), "=b" (cpu_info[1]), + "=c" (cpu_info[2]), "=d" (cpu_info[3]) : + "a" (cpu_info_type), "c" (0U)); +#else + cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0; +#endif +} + +static int +_sodium_runtime_intel_cpu_features(CPUFeatures * const cpu_features) +{ + unsigned int cpu_info[4]; + unsigned int id; + + _cpuid(cpu_info, 0x0); + if ((id = cpu_info[0]) == 0U) { + return -1; + } + _cpuid(cpu_info, 0x00000001); + cpu_features->have_sse2 = ((cpu_info[3] & CPUID_SSE2) != 0x0); + cpu_features->have_sse3 = ((cpu_info[2] & CPUIDECX_SSE3) != 0x0); + + return 0; +} + +int +sodium_runtime_get_cpu_features(void) +{ + int ret = -1; + + ret &= _sodium_runtime_arm_cpu_features(&cpu_features); + ret &= _sodium_runtime_intel_cpu_features(&cpu_features); + cpu_features.initialized = 1; + + return ret; +} + +int +sodium_runtime_have_neon(void) { + return cpu_features.have_neon; +} + +int +sodium_runtime_have_sse2(void) { + return cpu_features.have_sse2; +} + +int +sodium_runtime_have_sse3(void) { + return cpu_features.have_sse3; +}