Botan 3.4.0
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 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
12 #include <botan/internal/os_utils.h>
13
14 #if defined(BOTAN_TARGET_OS_IS_IOS) || defined(BOTAN_TARGET_OS_IS_MACOS)
15 #include <sys/sysctl.h>
16 #include <sys/types.h>
17 #endif
18
19namespace Botan {
20
21 #if defined(BOTAN_TARGET_OS_IS_MACOS)
22namespace {
23
24bool sysctlbyname_has_feature(const char* feature_name) {
25 unsigned int feature;
26 size_t size = sizeof(feature);
27 ::sysctlbyname(feature_name, &feature, &size, nullptr, 0);
28 return (feature == 1);
29}
30
31} // namespace
32 #endif
33
34uint32_t CPUID::CPUID_Data::detect_cpu_features() {
35 uint32_t detected_features = 0;
36
37 #if defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) || defined(BOTAN_TARGET_OS_HAS_ELF_AUX_INFO)
38 /*
39 * On systems with getauxval these bits should normally be defined
40 * in bits/auxv.h but some buggy? glibc installs seem to miss them.
41 * These following values are all fixed, for the Linux ELF format,
42 * so we just hardcode them in ARM_hwcap_bit enum.
43 */
44
45 enum ARM_hwcap_bit {
46 NEON_bit = (1 << 1),
47 AES_bit = (1 << 3),
48 PMULL_bit = (1 << 4),
49 SHA1_bit = (1 << 5),
50 SHA2_bit = (1 << 6),
51 SHA3_bit = (1 << 17),
52 SM3_bit = (1 << 18),
53 SM4_bit = (1 << 19),
54 SHA2_512_bit = (1 << 21),
55 SVE_bit = (1 << 22),
56
57 ARCH_hwcap = 16, // AT_HWCAP
58 };
59
60 const unsigned long hwcap = OS::get_auxval(ARM_hwcap_bit::ARCH_hwcap);
61 if(hwcap & ARM_hwcap_bit::NEON_bit) {
62 detected_features |= CPUID::CPUID_ARM_NEON_BIT;
63 if(hwcap & ARM_hwcap_bit::AES_bit)
64 detected_features |= CPUID::CPUID_ARM_AES_BIT;
65 if(hwcap & ARM_hwcap_bit::PMULL_bit)
66 detected_features |= CPUID::CPUID_ARM_PMULL_BIT;
67 if(hwcap & ARM_hwcap_bit::SHA1_bit)
68 detected_features |= CPUID::CPUID_ARM_SHA1_BIT;
69 if(hwcap & ARM_hwcap_bit::SHA2_bit)
70 detected_features |= CPUID::CPUID_ARM_SHA2_BIT;
71 if(hwcap & ARM_hwcap_bit::SHA3_bit)
72 detected_features |= CPUID::CPUID_ARM_SHA3_BIT;
73 if(hwcap & ARM_hwcap_bit::SM3_bit)
74 detected_features |= CPUID::CPUID_ARM_SM3_BIT;
75 if(hwcap & ARM_hwcap_bit::SM4_bit)
76 detected_features |= CPUID::CPUID_ARM_SM4_BIT;
77 if(hwcap & ARM_hwcap_bit::SHA2_512_bit)
78 detected_features |= CPUID::CPUID_ARM_SHA2_512_BIT;
79 if(hwcap & ARM_hwcap_bit::SVE_bit)
80 detected_features |= CPUID::CPUID_ARM_SVE_BIT;
81 }
82
83 #elif defined(BOTAN_TARGET_OS_IS_IOS) || defined(BOTAN_TARGET_OS_IS_MACOS)
84
85 // All 64-bit Apple ARM chips have NEON, AES, and SHA support
86 detected_features |= CPUID::CPUID_ARM_NEON_BIT;
87 detected_features |= CPUID::CPUID_ARM_AES_BIT;
88 detected_features |= CPUID::CPUID_ARM_PMULL_BIT;
89 detected_features |= CPUID::CPUID_ARM_SHA1_BIT;
90 detected_features |= CPUID::CPUID_ARM_SHA2_BIT;
91
92 #if defined(BOTAN_TARGET_OS_IS_MACOS)
93 if(sysctlbyname_has_feature("hw.optional.armv8_2_sha3"))
94 detected_features |= CPUID::CPUID_ARM_SHA3_BIT;
95 if(sysctlbyname_has_feature("hw.optional.armv8_2_sha512"))
96 detected_features |= CPUID::CPUID_ARM_SHA2_512_BIT;
97 #endif
98
99 #elif defined(BOTAN_USE_GCC_INLINE_ASM)
100
101 /*
102 No getauxval API available, fall back on probe functions. We only
103 bother with Aarch64 here to simplify the code and because going to
104 extreme contortions to detect NEON on devices that probably don't
105 support it doesn't seem worthwhile.
106
107 NEON registers v0-v7 are caller saved in Aarch64
108 */
109
110 auto neon_probe = []() noexcept -> int {
111 asm("and v0.16b, v0.16b, v0.16b");
112 return 1;
113 };
114 auto aes_probe = []() noexcept -> int {
115 asm(".word 0x4e284800");
116 return 1;
117 };
118 auto pmull_probe = []() noexcept -> int {
119 asm(".word 0x0ee0e000");
120 return 1;
121 };
122 auto sha1_probe = []() noexcept -> int {
123 asm(".word 0x5e280800");
124 return 1;
125 };
126 auto sha2_probe = []() noexcept -> int {
127 asm(".word 0x5e282800");
128 return 1;
129 };
130 auto sha512_probe = []() noexcept -> int {
131 asm(".long 0xcec08000");
132 return 1;
133 };
134
135 // Only bother running the crypto detection if we found NEON
136
137 if(OS::run_cpu_instruction_probe(neon_probe) == 1) {
138 detected_features |= CPUID::CPUID_ARM_NEON_BIT;
139
140 if(OS::run_cpu_instruction_probe(aes_probe) == 1)
141 detected_features |= CPUID::CPUID_ARM_AES_BIT;
142 if(OS::run_cpu_instruction_probe(pmull_probe) == 1)
143 detected_features |= CPUID::CPUID_ARM_PMULL_BIT;
144 if(OS::run_cpu_instruction_probe(sha1_probe) == 1)
145 detected_features |= CPUID::CPUID_ARM_SHA1_BIT;
146 if(OS::run_cpu_instruction_probe(sha2_probe) == 1)
147 detected_features |= CPUID::CPUID_ARM_SHA2_BIT;
148 if(OS::run_cpu_instruction_probe(sha512_probe) == 1)
149 detected_features |= CPUID::CPUID_ARM_SHA2_512_BIT;
150 }
151
152 #endif
153
154 return detected_features;
155}
156
157} // namespace Botan
158
159#endif
int BOTAN_TEST_API run_cpu_instruction_probe(const std::function< int()> &probe_fn)
Definition os_utils.cpp:683
unsigned long get_auxval(unsigned long id)
Definition os_utils.cpp:128