arm64: Implement baremetal OPENSSL_cpuid_setup Provide an implementation of OPENSSL_cpuid_setup() which identifies the available CPU features required by the library directly from the system registers for baremetal AArch64 builds without static initializer (OPENSSL_NO_STATIC_INITIALIZER) that don't configure static capabilities (OPENSSL_STATIC_ARMCAP). This assumes that the client code is NOT running at exception level EL0 (userspace) and is enabled for ANDROID_BAREMETAL. Bug: b:265125189 Change-Id: Ifee6fbd24ece823a4661dd984f89473e1e1e3eda Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/58586 Reviewed-by: David Benjamin <davidben@google.com> Commit-Queue: Bob Beck <bbe@google.com>
diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt index f0c892f..c7eb598 100644 --- a/crypto/CMakeLists.txt +++ b/crypto/CMakeLists.txt
@@ -131,6 +131,7 @@ cpu_aarch64_openbsd.c cpu_aarch64_fuchsia.c cpu_aarch64_linux.c + cpu_aarch64_sysreg.c cpu_aarch64_win.c cpu_arm_freebsd.c cpu_arm_openbsd.c
diff --git a/crypto/cpu_aarch64_sysreg.c b/crypto/cpu_aarch64_sysreg.c new file mode 100644 index 0000000..8f85e8a --- /dev/null +++ b/crypto/cpu_aarch64_sysreg.c
@@ -0,0 +1,91 @@ +/* Copyright (c) 2023, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include "internal.h" + +#if defined(OPENSSL_AARCH64) && !defined(OPENSSL_STATIC_ARMCAP) && \ + defined(ANDROID_BAREMETAL) + +#include <openssl/arm_arch.h> + +#define ID_AA64PFR0_EL1_ADVSIMD 5 + +#define ID_AA64ISAR0_EL1_AES 1 +#define ID_AA64ISAR0_EL1_SHA1 2 +#define ID_AA64ISAR0_EL1_SHA2 3 + +#define NBITS_ID_FIELD 4 + +#define READ_SYSREG(name) \ + ({ \ + uint64_t _r; \ + __asm__("mrs %0, " name : "=r"(_r)); \ + _r; \ + }) + +static unsigned get_id_field(uint64_t reg, unsigned field) { + return (reg >> (field * NBITS_ID_FIELD)) & ((1 << NBITS_ID_FIELD) - 1); +} + +static int get_signed_id_field(uint64_t reg, unsigned field) { + unsigned value = get_id_field(reg, field); + if (value & (1 << (NBITS_ID_FIELD - 1))) { + return (int)(value | (UINT64_MAX << NBITS_ID_FIELD)); + } else { + return (int)value; + } +} + +static uint32_t read_armcap(void) { + uint32_t armcap = ARMV7_NEON; + + uint64_t id_aa64pfr0_el1 = READ_SYSREG("id_aa64pfr0_el1"); + + if (get_signed_id_field(id_aa64pfr0_el1, ID_AA64PFR0_EL1_ADVSIMD) < 0) { + // If AdvSIMD ("NEON") is missing, don't report other features either. + // This matches OpenSSL. + return 0; + } + + uint64_t id_aa64isar0_el1 = READ_SYSREG("id_aa64isar0_el1"); + + unsigned aes = get_id_field(id_aa64isar0_el1, ID_AA64ISAR0_EL1_AES); + if (aes > 0) { + armcap |= ARMV8_AES; + } + if (aes > 1) { + armcap |= ARMV8_PMULL; + } + + unsigned sha1 = get_id_field(id_aa64isar0_el1, ID_AA64ISAR0_EL1_SHA1); + if (sha1 > 0) { + armcap |= ARMV8_SHA1; + } + + unsigned sha2 = get_id_field(id_aa64isar0_el1, ID_AA64ISAR0_EL1_SHA2); + if (sha2 > 0) { + armcap |= ARMV8_SHA256; + } + if (sha2 > 1) { + armcap |= ARMV8_SHA512; + } + + return armcap; +} + +extern uint32_t OPENSSL_armcap_P; + +void OPENSSL_cpuid_setup(void) { OPENSSL_armcap_P |= read_armcap(); } + +#endif // OPENSSL_AARCH64 && !OPENSSL_STATIC_ARMCAP && ANDROID_BAREMETAL