-
Notifications
You must be signed in to change notification settings - Fork 0
/
cpuid
executable file
·208 lines (192 loc) · 7.46 KB
/
cpuid
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/************ Beginning of source file sse41andsse42detection.cpp ********************/
/* Copyright 2009 Intel Corporation
* sse41andsse42detection.cpp
* This file uses code first published by Intel as part of the processor enumeration
* article available on the internet at:
* http://software.intel.com/en-us/articles/intel-64-architecture-processor-topology- * enumeration/
* Some of the original code from cpu_topo.c
* has been removed, while other code has been added to illustrate the CPUID usage
* to determine if the processor supports the SSE 4.1 and SSE 4.2 instruction sets.
* The reference code provided in this file is for demonstration purpose only. It assumes
* the hardware topology configuration within a coherent domain does not change during
* the life of an OS session. If an OS support advanced features that can change
* hardware topology configurations, more sophisticated adaptation may be necessary
* to account for the hardware configuration change that might have added and reduced
* the number of logical processors being managed by the OS.
*
* Users of this code should be aware that the provided code
* relies on CPUID instruction providing raw data reflecting the native hardware
* configuration. When an application runs inside a virtual machine hosted by a
* Virtual Machine Monitor (VMM), any CPUID instructions issued by an app (or a guest OS)
* are trapped by the VMM and it is the VMM's responsibility and decision to emulate
* CPUID return data to the virtual machines. When deploying topology enumeration code based
* on CPUID inside a VM environment, the user must consult with the VMM vendor on how an VMM
* will emulate CPUID instruction relating to topology enumeration.
*
* Original code written by Patrick Fay, Ronen Zohar and Shihjong Kuo .
* Modified by Garrett Drysdale for current application note.
*/
#include "sse41andsse42detection.h"
#define SSE4_1_FLAG 0x080000
#define SSE4_2_FLAG 0x100000
int isSSE41andSSE42Supported (void)
{
// returns 1 if is a Nehalem or later processor, 0 if prior to Nehalem
CPUIDinfo Info;
int rVal = 0;
// The code first determines if the processor is an Intel Processor. If it is, then
// feature flags bit 19 (SSE 4.1) and 20 (SSE 4.2) in ECX after CPUID call with EAX = 0x1
// are checked.
// If both bits are 1 (indicating both SSE 4.1 and SSE 4.2 exist) then
// the function returns 1
const int CHECKBITS = SSE4_1_FLAG | SSE4_2_FLAG;
if (isGenuineIntel() >= 1)
{
// execute CPUID with eax (leaf) = 1 to get feature bits,
// subleaf doesn't matter so set it to zero
get_cpuid_info(&Info, 0x1, 0x0);
if ((Info.ECX & CHECKBITS) == CHECKBITS)
{
rVal = 1;
}
}
return(rVal);
}
int isGenuineIntel (void)
{
// returns largest function # supported by CPUID if it is a Geniune Intel processor AND it supports
// the CPUID instruction, 0 if not
CPUIDinfo Info;
int rVal = 0;
char procString[] = "GenuineIntel";
if (isCPUIDsupported())
{
// execute CPUID with eax = 0, subleaf doesn't matter so set it to zero
get_cpuid_info(&Info, 0x0, 0x0);
if ((Info.EBX == ((int *)procString)[0]) &&
(Info.EDX == ((int *)procString)[1]) && (Info.ECX == ((int *)procString)[2]))
{
rVal = Info.EAX;
}
}
return(rVal);
}
#if (defined(__x86_64__) || defined(_M_X64))
// This code is assembly for 64 bit target OS.
// Assembly code must be compiled with the –use-msasm switch for Linux targets with the
// Intel compiler.
int isCPUIDsupported (void)
{
// returns 1 if CPUID instruction supported on this processor, zero otherwise
// This isn't necessary on 64 bit processors because all 64 bit processor support CPUID
return((int) 1);
}
void get_cpuid_info (CPUIDinfo *Info, const unsigned int leaf, const unsigned int subleaf)
{
// Stores CPUID return Info in the CPUIDinfo structure.
// leaf and subleaf used as parameters to the CPUID instruction
// parameters and register usage designed to be safe for both Windows and Linux
// Use the Intel compiler option -use-msasm when the target is Linux
__asm
{
mov r10d, subleaf ; arg2, subleaf (in R8 on WIN, in RDX on Linux)
mov r8, Info ; arg0, array addr (in RCX on WIN, in RDI on Linux)
mov r9d, leaf ; arg1, leaf (in RDX on WIN, in RSI on Linux)
push rax
push rbx
push rcx
push rdx
mov eax, r9d
mov ecx, r10d
cpuid
mov DWORD PTR [r8], eax
mov DWORD PTR [r8+4], ebx
mov DWORD PTR [r8+8], ecx
mov DWORD PTR [r8+12], edx
pop rdx
pop rcx
pop rbx
pop rax
}
}
#else // 32 bit
//Note need to make sure -use-msasm switch is used with Intel compiler for Linux to get the
// ASM code to compile for both windows and linux with one version source
int isCPUIDsupported (void)
{
// returns 1 if CPUID instruction supported on this processor, zero otherwise
// This isn't necessary on 64 bit processors because all 64 bit Intel processors support CPUID
__asm
{
push ecx ; save ecx
pushfd ; push original EFLAGS
pop eax ; get original EFLAGS
mov ecx, eax ; save original EFLAGS
xor eax, 200000h ; flip bit 21 in EFLAGS
push eax ; save new EFLAGS value on stack
popfd ; replace current EFLAGS value
pushfd ; get new EFLAGS
pop eax ; store new EFLAGS in EAX
xor eax, ecx ; Bit 21 of flags at 200000h will be 1 if CPUID exists
shr eax, 21 ; Shift bit 21 bit 0 and return it
push ecx
popfd ; restore bit 21 in EFLAGS first
pop ecx ; restore ecx
}
}
//Note need to make sure -use-msasm switch is used with Intel compiler for Linux to get the
// ASM code to compile for both windows and linux with one version source
void get_cpuid_info (CPUIDinfo *Info, const unsigned int leaf, const unsigned int subleaf)
{
// Stores CPUID return Info in the CPUIDinfo structure.
// leaf and subleaf used as parameters to the CPUID instruction
// parameters and registure usage designed to be safe for both Win and Linux
// when using -use-msasm
__asm
{
mov edx, Info ; addr of start of output array
mov eax, leaf ; leaf
mov ecx, subleaf ; subleaf
push edi
push ebx
mov edi, edx ; edi has output addr
cpuid
mov DWORD PTR [edi], eax
mov DWORD PTR [edi+4], ebx
mov DWORD PTR [edi+8], ecx
mov DWORD PTR [edi+12], edx
pop ebx
pop edi
ret
}
}
#endif
/************ End of source file sse41andsse42detection.cpp *******************************/
/************ Beginning of source file sse41andsse42detection.h ***************************/
/* Copyright 2008 Intel Corporation
* The source code contained or described herein and all documents related
* to the source code ("Material") are owned by Intel Corporation or
* its suppliers or licensors. Use of this material must comply with the
* rights and restrictions set forth in the accompnied license terms set
* forth in file "license.rtf".
*
* Original code contained in cputopology.h.
* This file has been renamed to cpuid.h for this app note, code removed, and some
* code added.
*
* This is the header file that contain type definitions
* and prototypes of functions in the file cpuid.cpp
* The source files can be compiled under 32-bit and 64-bit Windows and Linux.
*
* Original code written by Patrick Fay and Shihjong Kuo
* Modified by Garrett Drysdale for this application note.
*/
typedef struct
{
unsigned __int32 EAX,EBX,ECX,EDX;
} CPUIDinfo;
void get_cpuid_info (CPUIDinfo *, const unsigned int, const unsigned int);
int isCPUIDsupported (void);
int isGenuineIntel (void);
int isSSE41andSSE42Supported (void);
/************ End of source file sse41andsse42detection.h ****************************/