Coverage Report

Created: 2026-06-30 07:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}
cpu_info.c:ws_cpuid
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
}