1 /* hwf-x86.c - Detect hardware features - x86 part
2 * Copyright (C) 2007, 2011, 2012 Free Software Foundation, Inc.
3 * Copyright (C) 2012 Jussi Kivilinna
5 * This file is part of Libgcrypt.
7 * Libgcrypt is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
12 * Libgcrypt 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 Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
29 #include "hwf-common.h"
31 #if !defined (__i386__) && !defined (__x86_64__)
32 # error Module build for wrong CPU.
35 /* We use the next macro to decide whether we can test for certain
39 #if defined (__i386__) && SIZEOF_UNSIGNED_LONG == 4 && defined (__GNUC__)
40 # define HAS_X86_CPUID 1
43 is_cpuid_available(void)
47 /* Detect the CPUID feature by testing some undefined behaviour (16
48 vs 32 bit pushf/popf). */
50 ("pushf\n\t" /* Copy flags to EAX. */
52 "movl %%eax, %%ecx\n\t" /* Save flags into ECX. */
53 "xorl $0x200000, %%eax\n\t" /* Toggle ID bit and copy it to the flags. */
56 "pushf\n\t" /* Copy changed flags again to EAX. */
58 "pushl %%ecx\n\t" /* Restore flags from ECX. */
60 "xorl %%eax, %%ecx\n\t" /* Compare flags against saved flags. */
61 "jz .Lno_cpuid%=\n\t" /* Toggling did not work, thus no CPUID. */
62 "movl $1, %0\n" /* Worked. true -> HAS_CPUID. */
66 : "%eax", "%ecx", "cc"
73 get_cpuid(unsigned int in, unsigned int *eax, unsigned int *ebx,
74 unsigned int *ecx, unsigned int *edx)
79 ("pushl %%ebx\n\t" /* Save GOT register. */
83 "popl %%ebx\n\t" /* Restore GOT register. */
84 : "=a" (regs[0]), "=D" (regs[1]), "=c" (regs[2]), "=d" (regs[3])
85 : "0" (in), "1" (0), "2" (0), "3" (0)
99 #if defined(ENABLE_AVX_SUPPORT) || defined(ENABLE_AVX2_SUPPORT)
103 unsigned int t_eax, t_edx;
107 : "=a" (t_eax), "=d" (t_edx)
113 #endif /* ENABLE_AVX_SUPPORT || ENABLE_AVX2_SUPPORT */
115 #endif /* i386 && GNUC */
118 #if defined (__x86_64__) && defined (__GNUC__)
119 # define HAS_X86_CPUID 1
122 is_cpuid_available(void)
128 get_cpuid(unsigned int in, unsigned int *eax, unsigned int *ebx,
129 unsigned int *ecx, unsigned int *edx)
131 unsigned int regs[4];
135 : "=a" (regs[0]), "=b" (regs[1]), "=c" (regs[2]), "=d" (regs[3])
136 : "0" (in), "1" (0), "2" (0), "3" (0)
150 #if defined(ENABLE_AVX_SUPPORT) || defined(ENABLE_AVX2_SUPPORT)
154 unsigned int t_eax, t_edx;
158 : "=a" (t_eax), "=d" (t_edx)
164 #endif /* ENABLE_AVX_SUPPORT || ENABLE_AVX2_SUPPORT */
166 #endif /* x86-64 && GNUC */
171 detect_x86_gnuc (void)
173 char vendor_id[12+1];
174 unsigned int features;
175 unsigned int os_supports_avx_avx2_registers = 0;
176 unsigned int max_cpuid_level;
177 unsigned int fms, family, model;
178 unsigned int result = 0;
180 (void)os_supports_avx_avx2_registers;
182 if (!is_cpuid_available())
185 get_cpuid(0, &max_cpuid_level,
186 (unsigned int *)&vendor_id[0],
187 (unsigned int *)&vendor_id[8],
188 (unsigned int *)&vendor_id[4]);
192 ; /* Just to make "else if" and ifdef macros look pretty. */
193 #ifdef ENABLE_PADLOCK_SUPPORT
194 else if (!strcmp (vendor_id, "CentaurHauls"))
196 /* This is a VIA CPU. Check what PadLock features we have. */
198 /* Check for extended centaur (EAX). */
199 get_cpuid(0xC0000000, &features, NULL, NULL, NULL);
201 /* Has extended centaur features? */
202 if (features > 0xC0000000)
204 /* Ask for the extended feature flags (EDX). */
205 get_cpuid(0xC0000001, NULL, NULL, NULL, &features);
207 /* Test bits 2 and 3 to see whether the RNG exists and is enabled. */
208 if ((features & 0x0C) == 0x0C)
209 result |= HWF_PADLOCK_RNG;
211 /* Test bits 6 and 7 to see whether the ACE exists and is enabled. */
212 if ((features & 0xC0) == 0xC0)
213 result |= HWF_PADLOCK_AES;
215 /* Test bits 10 and 11 to see whether the PHE exists and is
217 if ((features & 0xC00) == 0xC00)
218 result |= HWF_PADLOCK_SHA;
220 /* Test bits 12 and 13 to see whether the MONTMUL exists and is
222 if ((features & 0x3000) == 0x3000)
223 result |= HWF_PADLOCK_MMUL;
226 #endif /*ENABLE_PADLOCK_SUPPORT*/
227 else if (!strcmp (vendor_id, "GenuineIntel"))
229 /* This is an Intel CPU. */
230 result |= HWF_INTEL_CPU;
232 else if (!strcmp (vendor_id, "AuthenticAMD"))
234 /* This is an AMD CPU. */
237 /* Detect Intel features, that might also be supported by other
240 /* Get CPU family/model/stepping (EAX) and Intel feature flags (ECX). */
241 get_cpuid(1, &fms, NULL, &features, NULL);
243 family = ((fms & 0xf00) >> 8) + ((fms & 0xff00000) >> 20);
244 model = ((fms & 0xf0) >> 4) + ((fms & 0xf0000) >> 12);
246 if ((result & HWF_INTEL_CPU) && family == 6)
248 /* These Intel Core processor models have SHLD/SHRD instruction that
249 * can do integer rotation faster actual ROL/ROR instructions. */
267 result |= HWF_INTEL_FAST_SHLD;
272 #ifdef ENABLE_PCLMUL_SUPPORT
273 /* Test bit 1 for PCLMUL. */
274 if (features & 0x00000002)
275 result |= HWF_INTEL_PCLMUL;
277 /* Test bit 9 for SSSE3. */
278 if (features & 0x00000200)
279 result |= HWF_INTEL_SSSE3;
280 /* Test bit 19 for SSE4.1. */
281 if (features & 0x00080000)
282 result |= HWF_INTEL_SSE4_1;
283 #ifdef ENABLE_AESNI_SUPPORT
284 /* Test bit 25 for AES-NI. */
285 if (features & 0x02000000)
286 result |= HWF_INTEL_AESNI;
287 #endif /*ENABLE_AESNI_SUPPORT*/
288 #if defined(ENABLE_AVX_SUPPORT) || defined(ENABLE_AVX2_SUPPORT)
289 /* Test bit 27 for OSXSAVE (required for AVX/AVX2). */
290 if (features & 0x08000000)
292 /* Check that OS has enabled both XMM and YMM state support. */
293 if ((get_xgetbv() & 0x6) == 0x6)
294 os_supports_avx_avx2_registers = 1;
297 #ifdef ENABLE_AVX_SUPPORT
298 /* Test bit 28 for AVX. */
299 if (features & 0x10000000)
300 if (os_supports_avx_avx2_registers)
301 result |= HWF_INTEL_AVX;
302 #endif /*ENABLE_AVX_SUPPORT*/
303 #ifdef ENABLE_DRNG_SUPPORT
304 /* Test bit 30 for RDRAND. */
305 if (features & 0x40000000)
306 result |= HWF_INTEL_RDRAND;
307 #endif /*ENABLE_DRNG_SUPPORT*/
309 /* Check additional Intel feature flags. Early Intel P5 processors report
310 * too high max_cpuid_level, so don't check level 7 if processor does not
311 * support SSE3 (as cpuid:7 contains only features for newer processors).
312 * Source: http://www.sandpile.org/x86/cpuid.htm */
313 if (max_cpuid_level >= 7 && (features & 0x00000001))
315 /* Get CPUID:7 contains further Intel feature flags. */
316 get_cpuid(7, NULL, &features, NULL, NULL);
318 /* Test bit 8 for BMI2. */
319 if (features & 0x00000100)
320 result |= HWF_INTEL_BMI2;
322 #ifdef ENABLE_AVX2_SUPPORT
323 /* Test bit 5 for AVX2. */
324 if (features & 0x00000020)
325 if (os_supports_avx_avx2_registers)
326 result |= HWF_INTEL_AVX2;
327 #endif /*ENABLE_AVX_SUPPORT*/
332 #endif /* HAS_X86_CPUID */
336 _gcry_hwf_detect_x86 (void)
338 #if defined (HAS_X86_CPUID)
339 return detect_x86_gnuc ();