8#include <botan/internal/cpuid.h>
10#include <botan/assert.h>
11#include <botan/internal/target_info.h>
14#if defined(BOTAN_HAS_OS_UTILS)
15 #include <botan/internal/os_utils.h>
18#if defined(BOTAN_TARGET_OS_HAS_SYSCTLBYNAME)
19 #include <sys/sysctl.h>
20 #include <sys/types.h>
27std::optional<uint32_t> aarch64_feat_via_auxval(uint32_t allowed) {
28#if defined(BOTAN_HAS_OS_UTILS)
39 enum class ARM_hwcap_bit : uint64_t {
48 SHA2_512_bit = (1 << 21),
52 const auto hwcap = auxval->first;
54 feat |=
CPUID::if_set(hwcap, ARM_hwcap_bit::NEON_bit, CPUFeature::Bit::NEON, allowed);
56 if((feat & CPUFeature::Bit::NEON) == CPUFeature::Bit::NEON) {
57 feat |=
CPUID::if_set(hwcap, ARM_hwcap_bit::AES_bit, CPUFeature::Bit::AES, allowed);
58 feat |=
CPUID::if_set(hwcap, ARM_hwcap_bit::PMULL_bit, CPUFeature::Bit::PMULL, allowed);
59 feat |=
CPUID::if_set(hwcap, ARM_hwcap_bit::SHA1_bit, CPUFeature::Bit::SHA1, allowed);
60 feat |=
CPUID::if_set(hwcap, ARM_hwcap_bit::SHA2_bit, CPUFeature::Bit::SHA2, allowed);
61 feat |=
CPUID::if_set(hwcap, ARM_hwcap_bit::SHA3_bit, CPUFeature::Bit::SHA3, allowed);
62 feat |=
CPUID::if_set(hwcap, ARM_hwcap_bit::SM3_bit, CPUFeature::Bit::SM3, allowed);
63 feat |=
CPUID::if_set(hwcap, ARM_hwcap_bit::SM4_bit, CPUFeature::Bit::SM4, allowed);
64 feat |=
CPUID::if_set(hwcap, ARM_hwcap_bit::SHA2_512_bit, CPUFeature::Bit::SHA2_512, allowed);
65 feat |=
CPUID::if_set(hwcap, ARM_hwcap_bit::SVE_bit, CPUFeature::Bit::SVE, allowed);
77std::optional<uint32_t> aarch64_feat_using_mac_api(uint32_t allowed) {
78#if defined(BOTAN_TARGET_OS_IS_IOS) || defined(BOTAN_TARGET_OS_IS_MACOS)
81 auto sysctlbyname_has_feature = [](
const char* feature_name) ->
bool {
82 unsigned int feature = 0;
83 size_t size =
sizeof(feature);
84 if(::sysctlbyname(feature_name, &feature, &size,
nullptr, 0) == 0) {
85 return (feature == 1);
92 feat |= CPUFeature::Bit::NEON & allowed;
93 if((feat & CPUFeature::Bit::NEON) == CPUFeature::Bit::NEON) {
94 feat |= CPUFeature::Bit::AES & allowed;
95 feat |= CPUFeature::Bit::PMULL & allowed;
96 feat |= CPUFeature::Bit::SHA1 & allowed;
97 feat |= CPUFeature::Bit::SHA2 & allowed;
99 if(sysctlbyname_has_feature(
"hw.optional.armv8_2_sha3")) {
100 feat |= CPUFeature::Bit::SHA3 & allowed;
102 if(sysctlbyname_has_feature(
"hw.optional.armv8_2_sha512")) {
103 feat |= CPUFeature::Bit::SHA2_512 & allowed;
114std::optional<uint32_t> aarch64_feat_using_instr_probe(uint32_t allowed) {
115#if defined(BOTAN_USE_GCC_INLINE_ASM) && defined(BOTAN_HAS_OS_UTILS)
124 auto neon_probe = []()
noexcept ->
int {
125 asm(
"and v0.16b, v0.16b, v0.16b");
128 auto aes_probe = []()
noexcept ->
int {
129 asm(
".word 0x4e284800");
132 auto pmull_probe = []()
noexcept ->
int {
133 asm(
".word 0x0ee0e000");
136 auto sha1_probe = []()
noexcept ->
int {
137 asm(
".word 0x5e280800");
140 auto sha2_probe = []()
noexcept ->
int {
141 asm(
".word 0x5e282800");
144 auto sha512_probe = []()
noexcept ->
int {
145 asm(
".long 0xcec08000");
152 if((allowed & CPUFeature::Bit::NEON) == CPUFeature::Bit::NEON) {
154 feat |= CPUFeature::Bit::NEON;
157 feat |= CPUFeature::Bit::AES & allowed;
160 feat |= CPUFeature::Bit::PMULL & allowed;
163 feat |= CPUFeature::Bit::SHA1 & allowed;
166 feat |= CPUFeature::Bit::SHA2 & allowed;
169 feat |= CPUFeature::Bit::SHA2_512 & allowed;
183uint32_t CPUID::CPUID_Data::detect_cpu_features(uint32_t allowed) {
184 if(
auto feat_aux = aarch64_feat_via_auxval(allowed)) {
185 return feat_aux.value();
186 }
else if(
auto feat_mac = aarch64_feat_using_mac_api(allowed)) {
187 return feat_mac.value();
188 }
else if(
auto feat_instr = aarch64_feat_using_instr_probe(allowed)) {
189 return feat_instr.value();
static uint32_t if_set(uint64_t cpuid, T flag, CPUID::Feature 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)