/src/wolfssl/wolfssl/wolfcrypt/cpuid.h
Line | Count | Source |
1 | | /* cpuid.h |
2 | | * |
3 | | * Copyright (C) 2006-2026 wolfSSL Inc. |
4 | | * |
5 | | * This file is part of wolfSSL. |
6 | | * |
7 | | * wolfSSL is free software; you can redistribute it and/or modify |
8 | | * it under the terms of the GNU General Public License as published by |
9 | | * the Free Software Foundation; either version 3 of the License, or |
10 | | * (at your option) any later version. |
11 | | * |
12 | | * wolfSSL is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | | * GNU General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU General Public License |
18 | | * along with this program; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA |
20 | | */ |
21 | | |
22 | | |
23 | | |
24 | | #ifndef WOLF_CRYPT_CPUID_H |
25 | | #define WOLF_CRYPT_CPUID_H |
26 | | |
27 | | |
28 | | #include <wolfssl/wolfcrypt/types.h> |
29 | | |
30 | | |
31 | | #ifdef __cplusplus |
32 | | extern "C" { |
33 | | #endif |
34 | | |
35 | | #if (defined(WOLFSSL_X86_64_BUILD) || defined(USE_INTEL_SPEEDUP) || \ |
36 | | defined(WOLFSSL_AESNI) || defined(WOLFSSL_SP_X86_64_ASM)) && \ |
37 | | !defined(WOLFSSL_NO_ASM) |
38 | | #define HAVE_CPUID |
39 | | #define HAVE_CPUID_INTEL |
40 | | #endif |
41 | | #if (defined(WOLFSSL_AARCH64_BUILD) || (defined(__aarch64__) && \ |
42 | | defined(WOLFSSL_ARMASM))) && !defined(WOLFSSL_NO_ASM) |
43 | | #define HAVE_CPUID |
44 | | #define HAVE_CPUID_AARCH64 |
45 | | #endif |
46 | | /* 32-bit Arm (AArch32). __arm__ is defined for both the A32 and Thumb |
47 | | * instruction sets but not for AArch64, so it cleanly distinguishes the 32-bit |
48 | | * build from the AArch64 one handled above. |
49 | | * |
50 | | * Thumb-2 builds - WOLFSSL_ARMASM_THUMB2, which the M profile requires - use |
51 | | * the separate thumb2-*.S assembly. It has a single implementation of each |
52 | | * algorithm and nothing to choose between at run time, so no CPU id is built |
53 | | * for it. |
54 | | * |
55 | | * The features detected (Advanced SIMD and the Armv8 crypto extension) and the |
56 | | * registers used to detect them (HWCAP, ID_ISAR5) are Armv7 and later, so the |
57 | | * older architectures - Armv4 / Armv5 / Armv6 - get no CPU id either. */ |
58 | | #if (defined(WOLFSSL_ARM32_BUILD) || (defined(__arm__) && \ |
59 | | defined(WOLFSSL_ARMASM))) && !defined(__aarch64__) && \ |
60 | | !defined(WOLFSSL_ARMASM_THUMB2) && !defined(WOLFSSL_NO_ASM) && \ |
61 | | (!defined(__ARM_ARCH) || (__ARM_ARCH >= 7)) |
62 | | #define HAVE_CPUID |
63 | | #define HAVE_CPUID_ARM32 |
64 | | #endif |
65 | | #if defined(WOLFSSL_PPC64_ASM) && !defined(WOLFSSL_NO_ASM) |
66 | | #define HAVE_CPUID |
67 | | #define HAVE_CPUID_PPC64 |
68 | | #endif |
69 | | |
70 | | #define WC_CPUID_INITIALIZER 0xffffffffU |
71 | | typedef word32 cpuid_flags_t; |
72 | | #if !defined(WOLFSSL_NO_ATOMICS) && !defined(SINGLE_THREADED) |
73 | | typedef wolfSSL_Atomic_Uint cpuid_flags_atomic_t; |
74 | | #define WC_CPUID_ATOMIC_INITIALIZER \ |
75 | | WOLFSSL_ATOMIC_INITIALIZER(WC_CPUID_INITIALIZER) |
76 | | #else |
77 | | typedef word32 cpuid_flags_atomic_t; |
78 | | #define WC_CPUID_ATOMIC_INITIALIZER WC_CPUID_INITIALIZER |
79 | | #endif |
80 | | |
81 | | #ifdef HAVE_CPUID_INTEL |
82 | | |
83 | | #define CPUID_AVX1 0x0001 |
84 | | #define CPUID_AVX2 0x0002 |
85 | | #define CPUID_RDRAND 0x0004 |
86 | | #define CPUID_RDSEED 0x0008 |
87 | | #define CPUID_BMI2 0x0010 /* MULX, RORX */ |
88 | | #define CPUID_AESNI 0x0020 |
89 | | #define CPUID_ADX 0x0040 /* ADCX, ADOX */ |
90 | | #define CPUID_MOVBE 0x0080 /* Move and byte swap */ |
91 | | #define CPUID_BMI1 0x0100 /* ANDN */ |
92 | | #define CPUID_SHA 0x0200 /* SHA-1 and SHA-256 instructions */ |
93 | | #define CPUID_VAES 0x0400 |
94 | | #define CPUID_AVX512 0x0800 |
95 | | #define CPUID_INTEL 0x1000 /* CPU vendor is GenuineIntel */ |
96 | | /* CPU vendor is AuthenticAMD. Used to pick between implementations that |
97 | | * differ only in which instructions are fast on a vendor - see the |
98 | | * VPMULLQ variant of the Curve25519 IFMA code in fe_x25519_asm.S. */ |
99 | | #define CPUID_AMD 0x2000 |
100 | | #define CPUID_AVX512_VBMI 0x4000 /* AVX-512 Vector Byte Manipulation */ |
101 | | #define CPUID_AVX512_VBMI2 0x8000 /* AVX-512 VBMI2 (vpcompressw etc.) */ |
102 | | #define CPUID_AVX512_IFMA 0x10000 /* AVX-512 IFMA (vpmadd52luq/huq) */ |
103 | | #define CPUID_AVX512_VL 0x20000 /* AVX-512 at 128 and 256 bits */ |
104 | | #define CPUID_AVX512_DQ 0x40000 /* AVX-512 DQ (vpmullq etc.) */ |
105 | | /* AVX-512 Byte and Word: byte/word instructions at 512-bit width |
106 | | * (vpshufb, vpaddw, vpmulhw, vpackusdw, ... on zmm). */ |
107 | | #define CPUID_AVX512_BW 0x80000 |
108 | | #define CPUID_SSSE3 0x100000 /* SSSE3 (pshufb etc.) */ |
109 | | |
110 | | #define IS_INTEL_AVX1(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_AVX1) |
111 | | #define IS_INTEL_AVX2(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_AVX2) |
112 | | #define IS_INTEL_RDRAND(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_RDRAND) |
113 | | #define IS_INTEL_RDSEED(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_RDSEED) |
114 | | #define IS_INTEL_BMI2(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_BMI2) |
115 | | #define IS_INTEL_AESNI(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_AESNI) |
116 | | #define IS_INTEL_ADX(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_ADX) |
117 | | #define IS_INTEL_MOVBE(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_MOVBE) |
118 | | #define IS_INTEL_BMI1(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_BMI1) |
119 | | #define IS_INTEL_SHA(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_SHA) |
120 | | #define IS_INTEL_VAES(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_VAES) |
121 | | #define IS_INTEL_AVX512(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_AVX512) |
122 | | #define IS_INTEL_AVX512_VBMI(f) \ |
123 | | (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_AVX512_VBMI) |
124 | | #define IS_INTEL_AVX512_VBMI2(f) \ |
125 | | (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_AVX512_VBMI2) |
126 | | #define IS_INTEL_AVX512_IFMA(f) \ |
127 | | (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_AVX512_IFMA) |
128 | | #define IS_INTEL_AVX512_VL(f) \ |
129 | | (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_AVX512_VL) |
130 | | #define IS_INTEL_AVX512_DQ(f) \ |
131 | | (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_AVX512_DQ) |
132 | | #define IS_INTEL_AVX512_BW(f) \ |
133 | | (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_AVX512_BW) |
134 | | /* Safe to dispatch to wolfSSL's AVX512 assembly: every algorithm using it |
135 | | * (ML-DSA, ML-KEM, FrodoKEM) works on 8- or 16-bit lanes at 512-bit width |
136 | | * - vpshufb, vpaddw, vpsubw, vpmulhw, vpmullw, vpackusdw, vpmaddwd, ... - |
137 | | * which are AVX512BW, not AVX512F. IS_INTEL_AVX512() is the F bit alone |
138 | | * and is not sufficient on its own. */ |
139 | | #define USE_INTEL_AVX512(f) \ |
140 | | (IS_INTEL_AVX512(f) && IS_INTEL_AVX512_BW(f)) |
141 | | #define IS_CPU_INTEL(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_INTEL) |
142 | | #define IS_CPU_AMD(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_AMD) |
143 | | #define IS_INTEL_SSSE3(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_SSSE3) |
144 | | |
145 | | #elif defined(HAVE_CPUID_AARCH64) |
146 | | |
147 | | #define CPUID_AES 0x0001 /* AES enc/dec */ |
148 | | #define CPUID_PMULL 0x0002 /* Carryless multiplication */ |
149 | | #define CPUID_SHA256 0x0004 /* SHA-256 digest */ |
150 | | #define CPUID_SHA512 0x0008 /* SHA-512 digest */ |
151 | | #define CPUID_RDM 0x0010 /* SQRDMLAH and SQRDMLSH */ |
152 | | #define CPUID_SHA3 0x0020 /* SHA-3 digest */ |
153 | | #define CPUID_SM3 0x0040 /* SM3 digest */ |
154 | | #define CPUID_SM4 0x0080 /* SM4 enc/dec */ |
155 | | #define CPUID_SB 0x0100 /* Speculation barrier */ |
156 | | #define CPUID_ASIMD 0x0200 /* ASIMD - NEON */ |
157 | | #define CPUID_SVE 0x0400 /* Scalable Vector Extension */ |
158 | | #define CPUID_SME 0x0800 /* Scalable Matrix Extension */ |
159 | | |
160 | | #define IS_AARCH64_AES(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_AES) |
161 | | #define IS_AARCH64_PMULL(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_PMULL) |
162 | | #define IS_AARCH64_SHA256(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_SHA256) |
163 | | #define IS_AARCH64_SHA512(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_SHA512) |
164 | | #define IS_AARCH64_RDM(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_RDM) |
165 | | #define IS_AARCH64_SHA3(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_SHA3) |
166 | | #define IS_AARCH64_SM3(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_SM3) |
167 | | #define IS_AARCH64_SM4(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_SM4) |
168 | | #define IS_AARCH64_SB(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_SB) |
169 | | #define IS_AARCH64_ASIMD(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_ASIMD) |
170 | | #define IS_AARCH64_SVE(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_SVE) |
171 | | #define IS_AARCH64_SME(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_SME) |
172 | | |
173 | | #elif defined(HAVE_CPUID_ARM32) |
174 | | |
175 | | /* Only the features that select between the available wolfCrypt AArch32 |
176 | | * assembly implementations are tracked: |
177 | | * - AES / PMULL: Armv8 crypto-extension AES and AES-GCM (armv8-32-aes). |
178 | | * - SHA256: Armv8 crypto-extension SHA-256 (armv8-32-sha256). |
179 | | * - ASIMD (NEON): armv8-32 SHA-512, SHA-3, ChaCha and Poly1305 asm. |
180 | | * AArch32 has no crypto-extension SHA-512/SHA-3 instructions, so those |
181 | | * digests are accelerated with NEON rather than a crypto path. */ |
182 | | #define CPUID_AES 0x0001 /* AES enc/dec */ |
183 | | #define CPUID_PMULL 0x0002 /* Carryless multiply - VMULL.P64 */ |
184 | | #define CPUID_SHA256 0x0004 /* SHA-256 digest */ |
185 | | #define CPUID_ASIMD 0x0008 /* Advanced SIMD - NEON */ |
186 | | |
187 | | #define IS_ARM32_AES(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_AES) |
188 | | #define IS_ARM32_PMULL(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_PMULL) |
189 | | #define IS_ARM32_SHA256(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_SHA256) |
190 | | #define IS_ARM32_ASIMD(f) (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_ASIMD) |
191 | | |
192 | | #elif defined(HAVE_CPUID_PPC64) |
193 | | |
194 | | #define CPUID_ALTIVEC 0x0001 /* VMX / AltiVec */ |
195 | | #define CPUID_VSX 0x0002 /* Vector-Scalar Extension */ |
196 | | #define CPUID_ARCH_2_07 0x0004 /* POWER8 / PowerISA 2.07 */ |
197 | | #define CPUID_VEC_CRYPTO 0x0008 /* Vector crypto: vshasigmaw, vcipher, |
198 | | * vpmsumd, ... */ |
199 | | #define CPUID_ARCH_3_00 0x0010 /* POWER9 / PowerISA 3.0 */ |
200 | | #define CPUID_ARCH_3_1 0x0020 /* POWER10 / PowerISA 3.1 */ |
201 | | |
202 | | #define IS_PPC64_ALTIVEC(f) \ |
203 | | (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_ALTIVEC) |
204 | | #define IS_PPC64_VSX(f) \ |
205 | | (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_VSX) |
206 | | #define IS_PPC64_ARCH_2_07(f) \ |
207 | | (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_ARCH_2_07) |
208 | | #define IS_PPC64_VEC_CRYPTO(f) \ |
209 | | (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_VEC_CRYPTO) |
210 | | #define IS_PPC64_ARCH_3_00(f) \ |
211 | | (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_ARCH_3_00) |
212 | | #define IS_PPC64_ARCH_3_1(f) \ |
213 | | (WOLFSSL_ATOMIC_COERCE_UINT(f) & CPUID_ARCH_3_1) |
214 | | |
215 | | #endif |
216 | | |
217 | | #ifdef HAVE_CPUID |
218 | | cpuid_flags_t cpuid_get_flags(void); |
219 | | |
220 | | /* Idempotent flag getter -- fast, but return value (whether updated) is not |
221 | | * strictly reliable. |
222 | | */ |
223 | 0 | static WC_INLINE int cpuid_get_flags_ex(cpuid_flags_t *flags) { |
224 | 0 | if (*flags == WC_CPUID_INITIALIZER) { |
225 | 0 | *flags = cpuid_get_flags(); |
226 | 0 | return 1; |
227 | 0 | } |
228 | 0 | else |
229 | 0 | return 0; |
230 | 0 | } Unexecuted instantiation: random.c:cpuid_get_flags_ex Unexecuted instantiation: sha256.c:cpuid_get_flags_ex Unexecuted instantiation: aes.c:cpuid_get_flags_ex Unexecuted instantiation: sha512.c:cpuid_get_flags_ex Unexecuted instantiation: wc_port.c:cpuid_get_flags_ex Unexecuted instantiation: chacha20_poly1305.c:cpuid_get_flags_ex Unexecuted instantiation: wc_mlkem_poly.c:cpuid_get_flags_ex Unexecuted instantiation: poly1305.c:cpuid_get_flags_ex Unexecuted instantiation: chacha.c:cpuid_get_flags_ex |
231 | | |
232 | | /* Strictly race-free flag getter -- slow, but the return value is strictly |
233 | | * accurate. |
234 | | */ |
235 | 0 | static WC_INLINE int cpuid_get_flags_atomic(cpuid_flags_atomic_t *flags) { |
236 | 0 | #ifdef WOLFSSL_BSDKM |
237 | 0 | if (WOLFSSL_ATOMIC_LOAD_UINT(*flags) == WC_CPUID_INITIALIZER) { |
238 | 0 | #else |
239 | 0 | if (WOLFSSL_ATOMIC_LOAD(*flags) == WC_CPUID_INITIALIZER) { |
240 | 0 | #endif /* WOLFSSL_BSDKM */ |
241 | 0 | cpuid_flags_t old_cpuid_flags = WC_CPUID_INITIALIZER; |
242 | 0 | return wolfSSL_Atomic_Uint_CompareExchange |
243 | 0 | (flags, &old_cpuid_flags, cpuid_get_flags()); |
244 | 0 | } |
245 | 0 | else |
246 | 0 | return 0; |
247 | 0 | } Unexecuted instantiation: random.c:cpuid_get_flags_atomic Unexecuted instantiation: sha256.c:cpuid_get_flags_atomic Unexecuted instantiation: aes.c:cpuid_get_flags_atomic Unexecuted instantiation: sha512.c:cpuid_get_flags_atomic Unexecuted instantiation: wc_port.c:cpuid_get_flags_atomic Unexecuted instantiation: chacha20_poly1305.c:cpuid_get_flags_atomic Unexecuted instantiation: wc_mlkem_poly.c:cpuid_get_flags_atomic Unexecuted instantiation: poly1305.c:cpuid_get_flags_atomic Unexecuted instantiation: chacha.c:cpuid_get_flags_atomic |
248 | | |
249 | | /* Public APIs to modify flags. */ |
250 | | |
251 | | #ifdef WOLFSSL_API_PREFIX_MAP |
252 | | #define cpuid_select_flags wc_cpuid_select_flags |
253 | | #define cpuid_set_flag wc_cpuid_set_flag |
254 | | #define cpuid_clear_flag wc_cpuid_clear_flag |
255 | | #endif /* WOLFSSL_API_PREFIX_MAP */ |
256 | | |
257 | | WOLFSSL_API void cpuid_select_flags(cpuid_flags_t flags); |
258 | | WOLFSSL_API void cpuid_set_flag(cpuid_flags_t flag); |
259 | | WOLFSSL_API void cpuid_clear_flag(cpuid_flags_t flag); |
260 | | |
261 | | #endif |
262 | | |
263 | | #ifdef __cplusplus |
264 | | } /* extern "C" */ |
265 | | #endif |
266 | | |
267 | | |
268 | | #endif /* WOLF_CRYPT_CPUID_H */ |