diff --git a/library/aesce.c b/library/aesce.c index 8aa07894f..42e04d3a4 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 #include -#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 9b8b0bcd6..1a0abb86f 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