1 /* ws_cpuid.h
2 * Get the CPU info on x86 processors that support it
3 *
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 /*
12 * Get CPU info on platforms where the cpuid instruction can be used skip 32 bit versions for GCC
13 * Intel has documented the CPUID instruction in the "Intel(r) 64 and IA-32
14 * Architectures Developer's Manual" at http://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-2a-manual.html
15 * the ws_cpuid() routine will return 0 if cpuinfo isn't available.
16 */
17
18 #include "ws_attributes.h"
19
20 #if defined(_MSC_VER) /* MSVC */
21 static gboolean
ws_cpuid(guint32 * CPUInfo,guint32 selector)22 ws_cpuid(guint32 *CPUInfo, guint32 selector)
23 {
24 CPUInfo[0] = CPUInfo[1] = CPUInfo[2] = CPUInfo[3] = 0;
25 __cpuid((int *) CPUInfo, selector);
26 /* XXX, how to check if it's supported on MSVC? just in case clear all flags above */
27 return TRUE;
28 }
29
30 #elif defined(__GNUC__) /* GCC/clang */
31
32 #if defined(__x86_64__)
33 static inline gboolean
ws_cpuid(guint32 * CPUInfo,int selector)34 ws_cpuid(guint32 *CPUInfo, int selector)
35 {
36 __asm__ __volatile__("cpuid"
37 : "=a" (CPUInfo[0]),
38 "=b" (CPUInfo[1]),
39 "=c" (CPUInfo[2]),
40 "=d" (CPUInfo[3])
41 : "a" (selector),
42 "c" (0));
43 return TRUE;
44 }
45 #elif defined(__i386__)
46 static gboolean
ws_cpuid(guint32 * CPUInfo _U_,int selector _U_)47 ws_cpuid(guint32 *CPUInfo _U_, int selector _U_)
48 {
49 /*
50 * TODO: need a test if older processors have the cpuid instruction.
51 *
52 * The correct way to test for this, according to the Intel64/IA-32
53 * documentation from Intel, in section 17.1 "USING THE CPUID
54 * INSTRUCTION", is to try to change the ID bit (bit 21) in
55 * EFLAGS. If it can be changed, the machine supports CPUID,
56 * otherwise it doesn't.
57 *
58 * Some 486's, and all subsequent processors, support CPUID.
59 *
60 * For those who are curious, the way you distinguish between
61 * an 80386 and an 80486 is to try to set the flag in EFLAGS
62 * that causes unaligned accesses to fault - that's bit 18.
63 * However, if the SMAP bit is set in CR4, that bit controls
64 * whether explicit supervisor-mode access to user-mode pages
65 * are allowed, so that should presumably only be done in a
66 * very controlled environment, such as the system boot process.
67 *
68 * So, if you want to find out what type of CPU the system has,
69 * it's probably best to ask the OS, if it supplies the result
70 * of any CPU type testing it's done.
71 */
72 return FALSE;
73 }
74 #else /* not x86 */
75 static gboolean
ws_cpuid(guint32 * CPUInfo _U_,int selector _U_)76 ws_cpuid(guint32 *CPUInfo _U_, int selector _U_)
77 {
78 /* Not x86, so no cpuid instruction */
79 return FALSE;
80 }
81 #endif
82
83 #else /* Other compilers */
84
85 static gboolean
ws_cpuid(guint32 * CPUInfo _U_,int selector _U_)86 ws_cpuid(guint32 *CPUInfo _U_, int selector _U_)
87 {
88 return FALSE;
89 }
90 #endif
91
92 static int
ws_cpuid_sse42(void)93 ws_cpuid_sse42(void)
94 {
95 guint32 CPUInfo[4];
96
97 if (!ws_cpuid(CPUInfo, 1))
98 return 0;
99
100 /* in ECX bit 20 toggled on */
101 return (CPUInfo[2] & (1 << 20));
102 }
103