From 4d89faea78128e236933b41f53bfef8aac8de4b6 Mon Sep 17 00:00:00 2001 From: William Bo Yang Date: Mon, 31 Jul 2023 07:50:50 -0700 Subject: [PATCH] Support changing OPENSSL_armcap with environment variable on Apple 64-bit ARM systems (#1045) * use handle_cpu_env from cpu_aarch64_linux.c to cpu_aarch64_apple.c * always use OPENSSL_armcap() when detecting hardware capabilities on arm * refactor duplicated into cpu_aarch64.h/c * add ifdefs to cpu_aarch64.h/c * Update comments Co-authored-by: Nevine Ebeid <66388554+nebeid@users.noreply.github.com> * adjust line length of comment * set arm capabilities functions to fillow format of x86 ones * make rest of the arm capability functions in line with x86 ones --------- Co-authored-by: Nevine Ebeid <66388554+nebeid@users.noreply.github.com> Co-authored-by: Bill Yang --- crypto/fipsmodule/bcm.c | 1 + crypto/fipsmodule/cpucap/cpu_aarch64.c | 52 ++++++++++++++++++++ crypto/fipsmodule/cpucap/cpu_aarch64.h | 31 ++++++++++++ crypto/fipsmodule/cpucap/cpu_aarch64_apple.c | 16 ++++++ crypto/fipsmodule/cpucap/cpu_aarch64_linux.c | 51 +------------------ crypto/fipsmodule/cpucap/internal.h | 26 ---------- 6 files changed, 101 insertions(+), 76 deletions(-) create mode 100644 crypto/fipsmodule/cpucap/cpu_aarch64.c create mode 100644 crypto/fipsmodule/cpucap/cpu_aarch64.h diff --git a/crypto/fipsmodule/bcm.c b/crypto/fipsmodule/bcm.c index c85d15c59d..64d576930e 100644 --- a/crypto/fipsmodule/bcm.c +++ b/crypto/fipsmodule/bcm.c @@ -71,6 +71,7 @@ #include "cipher/e_aesccm.c" #include "cpucap/internal.h" +#include "cpucap/cpu_aarch64.c" #include "cpucap/cpu_aarch64_apple.c" #include "cpucap/cpu_aarch64_freebsd.c" #include "cpucap/cpu_aarch64_fuchsia.c" diff --git a/crypto/fipsmodule/cpucap/cpu_aarch64.c b/crypto/fipsmodule/cpucap/cpu_aarch64.c new file mode 100644 index 0000000000..7c085b7e10 --- /dev/null +++ b/crypto/fipsmodule/cpucap/cpu_aarch64.c @@ -0,0 +1,52 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +#if defined(OPENSSL_AARCH64) && !defined(OPENSSL_STATIC_ARMCAP) + +#include "cpu_aarch64.h" + +void handle_cpu_env(uint32_t *out, const char *in) { + const int invert = in[0] == '~'; + const int or = in[0] == '|'; + const int skip_first_byte = invert || or; + const int hex = in[skip_first_byte] == '0' && in[skip_first_byte+1] == 'x'; + uint32_t armcap = out[0]; + + int sscanf_result; + uint32_t v; + if (hex) { + sscanf_result = sscanf(in + skip_first_byte + 2, "%" PRIx32, &v); + } else { + sscanf_result = sscanf(in + skip_first_byte, "%" PRIu32, &v); + } + + if (!sscanf_result) { + return; + } + + // Detect if the user is trying to use the environment variable to set + // a capability that is _not_ available on the CPU: + // If the runtime capability check (e.g via getauxval() on Linux) + // returned a non-zero hwcap in `armcap` (out) + // and a bit set in the requested `v` is not set in `armcap`, + // abort instead of crashing later. + // The case of invert cannot enable an unexisting capability; + // it can only disable an existing one. + if (!invert && armcap && (~armcap & v)) + { + fprintf(stderr, + "Fatal Error: HW capability found: 0x%02X, but HW capability requested: 0x%02X.\n", + armcap, v); + exit(1); + } + + if (invert) { + out[0] &= ~v; + } else if (or) { + out[0] |= v; + } else { + out[0] = v; + } +} + +#endif // OPENSSL_AARCH64 && !OPENSSL_STATIC_ARMCAP diff --git a/crypto/fipsmodule/cpucap/cpu_aarch64.h b/crypto/fipsmodule/cpucap/cpu_aarch64.h new file mode 100644 index 0000000000..0999d58c53 --- /dev/null +++ b/crypto/fipsmodule/cpucap/cpu_aarch64.h @@ -0,0 +1,31 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +#ifndef OPENSSL_HEADER_CPUCAP_CPU_AARCH64_H +#define OPENSSL_HEADER_CPUCAP_CPU_AARCH64_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#include + +#include +#include +#include + +#if defined(OPENSSL_AARCH64) && !defined(OPENSSL_STATIC_ARMCAP) + +// cpu_aarch64 contains common functions used across multiple cpu_aarch64_* files + +// handle_cpu_env applies the value from |in| to the CPUID values in |out[0]|. +// See the comment in |OPENSSL_cpuid_setup| about this. +void handle_cpu_env(uint32_t *out, const char *in); + +#endif // OPENSSL_AARCH64 && !OPENSSL_STATIC_ARMCAP + +#if defined(__cplusplus) +} +#endif + +#endif // OPENSSL_HEADER_CPUCAP_CPU_AARCH64_H diff --git a/crypto/fipsmodule/cpucap/cpu_aarch64_apple.c b/crypto/fipsmodule/cpucap/cpu_aarch64_apple.c index f99022a72b..c62a21ba8f 100644 --- a/crypto/fipsmodule/cpucap/cpu_aarch64_apple.c +++ b/crypto/fipsmodule/cpucap/cpu_aarch64_apple.c @@ -22,6 +22,7 @@ #include +#include "cpu_aarch64.h" extern uint32_t OPENSSL_armcap_P; extern uint8_t OPENSSL_cpucap_initialized; @@ -98,6 +99,21 @@ void OPENSSL_cpuid_setup(void) { OPENSSL_armcap_P |= ARMV8_APPLE_M1; } + // OPENSSL_armcap is a 32-bit, unsigned value which may start with "0x" to + // indicate a hex value. Prior to the 32-bit value, a '~' or '|' may be given. + // + // If the '~' prefix is present: + // the value is inverted and ANDed with the probed CPUID result + // If the '|' prefix is present: + // the value is ORed with the probed CPUID result + // Otherwise: + // the value is taken as the result of the CPUID + const char *env; + env = getenv("OPENSSL_armcap"); + if (env != NULL) { + handle_cpu_env(&OPENSSL_armcap_P, env); + } + OPENSSL_cpucap_initialized = 1; } diff --git a/crypto/fipsmodule/cpucap/cpu_aarch64_linux.c b/crypto/fipsmodule/cpucap/cpu_aarch64_linux.c index b30249e294..aea4b5095a 100644 --- a/crypto/fipsmodule/cpucap/cpu_aarch64_linux.c +++ b/crypto/fipsmodule/cpucap/cpu_aarch64_linux.c @@ -22,14 +22,10 @@ #ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS #endif -#include - -#include -#include -#include #include +#include "cpu_aarch64.h" extern uint32_t OPENSSL_armcap_P; extern uint8_t OPENSSL_cpucap_initialized; @@ -40,51 +36,6 @@ static uint64_t armv8_cpuid_probe(void) { return val; } -// handle_cpu_env applies the value from |in| to the CPUID values in |out[0]|. -// See the comment in |OPENSSL_cpuid_setup| about this. -static void handle_cpu_env(uint32_t *out, const char *in) { - const int invert = in[0] == '~'; - const int or = in[0] == '|'; - const int skip_first_byte = invert || or; - const int hex = in[skip_first_byte] == '0' && in[skip_first_byte+1] == 'x'; - uint32_t armcap = out[0]; - - int sscanf_result; - uint32_t v; - if (hex) { - sscanf_result = sscanf(in + skip_first_byte + 2, "%" PRIx32, &v); - } else { - sscanf_result = sscanf(in + skip_first_byte, "%" PRIu32, &v); - } - - if (!sscanf_result) { - return; - } - - // Detect if the user is trying to use the environment variable to set - // a capability that is _not_ available on the CPU: - // If getauxval() returned a non-zero hwcap in `armcap` (out) - // and a bit set in the requested `v` is not set in `armcap`, - // abort instead of crashing later. - // The case of invert cannot enable an unexisting capability; - // it can only disable an existing one. - if (!invert && armcap && (~armcap & v)) - { - fprintf(stderr, - "Fatal Error: HW capability found: 0x%02X, but HW capability requested: 0x%02X.\n", - armcap, v); - exit(1); - } - - if (invert) { - out[0] &= ~v; - } else if (or) { - out[0] |= v; - } else { - out[0] = v; - } -} - void OPENSSL_cpuid_setup(void) { unsigned long hwcap = getauxval(AT_HWCAP); diff --git a/crypto/fipsmodule/cpucap/internal.h b/crypto/fipsmodule/cpucap/internal.h index b2ff5bbb1e..a6ccb2222f 100644 --- a/crypto/fipsmodule/cpucap/internal.h +++ b/crypto/fipsmodule/cpucap/internal.h @@ -167,52 +167,26 @@ extern uint32_t OPENSSL_armcap_P; // |CRYPTO_is_ARMv8_AES_capable| and |CRYPTO_is_ARMv8_PMULL_capable| // for checking the support for AES and PMULL instructions, respectively. OPENSSL_INLINE int CRYPTO_is_NEON_capable(void) { -#if defined(OPENSSL_STATIC_ARMCAP_NEON) || defined(__ARM_NEON) - return 1; -#elif defined(OPENSSL_STATIC_ARMCAP) - return 0; -#else return (OPENSSL_armcap_P & ARMV7_NEON) != 0; -#endif } OPENSSL_INLINE int CRYPTO_is_ARMv8_AES_capable(void) { -#if defined(OPENSSL_STATIC_ARMCAP_AES) || defined(__ARM_FEATURE_AES) - return 1; -#elif defined(OPENSSL_STATIC_ARMCAP) - return 0; -#else return (OPENSSL_armcap_P & ARMV8_AES) != 0; -#endif } OPENSSL_INLINE int CRYPTO_is_ARMv8_PMULL_capable(void) { -#if defined(OPENSSL_STATIC_ARMCAP_PMULL) || defined(__ARM_FEATURE_AES) - return 1; -#elif defined(OPENSSL_STATIC_ARMCAP) - return 0; -#else return (OPENSSL_armcap_P & ARMV8_PMULL) != 0; -#endif } OPENSSL_INLINE int CRYPTO_is_ARMv8_GCM_8x_capable(void) { -#if defined(OPENSSL_STATIC_ARMCAP) - return 0; -#else return ((OPENSSL_armcap_P & ARMV8_SHA3) != 0 && ((OPENSSL_armcap_P & ARMV8_NEOVERSE_V1) != 0 || (OPENSSL_armcap_P & ARMV8_APPLE_M1) != 0)); -#endif } OPENSSL_INLINE int CRYPTO_is_ARMv8_wide_multiplier_capable(void) { -#if defined(OPENSSL_STATIC_ARMCAP) - return 0; -#else return (OPENSSL_armcap_P & ARMV8_NEOVERSE_V1) != 0 || (OPENSSL_armcap_P & ARMV8_APPLE_M1) != 0; -#endif } #endif // OPENSSL_ARM || OPENSSL_AARCH64