Wireshark  4.3.0
The Wireshark network protocol analyzer
ws_cpuid.h
Go to the documentation of this file.
1 
11 /*
12  * Get CPU info on platforms where the x86 cpuid instruction can be used.
13  *
14  * Skip 32-bit versions for GCC and Clang, as older IA-32 processors don't
15  * have cpuid.
16  *
17  * Intel has documented the CPUID instruction in the "Intel(r) 64 and IA-32
18  * Architectures Developer's Manual" at
19  *
20  * https://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-2a-manual.html
21  *
22  * The ws_cpuid() routine will return 0 if cpuinfo isn't available, including
23  * on non-x86 platforms and on 32-bit x86 platforms with GCC and Clang, as
24  * well as non-MSVC and non-GCC-or-Clang platforms.
25  *
26  * The "selector" argument to ws_cpuid() is the "initial EAX value" for the
27  * instruction. The initial ECX value is 0.
28  *
29  * The "CPUInfo" argument points to 4 32-bit values into which the
30  * resulting values of EAX, EBX, ECX, and EDX are store, in order.
31  */
32 
33 #include "ws_attributes.h"
34 
35 #include <inttypes.h>
36 #include <stdbool.h>
37 
38 #if defined(_MSC_VER) /* MSVC */
39 
40 /*
41  * XXX - do the same IA-32 (which doesn't have CPUID prior to some versions
42  * of the 80486 and all versions of the 80586^Woriginal Pentium) vs.
43  * x86-64 (which always has CPUID) stuff that we do with GCC/Clang?
44  *
45  * You will probably not be happy running current versions of Wireshark
46  * on an 80386 or 80486 machine, and we're dropping support for IA-32
47  * on Windows anyway, so the answer is probably "no".
48  */
49 #if defined(_M_IX86) || defined(_M_X64)
50 static bool
51 ws_cpuid(uint32_t *CPUInfo, uint32_t selector)
52 {
53  /* https://docs.microsoft.com/en-us/cpp/intrinsics/cpuid-cpuidex */
54 
55  CPUInfo[0] = CPUInfo[1] = CPUInfo[2] = CPUInfo[3] = 0;
56  __cpuid((int *) CPUInfo, selector);
57  /* XXX, how to check if it's supported on MSVC? just in case clear all flags above */
58  return true;
59 }
60 #else /* not x86 */
61 static bool
62 ws_cpuid(uint32_t *CPUInfo _U_, int selector _U_)
63 {
64  /* Not x86, so no cpuid instruction */
65  return false;
66 }
67 #endif
68 
69 #elif defined(__GNUC__) /* GCC/clang */
70 
71 #if defined(__x86_64__)
72 static inline bool
73 ws_cpuid(uint32_t *CPUInfo, int selector)
74 {
75  __asm__ __volatile__("cpuid"
76  : "=a" (CPUInfo[0]),
77  "=b" (CPUInfo[1]),
78  "=c" (CPUInfo[2]),
79  "=d" (CPUInfo[3])
80  : "a" (selector),
81  "c" (0));
82  return true;
83 }
84 #elif defined(__i386__)
85 static bool
86 ws_cpuid(uint32_t *CPUInfo _U_, int selector _U_)
87 {
88  /*
89  * TODO: need a test if older processors have the cpuid instruction.
90  *
91  * The correct way to test for this, according to the Intel64/IA-32
92  * documentation from Intel, in section 17.1 "USING THE CPUID
93  * INSTRUCTION", is to try to change the ID bit (bit 21) in
94  * EFLAGS. If it can be changed, the machine supports CPUID,
95  * otherwise it doesn't.
96  *
97  * Some 486's, and all subsequent processors, support CPUID.
98  *
99  * For those who are curious, the way you distinguish between
100  * an 80386 and an 80486 is to try to set the flag in EFLAGS
101  * that causes unaligned accesses to fault - that's bit 18.
102  * However, if the SMAP bit is set in CR4, that bit controls
103  * whether explicit supervisor-mode access to user-mode pages
104  * are allowed, so that should presumably only be done in a
105  * very controlled environment, such as the system boot process.
106  *
107  * So, if you want to find out what type of CPU the system has,
108  * it's probably best to ask the OS, if it supplies the result
109  * of any CPU type testing it's done.
110  */
111  return false;
112 }
113 #else /* not x86 */
114 static bool
115 ws_cpuid(uint32_t *CPUInfo _U_, int selector _U_)
116 {
117  /* Not x86, so no cpuid instruction */
118  return false;
119 }
120 #endif
121 
122 #else /* Other compilers */
123 
124 static bool
125 ws_cpuid(uint32_t *CPUInfo _U_, int selector _U_)
126 {
127  return false;
128 }
129 #endif
130 
131 static int
132 ws_cpuid_sse42(void)
133 {
134  uint32_t CPUInfo[4];
135 
136  if (!ws_cpuid(CPUInfo, 1))
137  return 0;
138 
139  /* in ECX bit 20 toggled on */
140  return (CPUInfo[2] & (1 << 20));
141 }