1
/*********************************************************
2
* Copyright (C) 1998 VMware, Inc. All rights reserved.
4
* This program is free software; you can redistribute it and/or modify it
5
* under the terms of the GNU Lesser General Public License as published
6
* by the Free Software Foundation version 2.1 and no later version.
8
* This program is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10
* or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
11
* License for more details.
13
* You should have received a copy of the GNU Lesser General Public License
14
* along with this program; if not, write to the Free Software Foundation, Inc.,
15
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17
*********************************************************/
22
* Platform-independent code that calls into hostinfo<OS>-specific
29
#include "cpuid_info.h"
33
#define LOGLEVEL_MODULE hostinfo
34
#include "loglevel_user.h"
36
#define LGPFX "HOSTINFO:"
40
*----------------------------------------------------------------------
42
* HostInfoGetIntelCPUCount --
44
* For an Intel processor, determine the number of cores per physical
45
* CPU and the number of threads per core.
49
* TRUE if the information was successfully gathered, FALSE if
55
*----------------------------------------------------------------------
59
HostInfoGetIntelCPUCount(CPUIDSummary *cpuid, // IN
60
uint32 *numCoresPerPCPU, // OUT
61
uint32 *numThreadsPerCore) // OUT
63
*numCoresPerPCPU = CPUIDSummary_IntelCoresPerPackage(cpuid,
71
*----------------------------------------------------------------------
73
* HostInfoGetAMDCPUCount --
75
* For an AMD processor, determine the number of cores per physical
76
* CPU and the number of threads per core.
80
* TRUE if the information was successfully gathered, FALSE if
86
*----------------------------------------------------------------------
90
HostInfoGetAMDCPUCount(CPUIDSummary *cpuid, // IN
91
uint32 *numCoresPerPCPU, // OUT
92
uint32 *numThreadsPerCore) // OUT
94
*numCoresPerPCPU = CPUIDSummary_AMDCoresPerPackage(cpuid,
102
*-----------------------------------------------------------------------------
104
* Hostinfo_GetCpuid --
106
* Get cpuid information for a CPU. Which CPU the information is for
107
* depends on the OS scheduler. We are assuming that all CPUs in
108
* the system have identical numbers of cores and threads.
111
* TRUE if the processor supports the cpuid instruction and this
112
* is a process we recognize, FALSE otherwise.
117
*-----------------------------------------------------------------------------
121
Hostinfo_GetCpuid(HostinfoCpuIdInfo *info) // OUT
125
uint32 numCoresPerPCPU, numThreadsPerCore;
128
* Can't do cpuid = {0} as an initializer above because gcc throws
129
* some idiotic warning.
132
memset(&cpuid, 0, sizeof(cpuid));
135
* Get basic and extended CPUID info.
138
__GET_CPUID(0, &id0);
140
cpuid.id0.numEntries = id0.eax;
142
if (0 == cpuid.id0.numEntries) {
143
Warning(LGPFX" No CPUID information available.\n");
148
*(uint32*)(cpuid.id0.name + 0) = id0.ebx;
149
*(uint32*)(cpuid.id0.name + 4) = id0.edx;
150
*(uint32*)(cpuid.id0.name + 8) = id0.ecx;
151
*(uint32*)(cpuid.id0.name + 12) = 0;
153
__GET_CPUID(1, (CPUIDRegs*)&cpuid.id1);
154
__GET_CPUID(0xa, (CPUIDRegs*)&cpuid.ida);
155
__GET_CPUID(0x80000000, (CPUIDRegs*)&cpuid.id80);
156
__GET_CPUID(0x80000001, (CPUIDRegs*)&cpuid.id81);
157
__GET_CPUID(0x80000008, (CPUIDRegs*)&cpuid.id88);
160
* Calculate vendor and CPU count information.
163
if (0 == strcmp(cpuid.id0.name, CPUID_INTEL_VENDOR_STRING_FIXED)) {
164
info->vendor = CPUID_VENDOR_INTEL;
165
if (!HostInfoGetIntelCPUCount(&cpuid, &numCoresPerPCPU,
166
&numThreadsPerCore)) {
167
Warning(LGPFX" Failed to get Intel CPU count.\n");
172
Log(LGPFX" Seeing Intel CPU, numCoresPerCPU %u numThreadsPerCore %u.\n",
173
numCoresPerPCPU, numThreadsPerCore);
174
} else if (strcmp(cpuid.id0.name, CPUID_AMD_VENDOR_STRING_FIXED) == 0) {
175
info->vendor = CPUID_VENDOR_AMD;
176
if (!HostInfoGetAMDCPUCount(&cpuid, &numCoresPerPCPU,
177
&numThreadsPerCore)) {
178
Warning(LGPFX" Failed to get AMD CPU count.\n");
183
Log(LGPFX" Seeing AMD CPU, numCoresPerCPU %u numThreadsPerCore %u.\n",
184
numCoresPerPCPU, numThreadsPerCore);
186
info->vendor = CPUID_VENDOR_UNKNOWN;
188
// assume one core per CPU, one thread per core
190
numThreadsPerCore = 1;
192
Log(LGPFX" Unknown CPU vendor \"%s\" seen, assuming one core per CPU "
193
"and one thread per core.\n", cpuid.id0.name);
196
info->numLogCPUs = Hostinfo_NumCPUs();
198
if (-1 == info->numLogCPUs) {
199
Warning(LGPFX" Failed to get logical CPU count.\n");
206
* The host can avoid scheduling hypertwins, regardless of the CPU
207
* supporting it or hyperthreading being enabled in the BIOS. This leads
208
* to numThreadsPerCore set to 2 when it should be 1.
211
if (Hostinfo_HTDisabled()) {
212
Log(LGPFX" hyperthreading disabled, setting number of threads per core "
214
numThreadsPerCore = 1;
218
info->numPhysCPUs = info->numLogCPUs / (numCoresPerPCPU *
221
if (0 == info->numPhysCPUs) {
222
// UP kernel case, possibly
223
Log(LGPFX" numPhysCPUs is 0, bumping to 1.\n");
224
info->numPhysCPUs = 1;
227
info->numCores = info->numLogCPUs / numThreadsPerCore;
229
if (0 == info->numCores) {
230
// UP kernel case, possibly
231
Log(LGPFX" numCores is 0, bumping to 1.\n");
235
Log(LGPFX" This machine has %u physical CPUS, %u total cores, and %u "
236
"logical CPUs.\n", info->numPhysCPUs, info->numCores,
240
* Pull out versioning and feature information.
243
info->version = cpuid.id1.version;
244
info->family = CPUID_FAMILY(cpuid.id1.version);
245
info->model = CPUID_MODEL(cpuid.id1.version);
246
info->stepping = CPUID_STEPPING(cpuid.id1.version);
247
info->type = (cpuid.id1.version >> 12) & 0x0003;
249
info->extfeatures = cpuid.id1.ecxFeatures;
250
info->features = cpuid.id1.edxFeatures;
257
*----------------------------------------------------------------------
259
* Hostinfo_HypervisorCPUIDSig --
261
* Get the hypervisor signature string from CPUID.
264
* Unqualified 16 byte nul-terminated hypervisor string
265
* String may contain garbage and caller must free
270
*----------------------------------------------------------------------
274
Hostinfo_HypervisorCPUIDSig(void)
279
__GET_CPUID(1, ®s);
280
if (!(regs.ecx & CPUID_FEATURE_COMMON_ID1ECX_HYPERVISOR)) {
288
__GET_CPUID(0x40000000, ®s);
290
if (regs.eax < 0x40000000) {
291
Log(LGPFX" CPUID hypervisor bit is set, but no "
292
"hypervisor vendor signature is present\n");
295
name = Util_SafeMalloc(4 * sizeof *name);
307
*----------------------------------------------------------------------
309
* Hostinfo_TouchXen --
313
* Official way is to call Hostinfo_HypervisorCPUIDSig(), which
314
* returns a hypervisor string. This is a secondary check
315
* that guards against a backdoor failure. See PR156185,
316
* http://xenbits.xensource.com/xen-unstable.hg?file/6a383beedf83/tools/misc/xen-detect.c
317
* (Canonical way is /proc/xen, but CPUID is better).
320
* TRUE if we are running in a Xen dom0 or domU.
322
* Illegal instruction exception on real hardware.
323
* Obscure Xen implementations might return FALSE.
325
* FALSE on real hardware.
328
* Linux: Will raise exception on native hardware.
331
*----------------------------------------------------------------------
335
Hostinfo_TouchXen(void)
337
#if defined(linux) && (defined(__i386__) || defined(__x86_64__))
338
#define XEN_CPUID 0x40000000
343
* PV mode: ud2a "xen" cpuid (faults on native hardware).
344
* (Only Linux can run PV, so skip others here).
345
* Since PV cannot trap CPUID, this is a Xen hook.
348
regs.eax = XEN_CPUID;
349
__asm__ __volatile__(
350
"xchgl %%ebx, %0" "\n\t"
351
"ud2a ; .ascii \"xen\" ; cpuid" "\n\t"
353
: "=&r" (regs.ebx), "=&c" (regs.ecx), "=&d" (regs.edx)
362
if (0 == strcmp(CPUID_XEN_HYPERVISOR_VENDOR_STRING, (const char*)name)) {
366
/* Passed checks. But native and anything non-Xen would #UD before here. */
368
Log("Xen detected but hypervisor unrecognized (Xen variant?)\n");
369
Log("CPUID 0x4000 0000: eax=%x ebx=%x ecx=%x edx=%x\n",
370
regs.eax, regs.ebx, regs.ecx, regs.edx);