Make mbedtls_aesce_has_support more efficient

Signed-off-by: Dave Rodgman <dave.rodgman@arm.com>
diff --git a/library/aesce.c b/library/aesce.c
index 8aa0789..42e04d3 100644
--- a/library/aesce.c
+++ b/library/aesce.c
@@ -94,28 +94,40 @@
 #endif /* !(__ARM_FEATURE_CRYPTO || __ARM_FEATURE_AES) ||
           MBEDTLS_ENABLE_ARM_CRYPTO_EXTENSIONS_COMPILER_FLAG */
 
-#if defined(__linux__)
+#if defined(__linux__) && !defined(MBEDTLS_AES_USE_HARDWARE_ONLY)
+
 #include <asm/hwcap.h>
 #include <sys/auxv.h>
-#endif
+
+char mbedtls_aesce_has_support_result = 2;
 
 #if !defined(MBEDTLS_AES_USE_HARDWARE_ONLY)
 /*
  * AES instruction support detection routine
  */
-int mbedtls_aesce_has_support(void)
+int mbedtls_aesce_has_support_impl(void)
 {
-#if defined(__linux__)
-    unsigned long auxval = getauxval(AT_HWCAP);
-    return (auxval & (HWCAP_ASIMD | HWCAP_AES)) ==
-           (HWCAP_ASIMD | HWCAP_AES);
-#else
-    /* Assume AES instructions are supported. */
-    return 1;
-#endif
+    /* To avoid many calls to getauxval, cache the result. This is
+     * thread-safe, because we store the result in a char so cannot
+     * be vulnerable to non-atomic updates.
+     * It is possible that we could end up setting result more than
+     * once, but that is harmless.
+     */
+    if (mbedtls_aesce_has_support_result == 2) {
+        unsigned long auxval = getauxval(AT_HWCAP);
+        if ((auxval & (HWCAP_ASIMD | HWCAP_AES)) ==
+            (HWCAP_ASIMD | HWCAP_AES)) {
+            mbedtls_aesce_has_support_result = 1;
+        } else {
+            mbedtls_aesce_has_support_result = 0;
+        }
+    }
+    return mbedtls_aesce_has_support_result;
 }
 #endif
 
+#endif /* defined(__linux__) && !defined(MBEDTLS_AES_USE_HARDWARE_ONLY) */
+
 /* Single round of AESCE encryption */
 #define AESCE_ENCRYPT_ROUND                   \
     block = vaeseq_u8(block, vld1q_u8(keys)); \
diff --git a/library/aesce.h b/library/aesce.h
index 9b8b0bc..1a0abb8 100644
--- a/library/aesce.h
+++ b/library/aesce.h
@@ -42,17 +42,29 @@
 extern "C" {
 #endif
 
+#if defined(__linux__) && !defined(MBEDTLS_AES_USE_HARDWARE_ONLY)
+
+extern char mbedtls_aesce_has_support_result;
+
 /**
  * \brief          Internal function to detect the crypto extension in CPUs.
  *
  * \return         1 if CPU has support for the feature, 0 otherwise
  */
-#if !defined(MBEDTLS_AES_USE_HARDWARE_ONLY)
-int mbedtls_aesce_has_support(void);
-#else
-#define mbedtls_aesce_has_support() 1
-#endif
+int mbedtls_aesce_has_support_impl(void);
 
+#define mbedtls_aesce_has_support() (mbedtls_aesce_has_support_result == 2 ? \
+                                     mbedtls_aesce_has_support_impl() : \
+                                     mbedtls_aesce_has_support_result)
+
+#else /* defined(__linux__) && !defined(MBEDTLS_AES_USE_HARDWARE_ONLY) */
+
+/* If we are not on Linux, we can't detect support so assume that it's supported.
+ * Similarly, assume support if MBEDTLS_AES_USE_HARDWARE_ONLY is set.
+ */
+#define mbedtls_aesce_has_support() 1
+
+#endif /* defined(__linux__) && !defined(MBEDTLS_AES_USE_HARDWARE_ONLY) */
 
 /**
  * \brief          Internal AES-ECB block encryption and decryption