2 * Get the CPU info on x86 processors that support it
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
12 * Get CPU info on platforms where the x86 cpuid instruction can be used.
14 * Skip 32-bit versions for GCC and Clang, as older IA-32 processors don't
17 * Intel has documented the CPUID instruction in the "Intel(r) 64 and IA-32
18 * Architectures Developer's Manual" at
20 * https://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-2a-manual.html
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.
26 * The "selector" argument to ws_cpuid() is the "initial EAX value" for the
27 * instruction. The initial ECX value is 0.
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.
33 #include "ws_attributes.h"
38 #if defined(_MSC_VER) /* MSVC */
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?
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".
49 #if defined(_M_IX86) || defined(_M_X64)
51 ws_cpuid(uint32_t *CPUInfo
, uint32_t selector
)
53 /* https://docs.microsoft.com/en-us/cpp/intrinsics/cpuid-cpuidex */
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 */
62 ws_cpuid(uint32_t *CPUInfo _U_
, int selector _U_
)
64 /* Not x86, so no cpuid instruction */
69 #elif defined(__GNUC__) /* GCC/clang */
71 #if defined(__x86_64__)
73 ws_cpuid(uint32_t *CPUInfo
, int selector
)
75 __asm__
__volatile__("cpuid"
84 #elif defined(__i386__)
86 ws_cpuid(uint32_t *CPUInfo _U_
, int selector _U_
)
89 * TODO: need a test if older processors have the cpuid instruction.
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.
97 * Some 486's, and all subsequent processors, support CPUID.
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.
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.
115 ws_cpuid(uint32_t *CPUInfo _U_
, int selector _U_
)
117 /* Not x86, so no cpuid instruction */
122 #else /* Other compilers */
125 ws_cpuid(uint32_t *CPUInfo _U_
, int selector _U_
)
136 if (!ws_cpuid(CPUInfo
, 1))
139 /* in ECX bit 20 toggled on */
140 return (CPUInfo
[2] & (1 << 20));