/src/wireshark/wsutil/ws_cpuid.h
Line | Count | Source |
1 | | /** @file |
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 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 | | /** |
39 | | * @def ws_cpuid |
40 | | * @brief Execute the x86 CPUID instruction with the given selector. |
41 | | * |
42 | | * Retrieves CPU information by executing the CPUID instruction with the specified |
43 | | * selector. The results are stored in the `CPUInfo` array as |
44 | | * EAX, EBX, ECX, and EDX, respectively. |
45 | | * |
46 | | * @param CPUInfo Pointer to an array of four uint32_t values to receive |
47 | | * EAX, EBX, ECX, and EDX results, in that order. |
48 | | * @param selector Initial EAX value for the CPUID instruction. |
49 | | * @return true if cpuinfo is available, otherwise 0. |
50 | | */ |
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 |
66 | | ws_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 |
77 | | ws_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 | | |
88 | | /** |
89 | | * @brief Execute a CPUID query on the current processor. |
90 | | * |
91 | | * @param CPUInfo Output array of four 32-bit registers (EAX, EBX, ECX, EDX). |
92 | | * @param selector The CPUID leaf (function ID) to query. |
93 | | * @return true if the query was successful, false if unsupported. |
94 | | */ |
95 | | static inline bool |
96 | | ws_cpuid(uint32_t *CPUInfo, int selector) |
97 | 301 | { |
98 | 301 | __asm__ __volatile__("cpuid" |
99 | 301 | : "=a" (CPUInfo[0]), |
100 | 301 | "=b" (CPUInfo[1]), |
101 | 301 | "=c" (CPUInfo[2]), |
102 | 301 | "=d" (CPUInfo[3]) |
103 | 301 | : "a" (selector), |
104 | 301 | "c" (0)); |
105 | 301 | return true; |
106 | 301 | } ws_mempbrk_sse42.c:ws_cpuid Line | Count | Source | 97 | 287 | { | 98 | 287 | __asm__ __volatile__("cpuid" | 99 | 287 | : "=a" (CPUInfo[0]), | 100 | 287 | "=b" (CPUInfo[1]), | 101 | 287 | "=c" (CPUInfo[2]), | 102 | 287 | "=d" (CPUInfo[3]) | 103 | 287 | : "a" (selector), | 104 | 287 | "c" (0)); | 105 | | return true; | 106 | 287 | } |
Line | Count | Source | 97 | 14 | { | 98 | 14 | __asm__ __volatile__("cpuid" | 99 | 14 | : "=a" (CPUInfo[0]), | 100 | 14 | "=b" (CPUInfo[1]), | 101 | 14 | "=c" (CPUInfo[2]), | 102 | 14 | "=d" (CPUInfo[3]) | 103 | 14 | : "a" (selector), | 104 | 14 | "c" (0)); | 105 | | return true; | 106 | 14 | } |
|
107 | | #elif defined(__i386__) |
108 | | |
109 | | /** |
110 | | * @brief Execute a CPUID query on the current processor. |
111 | | * |
112 | | * @param CPUInfo Output array of four 32-bit registers (EAX, EBX, ECX, EDX). |
113 | | * @param selector The CPUID leaf (function ID) to query. |
114 | | * @return true if the query was successful, false if unsupported. |
115 | | */ |
116 | | static bool |
117 | | ws_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 | | |
146 | | /** |
147 | | * @brief Execute a CPUID query on the current processor. |
148 | | * |
149 | | * @param CPUInfo Output array of four 32-bit registers (EAX, EBX, ECX, EDX). |
150 | | * @param selector The CPUID leaf (function ID) to query. |
151 | | * @return true if the query was successful, false if unsupported. |
152 | | */ |
153 | | static bool |
154 | | ws_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 | | |
163 | | /** |
164 | | * @brief Execute a CPUID query on the current processor. |
165 | | * |
166 | | * @param CPUInfo Output array of four 32-bit registers (EAX, EBX, ECX, EDX). |
167 | | * @param selector The CPUID leaf (function ID) to query. |
168 | | * @return true if the query was successful, false if unsupported. |
169 | | */ |
170 | | static bool |
171 | | ws_cpuid(uint32_t *CPUInfo _U_, int selector _U_) |
172 | | { |
173 | | return false; |
174 | | } |
175 | | #endif |
176 | | |
177 | | /** |
178 | | * @brief Checks if the CPU supports SSE4.2 instruction set. |
179 | | * |
180 | | * @return 1 if SSE4.2 is supported, otherwise returns 0. |
181 | | */ |
182 | | static int |
183 | | ws_cpuid_sse42(void) |
184 | 301 | { |
185 | 301 | uint32_t CPUInfo[4]; |
186 | | |
187 | 301 | if (!ws_cpuid(CPUInfo, 1)) |
188 | 0 | return 0; |
189 | | |
190 | | /* in ECX bit 20 toggled on */ |
191 | 301 | return (CPUInfo[2] & (1 << 20)); |
192 | 301 | } ws_mempbrk_sse42.c:ws_cpuid_sse42 Line | Count | Source | 184 | 287 | { | 185 | 287 | uint32_t CPUInfo[4]; | 186 | | | 187 | 287 | if (!ws_cpuid(CPUInfo, 1)) | 188 | 0 | return 0; | 189 | | | 190 | | /* in ECX bit 20 toggled on */ | 191 | 287 | return (CPUInfo[2] & (1 << 20)); | 192 | 287 | } |
cpu_info.c:ws_cpuid_sse42 Line | Count | Source | 184 | 14 | { | 185 | 14 | uint32_t CPUInfo[4]; | 186 | | | 187 | 14 | if (!ws_cpuid(CPUInfo, 1)) | 188 | 0 | return 0; | 189 | | | 190 | | /* in ECX bit 20 toggled on */ | 191 | 14 | return (CPUInfo[2] & (1 << 20)); | 192 | 14 | } |
|