8#include <botan/internal/cpuid.h>
10#include <botan/assert.h>
13#if defined(BOTAN_HAS_OS_UTILS)
14 #include <botan/internal/os_utils.h>
17#if defined(BOTAN_TARGET_OS_HAS_SYSCTLBYNAME)
18 #include <sys/sysctl.h>
19 #include <sys/types.h>
24#if defined(BOTAN_TARGET_ARCH_IS_ARM64)
28std::optional<uint32_t> aarch64_feat_via_auxval(uint32_t allowed) {
29 #if defined(BOTAN_HAS_OS_UTILS)
40 enum class ARM_hwcap_bit : uint64_t {
49 SHA2_512_bit = (1 << 21),
53 const auto hwcap = auxval->first;
55 feat |=
CPUID::if_set(hwcap, ARM_hwcap_bit::NEON_bit, CPUID::CPUID_ARM_NEON_BIT, allowed);
57 if(feat & CPUID::CPUID_ARM_NEON_BIT) {
58 feat |=
CPUID::if_set(hwcap, ARM_hwcap_bit::AES_bit, CPUID::CPUID_ARM_AES_BIT, allowed);
59 feat |=
CPUID::if_set(hwcap, ARM_hwcap_bit::PMULL_bit, CPUID::CPUID_ARM_PMULL_BIT, allowed);
60 feat |=
CPUID::if_set(hwcap, ARM_hwcap_bit::SHA1_bit, CPUID::CPUID_ARM_SHA1_BIT, allowed);
61 feat |=
CPUID::if_set(hwcap, ARM_hwcap_bit::SHA2_bit, CPUID::CPUID_ARM_SHA2_BIT, allowed);
62 feat |=
CPUID::if_set(hwcap, ARM_hwcap_bit::SHA3_bit, CPUID::CPUID_ARM_SHA3_BIT, allowed);
63 feat |=
CPUID::if_set(hwcap, ARM_hwcap_bit::SM3_bit, CPUID::CPUID_ARM_SM3_BIT, allowed);
64 feat |=
CPUID::if_set(hwcap, ARM_hwcap_bit::SM4_bit, CPUID::CPUID_ARM_SM4_BIT, allowed);
65 feat |=
CPUID::if_set(hwcap, ARM_hwcap_bit::SHA2_512_bit, CPUID::CPUID_ARM_SHA2_512_BIT, allowed);
66 feat |=
CPUID::if_set(hwcap, ARM_hwcap_bit::SVE_bit, CPUID::CPUID_ARM_SVE_BIT, allowed);
78std::optional<uint32_t> aarch64_feat_using_mac_api(uint32_t allowed) {
79 #if defined(BOTAN_TARGET_OS_IS_IOS) || defined(BOTAN_TARGET_OS_IS_MACOS)
82 auto sysctlbyname_has_feature = [](
const char* feature_name) ->
bool {
84 size_t size =
sizeof(feature);
85 ::sysctlbyname(feature_name, &feature, &size,
nullptr, 0);
86 return (feature == 1);
90 feat |= CPUID::CPUID_ARM_NEON_BIT & allowed;
91 if(feat & CPUID::CPUID_ARM_NEON_BIT) {
92 feat |= CPUID::CPUID_ARM_AES_BIT & allowed;
93 feat |= CPUID::CPUID_ARM_PMULL_BIT & allowed;
94 feat |= CPUID::CPUID_ARM_SHA1_BIT & allowed;
95 feat |= CPUID::CPUID_ARM_SHA2_BIT & allowed;
97 if(sysctlbyname_has_feature(
"hw.optional.armv8_2_sha3")) {
98 feat |= CPUID::CPUID_ARM_SHA3_BIT & allowed;
100 if(sysctlbyname_has_feature(
"hw.optional.armv8_2_sha512")) {
101 feat |= CPUID::CPUID_ARM_SHA2_512_BIT & allowed;
112std::optional<uint32_t> aarch64_feat_using_instr_probe(uint32_t allowed) {
113 #if defined(BOTAN_USE_GCC_INLINE_ASM)
120 auto neon_probe = []()
noexcept ->
int {
121 asm(
"and v0.16b, v0.16b, v0.16b");
124 auto aes_probe = []()
noexcept ->
int {
125 asm(
".word 0x4e284800");
128 auto pmull_probe = []()
noexcept ->
int {
129 asm(
".word 0x0ee0e000");
132 auto sha1_probe = []()
noexcept ->
int {
133 asm(
".word 0x5e280800");
136 auto sha2_probe = []()
noexcept ->
int {
137 asm(
".word 0x5e282800");
140 auto sha512_probe = []()
noexcept ->
int {
141 asm(
".long 0xcec08000");
146 if(allowed & CPUID::CPUID_ARM_NEON_BIT) {
148 feat |= CPUID::CPUID_ARM_NEON_BIT;
151 if(feat & CPUID::CPUID_ARM_NEON_BIT) {
153 feat |= CPUID::CPUID_ARM_AES_BIT & allowed;
156 feat |= CPUID::CPUID_ARM_PMULL_BIT & allowed;
159 feat |= CPUID::CPUID_ARM_SHA1_BIT & allowed;
162 feat |= CPUID::CPUID_ARM_SHA2_BIT & allowed;
165 feat |= CPUID::CPUID_ARM_SHA2_512_BIT & allowed;
179uint32_t CPUID::CPUID_Data::detect_cpu_features(uint32_t allowed) {
180 if(
auto feat_aux = aarch64_feat_via_auxval(allowed)) {
181 return feat_aux.value();
182 }
else if(
auto feat_mac = aarch64_feat_using_mac_api(allowed)) {
183 return feat_mac.value();
184 }
else if(
auto feat_instr = aarch64_feat_using_instr_probe(allowed)) {
185 return feat_instr.value();
static uint32_t if_set(uint64_t cpuid, T flag, CPUID::CPUID_bits bit, uint32_t allowed)
std::optional< std::pair< unsigned long, unsigned long > > get_auxval_hwcap()
int BOTAN_TEST_API run_cpu_instruction_probe(const std::function< int()> &probe_fn)