| Wireshark 4.7.3 The Wireshark network protocol analyzer

Loading...
Searching...
No Matches
ws_cpuid.h
Go to the documentation of this file.
1
10
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
51
52
53#if defined(_MSC_VER) /* MSVC */
54
55/*
56 * XXX - do the same IA-32 (which doesn't have CPUID prior to some versions
57 * of the 80486 and all versions of the 80586^Woriginal Pentium) vs.
58 * x86-64 (which always has CPUID) stuff that we do with GCC/Clang?
59 *
60 * You will probably not be happy running current versions of Wireshark
61 * on an 80386 or 80486 machine, and we're dropping support for IA-32
62 * on Windows anyway, so the answer is probably "no".
63 */
64#if defined(_M_IX86) || defined(_M_X64)
65 static bool
66ws_cpuid(uint32_t *CPUInfo, uint32_t selector)
67{
68 /* https://docs.microsoft.com/en-us/cpp/intrinsics/cpuid-cpuidex */
69
70 CPUInfo[0] = CPUInfo[1] = CPUInfo[2] = CPUInfo[3] = 0;
71 __cpuid((int *) CPUInfo, selector);
72 /* XXX, how to check if it's supported on MSVC? just in case clear all flags above */
73 return true;
74}
75#else /* not x86 */
76 static bool
77ws_cpuid(uint32_t *CPUInfo _U_, int selector _U_)
78{
79 /* Not x86, so no cpuid instruction */
80 return false;
81}
82#endif
83
84#elif defined(__GNUC__) /* GCC/clang */
85
86#if defined(__x86_64__)
87
95 static inline bool
96ws_cpuid(uint32_t *CPUInfo, int selector)
97{
98 __asm__ __volatile__("cpuid"
99 : "=a" (CPUInfo[0]),
100 "=b" (CPUInfo[1]),
101 "=c" (CPUInfo[2]),
102 "=d" (CPUInfo[3])
103 : "a" (selector),
104 "c" (0));
105 return true;
106}
107#elif defined(__i386__)
108
116 static bool
117ws_cpuid(uint32_t *CPUInfo _U_, int selector _U_)
118{
119 /*
120 * TODO: need a test if older processors have the cpuid instruction.
121 *
122 * The correct way to test for this, according to the Intel64/IA-32
123 * documentation from Intel, in section 17.1 "USING THE CPUID
124 * INSTRUCTION", is to try to change the ID bit (bit 21) in
125 * EFLAGS. If it can be changed, the machine supports CPUID,
126 * otherwise it doesn't.
127 *
128 * Some 486's, and all subsequent processors, support CPUID.
129 *
130 * For those who are curious, the way you distinguish between
131 * an 80386 and an 80486 is to try to set the flag in EFLAGS
132 * that causes unaligned accesses to fault - that's bit 18.
133 * However, if the SMAP bit is set in CR4, that bit controls
134 * whether explicit supervisor-mode access to user-mode pages
135 * are allowed, so that should presumably only be done in a
136 * very controlled environment, such as the system boot process.
137 *
138 * So, if you want to find out what type of CPU the system has,
139 * it's probably best to ask the OS, if it supplies the result
140 * of any CPU type testing it's done.
141 */
142 return false;
143}
144#else /* not x86 */
145
153 static bool
154ws_cpuid(uint32_t *CPUInfo _U_, int selector _U_)
155{
156 /* Not x86, so no cpuid instruction */
157 return false;
158}
159#endif
160
161#else /* Other compilers */
162
170 static bool
171ws_cpuid(uint32_t *CPUInfo _U_, int selector _U_)
172{
173 return false;
174}
175#endif
176
182 static int
183ws_cpuid_sse42(void)
184{
185 uint32_t CPUInfo[4];
186
187 if (!ws_cpuid(CPUInfo, 1))
188 return 0;
189
190 /* in ECX bit 20 toggled on */
191 return (CPUInfo[2] & (1 << 20));
192}