Add HW feature check for ARMv8 AArch64 and crypto extensions
authorJussi Kivilinna <jussi.kivilinna@iki.fi>
Thu, 14 Jul 2016 14:55:28 +0000 (17:55 +0300)
committerJussi Kivilinna <jussi.kivilinna@iki.fi>
Thu, 14 Jul 2016 14:55:28 +0000 (17:55 +0300)
* configure.ac: Add '--disable-arm-crypto-support'; enable hwf-arm
module on 64-bit ARM.
(armcryptosupport, gcry_cv_gcc_inline_aarch32_crypto)
(gcry_cv_inline_asm_aarch64_neon)
(gcry_cv_gcc_inline_asm_aarch64_crypto): New.
* src/g10lib.h (HWF_ARM_AES, HWF_ARM_SHA1, HWF_ARM_SHA2)
(HWF_ARM_PMULL): New.
* src/hwf-arm.c [__aarch64__]: Enable building in AArch64 mode.
(feature_map_s): New.
[__arm__] (AT_HWCAP, AT_HWCAP2, HWCAP2_AES, HWCAP2_PMULL)
(HWCAP2_SHA1, HWCAP2_SHA2, arm_features): New.
[__aarch64__] (AT_HWCAP, AT_HWCAP2, HWCAP_ASIMD, HWCAP_AES)
(HWCAP_PMULL, HWCAP_SHA1, HWCAP_SHA2, arm_features): New.
(get_hwcap): Add reading of 'AT_HWCAP2'; Change auxv use
'unsigned long'.
(detect_arm_at_hwcap): Add mapping of HWCAP/HWCAP2 to HWF flags.
(detect_arm_proc_cpuinfo): Add mapping of CPU features to HWF flags.
(_gcry_hwf_detect_arm): Use __ARM_NEON instead of legacy __ARM_NEON__.
* src/hwfeatures.c (hwflist): Add 'arm-aes', 'arm-sha1', 'arm-sha2'
and 'arm-pmull'.
--

Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi>
configure.ac
src/g10lib.h
src/hwf-arm.c
src/hwfeatures.c

index b116285..0299571 100644 (file)
@@ -637,6 +637,14 @@ AC_ARG_ENABLE(neon-support,
              neonsupport=$enableval,neonsupport=yes)
 AC_MSG_RESULT($neonsupport)
 
+# Implementation of the --disable-arm-crypto-support switch.
+AC_MSG_CHECKING([whether ARMv8 Crypto Extension support is requested])
+AC_ARG_ENABLE(arm-crypto-support,
+              AC_HELP_STRING([--disable-arm-crypto-support],
+                 [Disable support for the ARMv8 Crypto Extension instructions]),
+             armcryptosupport=$enableval,armcryptosupport=yes)
+AC_MSG_RESULT($armcryptosupport)
+
 # Implementation of the --disable-O-flag-munging switch.
 AC_MSG_CHECKING([whether a -O flag munging is requested])
 AC_ARG_ENABLE([O-flag-munging],
@@ -1125,7 +1133,10 @@ if test "$mpi_cpu_arch" != "x86" ; then
 fi
 
 if test "$mpi_cpu_arch" != "arm" ; then
-   neonsupport="n/a"
+   if test "$mpi_cpu_arch" != "aarch64" ; then
+     neonsupport="n/a"
+     armcryptosupport="n/a"
+   fi
 fi
 
 
@@ -1532,6 +1543,116 @@ if test "$gcry_cv_gcc_inline_asm_neon" = "yes" ; then
 fi
 
 
+#
+# Check whether GCC inline assembler supports AArch32 Crypto Extension instructions
+#
+AC_CACHE_CHECK([whether GCC inline assembler supports AArch32 Crypto Extension instructions],
+       [gcry_cv_gcc_inline_asm_aarch32_crypto],
+       [if test "$mpi_cpu_arch" != "arm" ; then
+          gcry_cv_gcc_inline_asm_aarch32_crypto="n/a"
+        else
+          gcry_cv_gcc_inline_asm_aarch32_crypto=no
+          AC_COMPILE_IFELSE([AC_LANG_SOURCE(
+          [[__asm__(
+                ".syntax unified\n\t"
+                ".arm\n\t"
+                ".fpu crypto-neon-fp-armv8\n\t"
+
+                "sha1h.32 q0, q0;\n\t"
+                "sha1c.32 q0, q0, q0;\n\t"
+                "sha1p.32 q0, q0, q0;\n\t"
+                "sha1su0.32 q0, q0, q0;\n\t"
+                "sha1su1.32 q0, q0;\n\t"
+
+                "sha256h.32 q0, q0, q0;\n\t"
+                "sha256h2.32 q0, q0, q0;\n\t"
+                "sha1p.32 q0, q0, q0;\n\t"
+                "sha256su0.32 q0, q0;\n\t"
+                "sha256su1.32 q0, q0, q15;\n\t"
+
+                "aese.8 q0, q0;\n\t"
+                "aesd.8 q0, q0;\n\t"
+                "aesmc.8 q0, q0;\n\t"
+                "aesimc.8 q0, q0;\n\t"
+
+                "vmull.p64 q0, d0, d0;\n\t"
+                );
+            ]])],
+          [gcry_cv_gcc_inline_asm_aarch32_crypto=yes])
+        fi])
+if test "$gcry_cv_gcc_inline_asm_aarch32_crypto" = "yes" ; then
+   AC_DEFINE(HAVE_GCC_INLINE_ASM_AARCH32_CRYPTO,1,
+     [Defined if inline assembler supports AArch32 Crypto Extension instructions])
+fi
+
+
+#
+# Check whether GCC inline assembler supports AArch64 NEON instructions
+#
+AC_CACHE_CHECK([whether GCC inline assembler supports AArch64 NEON instructions],
+       [gcry_cv_gcc_inline_asm_aarch64_neon],
+       [if test "$mpi_cpu_arch" != "aarch64" ; then
+          gcry_cv_gcc_inline_asm_aarch64_neon="n/a"
+        else
+          gcry_cv_gcc_inline_asm_aarch64_neon=no
+          AC_COMPILE_IFELSE([AC_LANG_SOURCE(
+          [[__asm__(
+                ".arch armv8-a\n\t"
+                "mov w0, \#42;\n\t"
+                "dup v0.8b, w0;\n\t"
+                "ld4 {v0.8b,v1.8b,v2.8b,v3.8b},[x0],\#32;\n\t"
+                );
+            ]])],
+          [gcry_cv_gcc_inline_asm_aarch64_neon=yes])
+        fi])
+if test "$gcry_cv_gcc_inline_asm_aarch64_neon" = "yes" ; then
+   AC_DEFINE(HAVE_GCC_INLINE_ASM_AARCH64_NEON,1,
+     [Defined if inline assembler supports AArch64 NEON instructions])
+fi
+
+
+#
+# Check whether GCC inline assembler supports AArch64 Crypto Extension instructions
+#
+AC_CACHE_CHECK([whether GCC inline assembler supports AArch64 Crypto Extension instructions],
+       [gcry_cv_gcc_inline_asm_aarch64_crypto],
+       [if test "$mpi_cpu_arch" != "aarch64" ; then
+          gcry_cv_gcc_inline_asm_aarch64_crypto="n/a"
+        else
+          gcry_cv_gcc_inline_asm_aarch64_crypto=no
+          AC_COMPILE_IFELSE([AC_LANG_SOURCE(
+          [[__asm__(
+                ".arch armv8-a+crypto\n\t"
+
+                "sha1h s0, s0;\n\t"
+                "sha1c q0, s0, v0.4s;\n\t"
+                "sha1p q0, s0, v0.4s;\n\t"
+                "sha1su0 v0.4s, v0.4s, v0.4s;\n\t"
+                "sha1su1 v0.4s, v0.4s;\n\t"
+
+                "sha256h q0, q0, v0.4s;\n\t"
+                "sha256h2 q0, q0, v0.4s;\n\t"
+                "sha1p q0, s0, v0.4s;\n\t"
+                "sha256su0 v0.4s, v0.4s;\n\t"
+                "sha256su1 v0.4s, v0.4s, v31.4s;\n\t"
+
+                "aese v0.16b, v0.16b;\n\t"
+                "aesd v0.16b, v0.16b;\n\t"
+                "aesmc v0.16b, v0.16b;\n\t"
+                "aesimc v0.16b, v0.16b;\n\t"
+
+                "pmull v0.1q, v0.1d, v31.1d;\n\t"
+                "pmull2 v0.1q, v0.2d, v31.2d;\n\t"
+                );
+            ]])],
+          [gcry_cv_gcc_inline_asm_aarch64_crypto=yes])
+        fi])
+if test "$gcry_cv_gcc_inline_asm_aarch64_crypto" = "yes" ; then
+   AC_DEFINE(HAVE_GCC_INLINE_ASM_AARCH64_CRYPTO,1,
+     [Defined if inline assembler supports AArch64 Crypto Extension instructions])
+fi
+
+
 #######################################
 #### Checks for library functions. ####
 #######################################
@@ -1758,7 +1879,16 @@ if test x"$avx2support" = xyes ; then
 fi
 if test x"$neonsupport" = xyes ; then
   if test "$gcry_cv_gcc_inline_asm_neon" != "yes" ; then
-    neonsupport="no (unsupported by compiler)"
+    if test "$gcry_cv_gcc_inline_asm_aarch64_neon" != "yes" ; then
+      neonsupport="no (unsupported by compiler)"
+    fi
+  fi
+fi
+if test x"$armcryptosupport" = xyes ; then
+  if test "$gcry_cv_gcc_inline_asm_aarch32_crypto" != "yes" ; then
+    if test "$gcry_cv_gcc_inline_asm_aarch64_crypto" != "yes" ; then
+      neonsupport="no (unsupported by compiler)"
+    fi
   fi
 fi
 
@@ -1786,6 +1916,10 @@ if test x"$neonsupport" = xyes ; then
   AC_DEFINE(ENABLE_NEON_SUPPORT,1,
             [Enable support for ARM NEON instructions.])
 fi
+if test x"$armcryptosupport" = xyes ; then
+  AC_DEFINE(ENABLE_ARM_CRYPTO_SUPPORT,1,
+            [Enable support for ARMv8 Crypto Extension instructions.])
+fi
 if test x"$padlocksupport" = xyes ; then
   AC_DEFINE(ENABLE_PADLOCK_SUPPORT, 1,
             [Enable support for the PadLock engine.])
@@ -2299,6 +2433,10 @@ case "$mpi_cpu_arch" in
         AC_DEFINE(HAVE_CPU_ARCH_ARM, 1,   [Defined for ARM platforms])
         GCRYPT_HWF_MODULES="hwf-arm.lo"
         ;;
+     aarch64)
+        AC_DEFINE(HAVE_CPU_ARCH_ARM, 1,   [Defined for ARM AArch64 platforms])
+        GCRYPT_HWF_MODULES="hwf-arm.lo"
+        ;;
 esac
 AC_SUBST([GCRYPT_HWF_MODULES])
 
@@ -2384,6 +2522,7 @@ 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([Try using ARMv8 crypto:   ],[$armcryptosupport])
 GCRY_MSG_SHOW([],[])
 
 if test "x${gpg_config_script_warn}" != x; then
index 170ffa1..444c868 100644 (file)
@@ -211,6 +211,10 @@ char **_gcry_strtokenize (const char *string, const char *delim);
 #define HWF_INTEL_AVX2      (1 << 13)
 
 #define HWF_ARM_NEON        (1 << 14)
+#define HWF_ARM_AES         (1 << 15)
+#define HWF_ARM_SHA1        (1 << 16)
+#define HWF_ARM_SHA2        (1 << 17)
+#define HWF_ARM_PMULL       (1 << 18)
 
 
 gpg_err_code_t _gcry_disable_hw_feature (const char *name);
index 3dc050e..a762b5e 100644 (file)
@@ -27,7 +27,7 @@
 #include "g10lib.h"
 #include "hwf-common.h"
 
-#if !defined (__arm__)
+#if !defined (__arm__) && !defined (__aarch64__)
 # error Module build for wrong CPU.
 #endif
 
 #undef HAS_PROC_CPUINFO
 #ifdef __linux__
 
+struct feature_map_s {
+  unsigned int hwcap_flag;
+  unsigned int hwcap2_flag;
+  const char *feature_match;
+  unsigned int hwf_flag;
+};
+
 #define HAS_SYS_AT_HWCAP 1
+#define HAS_PROC_CPUINFO 1
+
+#ifdef __arm__
+
+#define AT_HWCAP      16
+#define AT_HWCAP2     26
+
+#define HWCAP_NEON    4096
 
-#define AT_HWCAP 16
-#define HWCAP_NEON 4096
+#define HWCAP2_AES    1
+#define HWCAP2_PMULL  2
+#define HWCAP2_SHA1   3
+#define HWCAP2_SHA2   4
+
+static const struct feature_map_s arm_features[] =
+  {
+#ifdef ENABLE_NEON_SUPPORT
+    { HWCAP_NEON, 0, " neon", HWF_ARM_NEON },
+#endif
+#ifdef ENABLE_ARM_CRYPTO_SUPPORT
+    { 0, HWCAP2_AES, " aes", HWF_ARM_AES },
+    { 0, HWCAP2_SHA1," sha1", HWF_ARM_SHA1 },
+    { 0, HWCAP2_SHA2, " sha2", HWF_ARM_SHA2 },
+    { 0, HWCAP2_PMULL, " pmull", HWF_ARM_PMULL },
+#endif
+  };
+
+#elif defined(__aarch64__)
+
+#define AT_HWCAP    16
+#define AT_HWCAP2   -1
+
+#define HWCAP_ASIMD 2
+#define HWCAP_AES   8
+#define HWCAP_PMULL 16
+#define HWCAP_SHA1  32
+#define HWCAP_SHA2  64
+
+static const struct feature_map_s arm_features[] =
+  {
+#ifdef ENABLE_NEON_SUPPORT
+    { HWCAP_ASIMD, 0, " asimd", HWF_ARM_NEON },
+#endif
+#ifdef ENABLE_ARM_CRYPTO_SUPPORT
+    { HWCAP_AES, 0, " aes", HWF_ARM_AES },
+    { HWCAP_SHA1, 0, " sha1", HWF_ARM_SHA1 },
+    { HWCAP_SHA2, 0, " sha2", HWF_ARM_SHA2 },
+    { HWCAP_PMULL, 0, " pmull", HWF_ARM_PMULL },
+#endif
+  };
+
+#endif
 
 static int
-get_hwcap(unsigned int *hwcap)
+get_hwcap(unsigned int *hwcap, unsigned int *hwcap2)
 {
-  struct { unsigned int a_type; unsigned int a_val; } auxv;
+  struct { unsigned long a_type; unsigned long a_val; } auxv;
   FILE *f;
   int err = -1;
   static int hwcap_initialized = 0;
-  static unsigned int stored_hwcap;
+  static unsigned int stored_hwcap = 0;
+  static unsigned int stored_hwcap2 = 0;
 
   if (hwcap_initialized)
     {
       *hwcap = stored_hwcap;
+      *hwcap2 = stored_hwcap2;
       return 0;
     }
 
@@ -59,22 +117,31 @@ get_hwcap(unsigned int *hwcap)
   if (!f)
     {
       *hwcap = stored_hwcap;
+      *hwcap2 = stored_hwcap2;
       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;
+      if (auxv.a_type == AT_HWCAP)
+        {
+          stored_hwcap = auxv.a_val;
+          hwcap_initialized = 1;
+        }
+
+      if (auxv.a_type == AT_HWCAP2)
+        {
+          stored_hwcap2 = auxv.a_val;
+          hwcap_initialized = 1;
+        }
     }
 
+  if (hwcap_initialized)
+    err = 0;
+
   fclose(f);
   *hwcap = stored_hwcap;
+  *hwcap2 = stored_hwcap2;
   return err;
 }
 
@@ -82,29 +149,34 @@ static unsigned int
 detect_arm_at_hwcap(void)
 {
   unsigned int hwcap;
+  unsigned int hwcap2;
   unsigned int features = 0;
+  unsigned int i;
 
-  if (get_hwcap(&hwcap) < 0)
+  if (get_hwcap(&hwcap, &hwcap2) < 0)
     return features;
 
-#ifdef ENABLE_NEON_SUPPORT
-  if (hwcap & HWCAP_NEON)
-    features |= HWF_ARM_NEON;
-#endif
+  for (i = 0; i < DIM(arm_features); i++)
+    {
+      if (hwcap & arm_features[i].hwcap_flag)
+        features |= arm_features[i].hwf_flag;
+
+      if (hwcap2 & arm_features[i].hwcap2_flag)
+        features |= arm_features[i].hwf_flag;
+    }
 
   return features;
 }
 
-#define HAS_PROC_CPUINFO 1
-
 static unsigned int
 detect_arm_proc_cpuinfo(unsigned int *broken_hwfs)
 {
   char buf[1024]; /* large enough */
-  char *str_features, *str_neon;
+  char *str_features, *str_feat;
   int cpu_implementer, cpu_arch, cpu_variant, cpu_part, cpu_revision;
   FILE *f;
   int readlen, i;
+  size_t mlen;
   static int cpuinfo_initialized = 0;
   static unsigned int stored_cpuinfo_features;
   static unsigned int stored_broken_hwfs;
@@ -162,7 +234,11 @@ detect_arm_proc_cpuinfo(unsigned int *broken_hwfs)
         continue;
 
       str += 2;
-      *cpu_entries[i].value = strtoul(str, NULL, 0);
+      if (strcmp(cpu_entries[i].name, "CPU architecture") == 0
+          && strcmp(str, "AArch64") == 0)
+        *cpu_entries[i].value = 8;
+      else
+        *cpu_entries[i].value = strtoul(str, NULL, 0);
     }
 
   /* Lines to strings. */
@@ -170,10 +246,19 @@ detect_arm_proc_cpuinfo(unsigned int *broken_hwfs)
     if (buf[i] == '\n')
       buf[i] = '\0';
 
-  /* Check for NEON. */
-  str_neon = strstr(str_features, " neon");
-  if (str_neon && (str_neon[5] == ' ' || str_neon[5] == '\0'))
-    stored_cpuinfo_features |= HWF_ARM_NEON;
+  /* Check features. */
+  for (i = 0; i < DIM(arm_features); i++)
+    {
+      str_feat = strstr(str_features, arm_features[i].feature_match);
+      if (str_feat)
+        {
+          mlen = strlen(arm_features[i].feature_match);
+          if (str_feat[mlen] == ' ' || str_feat[mlen] == '\0')
+            {
+              stored_cpuinfo_features |= arm_features[i].hwf_flag;
+            }
+        }
+    }
 
   /* Check for CPUs with broken NEON implementation. See
    * https://code.google.com/p/chromium/issues/detail?id=341598
@@ -207,7 +292,7 @@ _gcry_hwf_detect_arm (void)
   ret |= detect_arm_proc_cpuinfo (&broken_hwfs);
 #endif
 
-#if defined(__ARM_NEON__) && defined(ENABLE_NEON_SUPPORT)
+#if defined(__ARM_NEON) && defined(ENABLE_NEON_SUPPORT)
   ret |= HWF_ARM_NEON;
 #endif
 
index 4cafae1..07221e8 100644 (file)
@@ -56,7 +56,11 @@ static struct
     { HWF_INTEL_RDRAND,    "intel-rdrand" },
     { HWF_INTEL_AVX,       "intel-avx" },
     { HWF_INTEL_AVX2,      "intel-avx2" },
-    { HWF_ARM_NEON,        "arm-neon" }
+    { HWF_ARM_NEON,        "arm-neon" },
+    { HWF_ARM_AES,         "arm-aes" },
+    { HWF_ARM_SHA1,        "arm-sha1" },
+    { HWF_ARM_SHA2,        "arm-sha2" },
+    { HWF_ARM_PMULL,       "arm-pmull" }
   };
 
 /* A bit vector with the hardware features which shall not be used.