Botan 3.6.1
Crypto and TLS for C&
cpuid_aarch64.cpp
Go to the documentation of this file.
1/*
2* Runtime CPU detection for Aarch64
3* (C) 2009,2010,2013,2017,2020,2024 Jack Lloyd
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#include <botan/internal/cpuid.h>
9
10#if defined(BOTAN_TARGET_ARCH_IS_ARM64)
11 #include <botan/internal/os_utils.h>
12#endif
13
14#if defined(BOTAN_TARGET_OS_HAS_SYSCTLBYNAME)
15 #include <sys/sysctl.h>
16 #include <sys/types.h>
17#endif
18
19namespace Botan {
20
21#if defined(BOTAN_TARGET_ARCH_IS_ARM64)
22
23uint32_t CPUID::CPUID_Data::detect_cpu_features(uint32_t allowed) {
24 if(OS::has_auxval()) {
25 uint32_t feat = 0;
26
27 /*
28 * On systems with getauxval these bits should normally be defined
29 * in bits/auxv.h but some buggy? glibc installs seem to miss them.
30 * These following values are all fixed, for the Linux ELF format,
31 * so we just hardcode them in ARM_hwcap_bit enum.
32 */
33 enum class ARM_hwcap_bit : uint64_t {
34 NEON_bit = (1 << 1),
35 AES_bit = (1 << 3),
36 PMULL_bit = (1 << 4),
37 SHA1_bit = (1 << 5),
38 SHA2_bit = (1 << 6),
39 SHA3_bit = (1 << 17),
40 SM3_bit = (1 << 18),
41 SM4_bit = (1 << 19),
42 SHA2_512_bit = (1 << 21),
43 SVE_bit = (1 << 22),
44 };
45
46 const uint64_t hwcap = OS::get_auxval(OS::auxval_hwcap());
47
48 feat |= if_set(hwcap, ARM_hwcap_bit::NEON_bit, CPUID::CPUID_ARM_NEON_BIT, allowed);
49
50 if(feat & CPUID::CPUID_ARM_NEON_BIT) {
51 feat |= if_set(hwcap, ARM_hwcap_bit::AES_bit, CPUID::CPUID_ARM_AES_BIT, allowed);
52 feat |= if_set(hwcap, ARM_hwcap_bit::PMULL_bit, CPUID::CPUID_ARM_PMULL_BIT, allowed);
53 feat |= if_set(hwcap, ARM_hwcap_bit::SHA1_bit, CPUID::CPUID_ARM_SHA1_BIT, allowed);
54 feat |= if_set(hwcap, ARM_hwcap_bit::SHA2_bit, CPUID::CPUID_ARM_SHA2_BIT, allowed);
55 feat |= if_set(hwcap, ARM_hwcap_bit::SHA3_bit, CPUID::CPUID_ARM_SHA3_BIT, allowed);
56 feat |= if_set(hwcap, ARM_hwcap_bit::SM3_bit, CPUID::CPUID_ARM_SM3_BIT, allowed);
57 feat |= if_set(hwcap, ARM_hwcap_bit::SM4_bit, CPUID::CPUID_ARM_SM4_BIT, allowed);
58 feat |= if_set(hwcap, ARM_hwcap_bit::SHA2_512_bit, CPUID::CPUID_ARM_SHA2_512_BIT, allowed);
59 feat |= if_set(hwcap, ARM_hwcap_bit::SVE_bit, CPUID::CPUID_ARM_SVE_BIT, allowed);
60 }
61
62 return feat;
63 }
64
65 uint32_t feat = 0;
66
67 #if defined(BOTAN_TARGET_OS_IS_IOS) || defined(BOTAN_TARGET_OS_IS_MACOS)
68
69 auto sysctlbyname_has_feature = [](const char* feature_name) -> bool {
70 unsigned int feature;
71 size_t size = sizeof(feature);
72 ::sysctlbyname(feature_name, &feature, &size, nullptr, 0);
73 return (feature == 1);
74 };
75
76 // All 64-bit Apple ARM chips have NEON, AES, and SHA support
77 feat |= CPUID::CPUID_ARM_NEON_BIT & allowed;
78 if(feat & CPUID::CPUID_ARM_NEON_BIT) {
79 feat |= CPUID::CPUID_ARM_AES_BIT & allowed;
80 feat |= CPUID::CPUID_ARM_PMULL_BIT & allowed;
81 feat |= CPUID::CPUID_ARM_SHA1_BIT & allowed;
82 feat |= CPUID::CPUID_ARM_SHA2_BIT & allowed;
83
84 if(sysctlbyname_has_feature("hw.optional.armv8_2_sha3")) {
85 feat |= CPUID::CPUID_ARM_SHA3_BIT & allowed;
86 }
87 if(sysctlbyname_has_feature("hw.optional.armv8_2_sha512")) {
88 feat |= CPUID::CPUID_ARM_SHA2_512_BIT & allowed;
89 }
90 }
91
92 #elif defined(BOTAN_USE_GCC_INLINE_ASM)
93
94 /*
95 No getauxval API available, fall back on probe functions.
96 NEON registers v0-v7 are caller saved in Aarch64
97 */
98
99 auto neon_probe = []() noexcept -> int {
100 asm("and v0.16b, v0.16b, v0.16b");
101 return 1;
102 };
103 auto aes_probe = []() noexcept -> int {
104 asm(".word 0x4e284800");
105 return 1;
106 };
107 auto pmull_probe = []() noexcept -> int {
108 asm(".word 0x0ee0e000");
109 return 1;
110 };
111 auto sha1_probe = []() noexcept -> int {
112 asm(".word 0x5e280800");
113 return 1;
114 };
115 auto sha2_probe = []() noexcept -> int {
116 asm(".word 0x5e282800");
117 return 1;
118 };
119 auto sha512_probe = []() noexcept -> int {
120 asm(".long 0xcec08000");
121 return 1;
122 };
123
124 if(allowed & CPUID::CPUID_ARM_NEON_BIT) {
125 if(OS::run_cpu_instruction_probe(neon_probe) == 1) {
126 feat |= CPUID::CPUID_ARM_NEON_BIT;
127 }
128
129 if(feat & CPUID::CPUID_ARM_NEON_BIT) {
130 if(OS::run_cpu_instruction_probe(aes_probe) == 1) {
131 feat |= CPUID::CPUID_ARM_AES_BIT & allowed;
132 }
133 if(OS::run_cpu_instruction_probe(pmull_probe) == 1) {
134 feat |= CPUID::CPUID_ARM_PMULL_BIT & allowed;
135 }
136 if(OS::run_cpu_instruction_probe(sha1_probe) == 1) {
137 feat |= CPUID::CPUID_ARM_SHA1_BIT & allowed;
138 }
139 if(OS::run_cpu_instruction_probe(sha2_probe) == 1) {
140 feat |= CPUID::CPUID_ARM_SHA2_BIT & allowed;
141 }
142 if(OS::run_cpu_instruction_probe(sha512_probe) == 1) {
143 feat |= CPUID::CPUID_ARM_SHA2_512_BIT & allowed;
144 }
145 }
146 }
147
148 #endif
149
150 return feat;
151}
152
153#endif
154
155} // namespace Botan
unsigned long auxval_hwcap()
Definition os_utils.cpp:136
bool has_auxval()
Definition os_utils.cpp:124
int BOTAN_TEST_API run_cpu_instruction_probe(const std::function< int()> &probe_fn)
Definition os_utils.cpp:716
unsigned long get_auxval(unsigned long id)
Definition os_utils.cpp:156