>From 184cc27c1592eea98f3bcb7e48a32bf97e126709 Mon Sep 17 00:00:00 2001
From: "Yuriy M. Kaminskiy" <yumkam@gmail.com>
Date: Sun, 10 Mar 2019 12:25:21 +0300
Subject: [PATCH] fat-arm.c: prefer getauxval() over /proc/cpuinfo parsing

When getauxval() is present (glibc 2.16+), avoid slow and unreliable
/proc/cpuinfo parsing.

Use compile-time ARM archeticture as a fallback.

Use VFPv3 as fallback to ARMv7 detection when AT_PLATFORM is not
recognized (NEON implies VFPv3 with VFPD32; VFPv4 implies VFPv3;
when NEON present, VFPv4 implies NEONv2; VFPv3 implies armv7)
---
 configure.ac |  4 ++++
 fat-arm.c    | 32 ++++++++++++++++++++++++++++++++
 2 files changed, 36 insertions(+)

diff --git a/configure.ac b/configure.ac
index 4a482bdd..76fabfef 100644
--- a/configure.ac
+++ b/configure.ac
@@ -193,6 +193,10 @@ AC_CHECK_HEADERS([openssl/evp.h openssl/ecdsa.h],,
 [enable_openssl=no
  break])
 
+# For --enable-fat on arm
+AC_CHECK_HEADERS([sys/auxv.h])
+AC_CHECK_FUNCS(getauxval)
+
 # For use by the testsuite
 AC_CHECK_HEADERS([valgrind/memcheck.h])
 AC_CHECK_HEADERS([dlfcn.h])
diff --git a/fat-arm.c b/fat-arm.c
index 6e4c8622..cdc137a2 100644
--- a/fat-arm.c
+++ b/fat-arm.c
@@ -40,6 +40,15 @@
 #include <stdlib.h>
 #include <string.h>
 
+#ifdef HAVE_SYS_AUXV_H
+#include <sys/auxv.h>
+#if !defined(AT_HWCAP) || !defined(HWCAP_ARM_NEON) || !defined(AT_PLATFORM)
+#undef HAVE_GETAUXVAL
+#endif
+#else
+#undef HAVE_GETAUXVAL
+#endif
+
 #include "nettle-types.h"
 
 #include "aes-internal.h"
@@ -64,7 +73,11 @@ static void
 get_arm_features (struct arm_features *features)
 {
   const char *s;
+#if __ARM_ARCH > 5 /* use compile-time arch as fallback */
+  features->arch_version = __ARM_ARCH;
+#else
   features->arch_version = 5;
+#endif
   features->have_neon = 0;
 
   s = secure_getenv (ENV_OVERRIDE);
@@ -87,6 +100,24 @@ get_arm_features (struct arm_features *features)
       }
   else
     {
+#if defined(HAVE_GETAUXVAL)
+      unsigned long hwcap = getauxval(AT_HWCAP);
+      const char *platform = (const char *)getauxval(AT_PLATFORM);
+
+      if (platform != NULL && platform[0] == 'v' &&
+	  (platform[1] >= '0' && platform[1] <= '9') &&
+	  (platform[2] == 'l' || platform[2] == 'b'))
+	features->arch_version = platform[1] - '0';
+      else
+        {
+	  /* fallback to VFPv3 as a proxy for armv7 detection */
+	  if (features->arch_version < 7 && (hwcap & HWCAP_ARM_VFPv3))
+	    features->arch_version = 7;
+	}
+
+      if ((hwcap & HWCAP_ARM_NEON))
+	features->have_neon = 1;
+#else
       FILE *f;
       char line[200];
       int seen_arch = 0;
@@ -132,6 +163,7 @@ get_arm_features (struct arm_features *features)
 	  features->have_neon = 1;
 	}
       fclose (f);
+#endif
     }
 }
 
-- 
2.11.0

