Add ARM HW feature detection module and add NEON detection
authorJussi Kivilinna <jussi.kivilinna@iki.fi>
Sat, 31 Aug 2013 09:48:30 +0000 (12:48 +0300)
committerJussi Kivilinna <jussi.kivilinna@iki.fi>
Sat, 31 Aug 2013 09:48:30 +0000 (12:48 +0300)
* configure.ac: Add option --disable-neon-support.
(HAVE_GCC_INLINE_ASM_NEON): New.
(ENABLE_NEON_SUPPORT): New.
[arm]: Add 'hwf-arm.lo' as HW feature module.
* src/Makefile.am: Add 'hwf-arm.c'.
* src/g10lib.h (HWF_ARM_NEON): New macro.
* src/global.c (hwflist): Add HWF_ARM_NEON entry.
* src/hwf-arm.c: New file.
* src/hwf-common.h (_gcry_hwf_detect_arm): New prototype.
* src/hwfeatures.c (_gcry_detect_hw_features) [HAVE_CPU_ARCH_ARM]: Add
call to _gcry_hwf_detect_arm.
--

Add HW detection module for detecting ARM NEON instruction set. ARM does not
have cpuid instruction so we have to rely on OS to pass feature set information
to user-space. For linux, NEON support can be detected by parsing
'/proc/self/auxv' for hardware capabilities information. For other OSes, NEON
can be detected by checking if platform/compiler only supports NEON capable
CPUs (by check if __ARM_NEON__ macro is defined).

Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi>
configure.ac
src/Makefile.am
src/g10lib.h
src/global.c
src/hwf-arm.c [new file with mode: 0644]
src/hwf-common.h
src/hwfeatures.c

index b54b4d6..89b9366 100644 (file)
@@ -595,6 +595,14 @@ AC_ARG_ENABLE(avx2-support,
              avx2support=$enableval,avx2support=yes)
 AC_MSG_RESULT($avx2support)
 
+# Implementation of the --disable-neon-support switch.
+AC_MSG_CHECKING([whether NEON support is requested])
+AC_ARG_ENABLE(neon-support,
+              AC_HELP_STRING([--disable-neon-support],
+                 [Disable support for the ARM NEON instructions]),
+             neonsupport=$enableval,neonsupport=yes)
+AC_MSG_RESULT($neonsupport)
+
 # Implementation of the --disable-O-flag-munging switch.
 AC_MSG_CHECKING([whether a -O flag munging is requested])
 AC_ARG_ENABLE([O-flag-munging],
@@ -988,6 +996,30 @@ fi
 
 
 #
+# Check whether GCC inline assembler supports NEON instructions
+#
+AC_CACHE_CHECK([whether GCC inline assembler supports NEON instructions],
+       [gcry_cv_gcc_inline_asm_neon],
+       [gcry_cv_gcc_inline_asm_neon=no
+        AC_COMPILE_IFELSE([AC_LANG_SOURCE(
+          [[__asm__(
+                ".syntax unified\n\t"
+                ".thumb\n\t"
+                ".fpu neon\n\t"
+                "vld1.64 {%q0-%q1}, [%r0]!;\n\t"
+                "vrev64.8 %q0, %q3;\n\t"
+                "vadd.u64 %q0, %q1;\n\t"
+                "vadd.s64 %d3, %d2, %d3;\n\t"
+                );
+            ]])],
+          [gcry_cv_gcc_inline_asm_neon=yes])])
+if test "$gcry_cv_gcc_inline_asm_neon" = "yes" ; then
+   AC_DEFINE(HAVE_GCC_INLINE_ASM_NEON,1,
+     [Defined if inline assembler supports NEON instructions])
+fi
+
+
+#
 # Check whether GCC assembler supports features needed for our ARM
 # implementations
 #
@@ -1269,6 +1301,11 @@ if test x"$avx2support" = xyes ; then
     avx2support="no (unsupported by compiler)"
   fi
 fi
+if test x"$neonsupport" = xyes ; then
+  if test "$gcry_cv_gcc_inline_asm_neon" != "yes" ; then
+    neonsupport="no (unsupported by compiler)"
+  fi
+fi
 
 if test x"$aesnisupport" = xyes ; then
   AC_DEFINE(ENABLE_AESNI_SUPPORT, 1,
@@ -1282,6 +1319,10 @@ if test x"$avx2support" = xyes ; then
   AC_DEFINE(ENABLE_AVX2_SUPPORT,1,
             [Enable support for Intel AVX2 instructions.])
 fi
+if test x"$neonsupport" = xyes ; then
+  AC_DEFINE(ENABLE_NEON_SUPPORT,1,
+            [Enable support for ARM NEON instructions.])
+fi
 
 
 # Define conditional sources and config.h symbols depending on the
@@ -1597,6 +1638,7 @@ case "$mpi_cpu_arch" in
         ;;
      arm)
         AC_DEFINE(HAVE_CPU_ARCH_ARM, 1,   [Defined for ARM platforms])
+        GCRYPT_HWF_MODULES="hwf-arm.lo"
         ;;
 esac
 AC_SUBST([GCRYPT_HWF_MODULES])
@@ -1660,6 +1702,7 @@ GCRY_MSG_SHOW([Try using AES-NI crypto:  ],[$aesnisupport])
 GCRY_MSG_SHOW([Try using DRNG (RDRAND):  ],[$drngsupport])
 GCRY_MSG_SHOW([Try using Intel AVX:      ],[$avxsupport])
 GCRY_MSG_SHOW([Try using Intel AVX2:     ],[$avx2support])
+GCRY_MSG_SHOW([Try using ARM NEON:       ],[$neonsupport])
 GCRY_MSG_SHOW([],[])
 
 if test "$print_egd_notice" = "yes"; then
index 8eb46e6..d4329c9 100644 (file)
@@ -64,7 +64,7 @@ libgcrypt_la_SOURCES = \
        ec-context.h \
        ath.h ath.c
 
-EXTRA_libgcrypt_la_SOURCES = hwf-x86.c
+EXTRA_libgcrypt_la_SOURCES = hwf-x86.c hwf-arm.c
 gcrypt_hwf_modules = @GCRYPT_HWF_MODULES@
 
 
index 198ab38..31131a5 100644 (file)
@@ -155,6 +155,8 @@ int _gcry_log_verbosity( int level );
 #define HWF_INTEL_AVX    1024
 #define HWF_INTEL_AVX2   2048
 
+#define HWF_ARM_NEON     4096
+
 
 unsigned int _gcry_get_hw_features (void);
 void _gcry_detect_hw_features (unsigned int);
index 9c80573..44667cf 100644 (file)
@@ -70,6 +70,7 @@ static struct
     { HWF_INTEL_RDRAND,"intel-rdrand" },
     { HWF_INTEL_AVX,   "intel-avx" },
     { HWF_INTEL_AVX2,  "intel-avx2" },
+    { HWF_ARM_NEON,    "arm-neon" },
     { 0, NULL}
   };
 
diff --git a/src/hwf-arm.c b/src/hwf-arm.c
new file mode 100644 (file)
index 0000000..9ab4cd0
--- /dev/null
@@ -0,0 +1,113 @@
+/* hwf-arm.c - Detect hardware features - ARM part
+ * Copyright © 2013  Jussi Kivilinna <jussi.kivilinna@iki.fi>
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#include "g10lib.h"
+#include "hwf-common.h"
+
+#if !defined (__arm__)
+# error Module build for wrong CPU.
+#endif
+
+#undef HAS_SYS_AT_HWCAP
+#ifdef __linux__
+
+#define HAS_SYS_AT_HWCAP 1
+
+#define AT_HWCAP 16
+#define HWCAP_NEON 4096
+
+static int get_hwcap(unsigned int *hwcap)
+{
+  struct { unsigned int a_type; unsigned int a_val; } auxv;
+  FILE *f;
+  int err = -1;
+  static int hwcap_initialized = 0;
+  static unsigned int stored_hwcap;
+
+  if (hwcap_initialized)
+    {
+      *hwcap = stored_hwcap;
+      return 0;
+    }
+
+  f = fopen("/proc/self/auxv", "r");
+  if (!f)
+    {
+      *hwcap = stored_hwcap;
+      return -1;
+    }
+
+  while (fread(&auxv, sizeof(auxv), 1, f) > 0)
+    {
+      if (auxv.a_type != AT_HWCAP)
+        continue;
+
+      stored_hwcap = auxv.a_val;
+      hwcap_initialized = 1;
+      err = 0;
+      break;
+    }
+
+  fclose(f);
+  *hwcap = stored_hwcap;
+  return err;
+}
+
+static unsigned int detect_arm_at_hwcap(void)
+{
+  unsigned int hwcap;
+  unsigned int features = 0;
+
+  if (get_hwcap(&hwcap) < 0)
+    return features;
+
+#ifdef ENABLE_NEON_SUPPORT
+  if (hwcap & HWCAP_NEON)
+    features |= HWF_ARM_NEON;
+#endif
+
+  return features;
+}
+
+#endif /* __linux__ */
+
+unsigned int
+_gcry_hwf_detect_arm (void)
+{
+  unsigned int ret = 0;
+
+#if defined (HAS_SYS_AT_HWCAP)
+  ret |= detect_arm_at_hwcap ();
+#else
+  ret |= 0;
+#endif
+
+#if defined(__ARM_NEON__) && defined(ENABLE_NEON_SUPPORT)
+  ret |= HWF_ARM_NEON;
+#endif
+
+  return ret;
+}
index 974f47d..8f156b5 100644 (file)
@@ -21,6 +21,7 @@
 #define HWF_COMMON_H
 
 unsigned int _gcry_hwf_detect_x86 (void);
+unsigned int _gcry_hwf_detect_arm (void);
 
 
 #endif /*HWF_COMMON_H*/
index 87d05d8..1e3c27d 100644 (file)
@@ -59,6 +59,11 @@ _gcry_detect_hw_features (unsigned int disabled_features)
     hw_features = _gcry_hwf_detect_x86 ();
   }
 #endif /* HAVE_CPU_ARCH_X86 */
+#if defined (HAVE_CPU_ARCH_ARM)
+  {
+    hw_features = _gcry_hwf_detect_arm ();
+  }
+#endif /* HAVE_CPU_ARCH_ARM */
 
   hw_features &= ~disabled_features;
 }