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