8#include <botan/cpuid.h>
10#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
12#if defined(BOTAN_TARGET_OS_IS_IOS)
13 #include <sys/types.h>
14 #include <sys/sysctl.h>
17 #include <botan/internal/os_utils.h>
19#if defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) || defined(BOTAN_TARGET_OS_HAS_ELF_AUX_INFO)
29#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY)
31#if defined(BOTAN_TARGET_OS_IS_IOS)
35uint64_t flags_by_ios_machine_type(
const std::string& machine)
45 size_t min_version_neon;
46 size_t min_version_armv8;
49 static const version_info min_versions[] = {
56 if(machine.size() < 3)
59 auto comma = machine.find(
',');
62 if(comma == std::string::npos)
65 std::string product = machine.substr(0, comma);
69 while(product.size() > 1 && ::isdigit(product.back()))
71 const size_t digit = product.back() -
'0';
72 version += digit * place;
80 for(
const version_info& info : min_versions)
82 if(info.name != product)
85 if(version >= info.min_version_armv8)
87 return CPUID::CPUID_ARM_AES_BIT |
88 CPUID::CPUID_ARM_PMULL_BIT |
89 CPUID::CPUID_ARM_SHA1_BIT |
90 CPUID::CPUID_ARM_SHA2_BIT |
91 CPUID::CPUID_ARM_NEON_BIT;
94 if(version >= info.min_version_neon)
95 return CPUID::CPUID_ARM_NEON_BIT;
106uint64_t CPUID::CPUID_Data::detect_cpu_features(
size_t* cache_line_size)
110 uint64_t detected_features = 0;
112#if defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) || defined(BOTAN_TARGET_OS_HAS_ELF_AUX_INFO)
121#if defined(BOTAN_TARGET_ARCH_IS_ARM32)
122 NEON_bit = (1 << 12),
124 PMULL_bit = (1 << 1),
128 ARCH_hwcap_neon = 16,
129 ARCH_hwcap_crypto = 26,
130#elif defined(BOTAN_TARGET_ARCH_IS_ARM64)
133 PMULL_bit = (1 << 4),
136 SHA3_bit = (1 << 17),
139 SHA2_512_bit = (1 << 21),
142 ARCH_hwcap_neon = 16,
143 ARCH_hwcap_crypto = 16,
147#if defined(AT_DCACHEBSIZE)
152 if(dcache_line == 32 || dcache_line == 64 || dcache_line == 128)
153 *cache_line_size =
static_cast<size_t>(dcache_line);
156 const unsigned long hwcap_neon =
OS::get_auxval(ARM_hwcap_bit::ARCH_hwcap_neon);
157 if(hwcap_neon & ARM_hwcap_bit::NEON_bit)
158 detected_features |= CPUID::CPUID_ARM_NEON_BIT;
165 const unsigned long hwcap_crypto =
OS::get_auxval(ARM_hwcap_bit::ARCH_hwcap_crypto);
166 if(hwcap_crypto & ARM_hwcap_bit::AES_bit)
167 detected_features |= CPUID::CPUID_ARM_AES_BIT;
168 if(hwcap_crypto & ARM_hwcap_bit::PMULL_bit)
169 detected_features |= CPUID::CPUID_ARM_PMULL_BIT;
170 if(hwcap_crypto & ARM_hwcap_bit::SHA1_bit)
171 detected_features |= CPUID::CPUID_ARM_SHA1_BIT;
172 if(hwcap_crypto & ARM_hwcap_bit::SHA2_bit)
173 detected_features |= CPUID::CPUID_ARM_SHA2_BIT;
175#if defined(BOTAN_TARGET_ARCH_IS_ARM64)
176 if(hwcap_crypto & ARM_hwcap_bit::SHA3_bit)
177 detected_features |= CPUID::CPUID_ARM_SHA3_BIT;
178 if(hwcap_crypto & ARM_hwcap_bit::SM3_bit)
179 detected_features |= CPUID::CPUID_ARM_SM3_BIT;
180 if(hwcap_crypto & ARM_hwcap_bit::SM4_bit)
181 detected_features |= CPUID::CPUID_ARM_SM4_BIT;
182 if(hwcap_crypto & ARM_hwcap_bit::SHA2_512_bit)
183 detected_features |= CPUID::CPUID_ARM_SHA2_512_BIT;
184 if(hwcap_crypto & ARM_hwcap_bit::SVE_bit)
185 detected_features |= CPUID::CPUID_ARM_SVE_BIT;
188#elif defined(BOTAN_TARGET_OS_IS_IOS)
190 char machine[64] = { 0 };
191 size_t size =
sizeof(machine) - 1;
192 ::sysctlbyname(
"hw.machine", machine, &size,
nullptr, 0);
194 detected_features = flags_by_ios_machine_type(machine);
197#elif defined(BOTAN_USE_GCC_INLINE_ASM) && defined(BOTAN_TARGET_ARCH_IS_ARM64)
208 auto neon_probe = []()
noexcept ->
int {
asm(
"and v0.16b, v0.16b, v0.16b");
return 1; };
209 auto aes_probe = []()
noexcept ->
int {
asm(
".word 0x4e284800");
return 1; };
210 auto pmull_probe = []()
noexcept ->
int {
asm(
".word 0x0ee0e000");
return 1; };
211 auto sha1_probe = []()
noexcept ->
int {
asm(
".word 0x5e280800");
return 1; };
212 auto sha2_probe = []()
noexcept ->
int {
asm(
".word 0x5e282800");
return 1; };
218 detected_features |= CPUID::CPUID_ARM_NEON_BIT;
221 detected_features |= CPUID::CPUID_ARM_AES_BIT;
223 detected_features |= CPUID::CPUID_ARM_PMULL_BIT;
225 detected_features |= CPUID::CPUID_ARM_SHA1_BIT;
227 detected_features |= CPUID::CPUID_ARM_SHA2_BIT;
232 return detected_features;
#define BOTAN_UNUSED(...)
unsigned long get_auxval(unsigned long id)
int BOTAN_TEST_API run_cpu_instruction_probe(std::function< int()> probe_fn)