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