1 /*
2 * This file is part of the openHiTLS project.
3 *
4 * openHiTLS is licensed under the Mulan PSL v2.
5 * You can use this software according to the terms and conditions of the Mulan PSL v2.
6 * You may obtain a copy of Mulan PSL v2 at:
7 *
8 * http://license.coscl.org.cn/MulanPSL2
9 *
10 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13 * See the Mulan PSL v2 for more details.
14 */
15
16 #include "crypt_utils.h"
17 #ifdef __x86_64__
18
19 #include <cpuid.h>
20 #include "securec.h"
21
22
23 CpuInstrSupportState g_cpuState = {0};
24
25 /* Obtain whether the CPU supports the SIMD instruction set through the cpuid instruction. */
GetCpuId(uint32_t eax,uint32_t ecx,uint32_t cpuId[CPU_ID_OUT_U32_CNT])26 void GetCpuId(uint32_t eax, uint32_t ecx, uint32_t cpuId[CPU_ID_OUT_U32_CNT])
27 {
28 uint32_t eaxOut, ebxOut, ecxOut, edxOut;
29
30 __asm("cpuid": "=a"(eaxOut), "=b"(ebxOut), "=c"(ecxOut), "=d"(edxOut): "a"(eax), "c"(ecx):);
31
32 cpuId[EAX_OUT_IDX] = eaxOut;
33 cpuId[EBX_OUT_IDX] = ebxOut;
34 cpuId[ECX_OUT_IDX] = ecxOut;
35 cpuId[EDX_OUT_IDX] = edxOut;
36 }
37
38 /* Obtain whether the OS supports the SIMD instruction set by using the xgetbv instruction. */
GetExCtl(uint32_t ecx)39 static uint32_t GetExCtl(uint32_t ecx)
40 {
41 uint32_t ret = 0;
42
43 __asm("xgetbv": "=a"(ret): "c"(ecx):);
44
45 return ret;
46 }
47
48
IsSupportBMI1(void)49 bool IsSupportBMI1(void)
50 {
51 return g_cpuState.code7Out[EBX_OUT_IDX] & bit_BMI;
52 }
53
IsSupportMOVBE(void)54 bool IsSupportMOVBE(void)
55 {
56 return g_cpuState.code1Out[ECX_OUT_IDX] & bit_MOVBE;
57 }
58
IsSupportBMI2(void)59 bool IsSupportBMI2(void)
60 {
61 return g_cpuState.code7Out[EBX_OUT_IDX] & bit_BMI2;
62 }
63
IsSupportADX(void)64 bool IsSupportADX(void)
65 {
66 return g_cpuState.code7Out[EBX_OUT_IDX] & bit_ADX;
67 }
68
IsSupportSSE(void)69 bool IsSupportSSE(void)
70 {
71 return g_cpuState.code1Out[EDX_OUT_IDX] & bit_SSE;
72 }
73
IsSupportSSE2(void)74 bool IsSupportSSE2(void)
75 {
76 return g_cpuState.code1Out[EDX_OUT_IDX] & bit_SSE2;
77 }
78
IsSupportAVX(void)79 bool IsSupportAVX(void)
80 {
81 return g_cpuState.code1Out[ECX_OUT_IDX] & bit_AVX;
82 }
83
IsSupportAES(void)84 bool IsSupportAES(void)
85 {
86 return g_cpuState.code1Out[ECX_OUT_IDX] & bit_AES;
87 }
88
IsSupportSSE3(void)89 bool IsSupportSSE3(void)
90 {
91 return g_cpuState.code1Out[ECX_OUT_IDX] & bit_SSE3;
92 }
93
IsSupportAVX2(void)94 bool IsSupportAVX2(void)
95 {
96 return g_cpuState.code7Out[EBX_OUT_IDX] & bit_AVX2;
97 }
98
IsSupportAVX512F(void)99 bool IsSupportAVX512F(void)
100 {
101 return g_cpuState.code7Out[EBX_OUT_IDX] & bit_AVX512F;
102 }
103
IsSupportAVX512DQ(void)104 bool IsSupportAVX512DQ(void)
105 {
106 return g_cpuState.code7Out[EBX_OUT_IDX] & bit_AVX512DQ;
107 }
108
IsSupportAVX512VL(void)109 bool IsSupportAVX512VL(void)
110 {
111 return g_cpuState.code7Out[EBX_OUT_IDX] & bit_AVX512VL;
112 }
113
IsSupportAVX512BW(void)114 bool IsSupportAVX512BW(void)
115 {
116 return g_cpuState.code7Out[EBX_OUT_IDX] & bit_AVX512BW;
117 }
118
IsSupportXSAVE(void)119 bool IsSupportXSAVE(void)
120 {
121 return g_cpuState.code1Out[ECX_OUT_IDX] & bit_XSAVE;
122 }
123
IsSupportOSXSAVE(void)124 bool IsSupportOSXSAVE(void)
125 {
126 return g_cpuState.code1Out[ECX_OUT_IDX] & bit_OSXSAVE;
127 }
128
IsOSSupportAVX(void)129 bool IsOSSupportAVX(void)
130 {
131 return g_cpuState.osSupportAVX;
132 }
133
IsOSSupportAVX512(void)134 bool IsOSSupportAVX512(void)
135 {
136 return g_cpuState.osSupportAVX512;
137 }
138
139
140 /* ARM */
141 #elif defined(__arm__) || defined (__arm) || defined(__aarch64__)
142 #include "crypt_arm.h"
143 uint32_t g_cryptArmCpuInfo = 0;
144
145 #if defined(HITLS_CRYPTO_NO_AUXVAL)
146 #include <setjmp.h>
147 #include <signal.h>
148
149 static jmp_buf g_jump_buffer;
150
signal_handler(int sig)151 void signal_handler(int sig)
152 {
153 (void)sig;
154 longjmp(g_jump_buffer, 1);
155 }
156
getarmcap(void)157 void getarmcap(void)
158 {
159 struct sigaction sa, old_sa;
160
161 sa.sa_handler = signal_handler;
162 sigemptyset(&sa.sa_mask);
163 sa.sa_flags = 0;
164 sigaction(SIGILL, &sa, &old_sa);
165
166 // NEON
167 if (setjmp(g_jump_buffer) == 0) {
168 #if defined(__ARM_NEON) || defined(__aarch64__)
169 __asm__ volatile ("ORR v0.16b, v0.16b, v0.16b" : : : "v0");
170 g_cryptArmCpuInfo |= CRYPT_ARM_NEON;
171 #endif
172 #if defined(__aarch64__)
173 // AES
174 if (setjmp(g_jump_buffer) == 0) {
175 __asm__ volatile ("aese v0.16b, v0.16b" : : : "v0");
176 g_cryptArmCpuInfo |= CRYPT_ARM_AES;
177 }
178 // PMULL
179 if (setjmp(g_jump_buffer) == 0) {
180 __asm__ volatile ("pmull v0.1q, v0.1d, v0.1d" : : : "v0");
181 g_cryptArmCpuInfo |= CRYPT_ARM_PMULL;
182 }
183 // SHA1
184 if (setjmp(g_jump_buffer) == 0) {
185 __asm__ volatile ("sha1h s0, s0" : : : "s0");
186 g_cryptArmCpuInfo |= CRYPT_ARM_SHA1;
187 }
188 // SHA256
189 if (setjmp(g_jump_buffer) == 0) {
190 __asm__ volatile ("sha256su0 v0.4s, v0.4s" : : : "v0");
191 g_cryptArmCpuInfo |= CRYPT_ARM_SHA256;
192 }
193 // SHA512
194 if (setjmp(g_jump_buffer) == 0) {
195 __asm__ volatile ("sha512su0 v0.2d, v0.2d" : : : "v0");
196 g_cryptArmCpuInfo |= CRYPT_ARM_SHA512;
197 }
198 #endif
199 }
200
201 sigaction(SIGILL, &old_sa, NULL);
202 }
203 #else
204
205 #include <sys/auxv.h>
206
207 static bool g_supportNEON = {0};
208
IsSupportAES(void)209 bool IsSupportAES(void)
210 {
211 return g_cryptArmCpuInfo & CRYPT_ARM_AES;
212 }
213
IsSupportPMULL(void)214 bool IsSupportPMULL(void)
215 {
216 return g_cryptArmCpuInfo & CRYPT_ARM_PMULL;
217 }
218
IsSupportSHA1(void)219 bool IsSupportSHA1(void)
220 {
221 return g_cryptArmCpuInfo & CRYPT_ARM_SHA1;
222 }
223
IsSupportSHA256(void)224 bool IsSupportSHA256(void)
225 {
226 return g_cryptArmCpuInfo & CRYPT_ARM_SHA256;
227 }
228
IsSupportNEON(void)229 bool IsSupportNEON(void)
230 {
231 return g_supportNEON;
232 }
233
234 #if defined(__aarch64__)
IsSupportSHA512(void)235 bool IsSupportSHA512(void)
236 {
237 return g_cryptArmCpuInfo & CRYPT_ARM_SHA512;
238 }
239 #endif // __aarch64__
240
241 #endif // HITLS_CRYPTO_NO_AUXVAL
242 #endif // x86_64 || __arm__ || __arm || __aarch64__
243
GetCpuInstrSupportState(void)244 void GetCpuInstrSupportState(void)
245 {
246 #ifdef __x86_64__
247 uint32_t cpuId[CPU_ID_OUT_U32_CNT];
248 uint64_t xcr0;
249
250 /* SIMD CPU support */
251 GetCpuId(0x1, 0, cpuId);
252 (void)memcpy_s(g_cpuState.code1Out, CPU_ID_OUT_U32_CNT * sizeof(uint32_t), cpuId,
253 CPU_ID_OUT_U32_CNT * sizeof(uint32_t));
254
255 GetCpuId(0x7, 0, cpuId);
256 (void)memcpy_s(g_cpuState.code7Out, CPU_ID_OUT_U32_CNT * sizeof(uint32_t), cpuId,
257 CPU_ID_OUT_U32_CNT * sizeof(uint32_t));
258
259 /* SIMD OS support */
260 if (IsSupportXSAVE() && IsSupportOSXSAVE()) {
261 xcr0 = GetExCtl(0);
262 bool sse = xcr0 & XCR0_BIT_SSE;
263 bool avx = xcr0 & XCR0_BIT_AVX;
264 g_cpuState.osSupportAVX = sse && avx;
265 bool opmask = xcr0 & XCR0_BIT_OPMASK;
266 bool zmmLow = xcr0 & XCR0_BIT_ZMM_LOW;
267 bool zmmHigh = xcr0 & XCR0_BIT_ZMM_HIGH;
268 g_cpuState.osSupportAVX512 = opmask && zmmLow && zmmHigh;
269 }
270 #elif defined(__arm__) || defined (__arm) || defined(__aarch64__)
271 #if defined(HITLS_CRYPTO_NO_AUXVAL)
272 getarmcap();
273 #else // HITLS_CRYPTO_NO_AUXVAL
274 g_supportNEON = getauxval(CRYPT_CAP) & CRYPT_ARM_NEON;
275 if (g_supportNEON) {
276 g_cryptArmCpuInfo = (uint32_t)getauxval(CRYPT_CE);
277 }
278 #endif // HITLS_CRYPTO_NO_AUXVAL
279 #endif // defined(__arm__) || defined (__arm) || defined(__aarch64__)
280 }