~ubuntu-branches/ubuntu/quantal/open-vm-tools/quantal-201207201942

« back to all changes in this revision

Viewing changes to lib/misc/hostinfo.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Baumann
  • Date: 2009-10-18 12:28:19 UTC
  • mfrom: (1.1.7 upstream) (2.4.9 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091018122819-00vqew6m0ztpqcqp
Tags: 2009.10.15-201664-1
MergingĀ upstreamĀ versionĀ 2009.10.15-201664.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*********************************************************
 
2
 * Copyright (C) 1998 VMware, Inc. All rights reserved.
 
3
 *
 
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.
 
7
 *
 
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.
 
12
 *
 
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.
 
16
 *
 
17
 *********************************************************/
 
18
 
 
19
/*
 
20
 * hostinfo.c --
 
21
 *
 
22
 *    Platform-independent code that calls into hostinfo<OS>-specific
 
23
 *    code.
 
24
 */
 
25
 
 
26
#include "vmware.h"
 
27
#include <string.h>
 
28
 
 
29
#include "cpuid_info.h"
 
30
#include "hostinfo.h"
 
31
#include "util.h"
 
32
 
 
33
#define LOGLEVEL_MODULE hostinfo
 
34
#include "loglevel_user.h"
 
35
 
 
36
#define LGPFX "HOSTINFO:"
 
37
 
 
38
 
 
39
/*
 
40
 *----------------------------------------------------------------------
 
41
 *
 
42
 * HostInfoGetIntelCPUCount --
 
43
 *
 
44
 *      For an Intel processor, determine the number of cores per physical
 
45
 *      CPU and the number of threads per core.
 
46
 *
 
47
 * Results:
 
48
 *
 
49
 *      TRUE if the information was successfully gathered, FALSE if
 
50
 *      otherwise.
 
51
 *
 
52
 * Side effects:
 
53
 *      None.
 
54
 *
 
55
 *----------------------------------------------------------------------
 
56
 */
 
57
 
 
58
Bool
 
59
HostInfoGetIntelCPUCount(CPUIDSummary *cpuid,       // IN
 
60
                         uint32 *numCoresPerPCPU,   // OUT
 
61
                         uint32 *numThreadsPerCore) // OUT
 
62
{
 
63
   *numCoresPerPCPU = CPUIDSummary_IntelCoresPerPackage(cpuid,
 
64
                                                        numThreadsPerCore);
 
65
 
 
66
   return TRUE;
 
67
}
 
68
 
 
69
 
 
70
/*
 
71
 *----------------------------------------------------------------------
 
72
 *
 
73
 * HostInfoGetAMDCPUCount --
 
74
 *
 
75
 *      For an AMD processor, determine the number of cores per physical
 
76
 *      CPU and the number of threads per core.
 
77
 *
 
78
 * Results:
 
79
 *
 
80
 *      TRUE if the information was successfully gathered, FALSE if
 
81
 *      otherwise.
 
82
 *
 
83
 * Side effects:
 
84
 *      None.
 
85
 *
 
86
 *----------------------------------------------------------------------
 
87
 */
 
88
 
 
89
Bool
 
90
HostInfoGetAMDCPUCount(CPUIDSummary *cpuid,       // IN
 
91
                       uint32 *numCoresPerPCPU,   // OUT
 
92
                       uint32 *numThreadsPerCore) // OUT
 
93
{
 
94
   *numCoresPerPCPU = CPUIDSummary_AMDCoresPerPackage(cpuid,
 
95
                                                      numThreadsPerCore);
 
96
 
 
97
   return TRUE;
 
98
}
 
99
 
 
100
 
 
101
/*
 
102
 *-----------------------------------------------------------------------------
 
103
 *
 
104
 * Hostinfo_GetCpuid --
 
105
 *
 
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.
 
109
 *
 
110
 * Results:
 
111
 *       TRUE if the processor supports the cpuid instruction and this
 
112
 *       is a process we recognize, FALSE otherwise.
 
113
 *
 
114
 * Side effect:
 
115
 *       None
 
116
 *
 
117
 *-----------------------------------------------------------------------------
 
118
 */
 
119
 
 
120
Bool
 
121
Hostinfo_GetCpuid(HostinfoCpuIdInfo *info) // OUT
 
122
{
 
123
   CPUIDSummary cpuid;
 
124
   CPUIDRegs id0;
 
125
   uint32 numCoresPerPCPU, numThreadsPerCore;
 
126
 
 
127
   /*
 
128
    * Can't do cpuid = {0} as an initializer above because gcc throws
 
129
    * some idiotic warning.
 
130
    */
 
131
 
 
132
   memset(&cpuid, 0, sizeof(cpuid));
 
133
 
 
134
   /*
 
135
    * Get basic and extended CPUID info.
 
136
    */
 
137
 
 
138
   __GET_CPUID(0, &id0);
 
139
 
 
140
   cpuid.id0.numEntries = id0.eax;
 
141
 
 
142
   if (0 == cpuid.id0.numEntries) {
 
143
      Warning(LGPFX" No CPUID information available.\n");
 
144
 
 
145
      return FALSE;
 
146
   }
 
147
 
 
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;
 
152
 
 
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);
 
158
 
 
159
   /*
 
160
    * Calculate vendor and CPU count information.
 
161
    */
 
162
 
 
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");
 
168
 
 
169
         return FALSE;
 
170
      }
 
171
 
 
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");
 
179
 
 
180
         return FALSE;
 
181
      }
 
182
 
 
183
      Log(LGPFX" Seeing AMD CPU, numCoresPerCPU %u numThreadsPerCore %u.\n",
 
184
          numCoresPerPCPU, numThreadsPerCore);
 
185
   } else {
 
186
      info->vendor = CPUID_VENDOR_UNKNOWN;
 
187
 
 
188
      // assume one core per CPU, one thread per core
 
189
      numCoresPerPCPU = 1;
 
190
      numThreadsPerCore = 1;
 
191
 
 
192
      Log(LGPFX" Unknown CPU vendor \"%s\" seen, assuming one core per CPU "
 
193
               "and one thread per core.\n", cpuid.id0.name);
 
194
   }
 
195
 
 
196
   info->numLogCPUs = Hostinfo_NumCPUs();
 
197
 
 
198
   if (-1 == info->numLogCPUs) {
 
199
      Warning(LGPFX" Failed to get logical CPU count.\n");
 
200
 
 
201
      return FALSE;
 
202
   }
 
203
 
 
204
#ifdef VMX86_SERVER
 
205
   /*
 
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.
 
209
    */
 
210
 
 
211
   if (Hostinfo_HTDisabled()) {
 
212
      Log(LGPFX" hyperthreading disabled, setting number of threads per core "
 
213
               "to 1.\n");
 
214
      numThreadsPerCore = 1;
 
215
   } 
 
216
#endif
 
217
 
 
218
   info->numPhysCPUs = info->numLogCPUs / (numCoresPerPCPU *
 
219
                                           numThreadsPerCore);
 
220
 
 
221
   if (0 == info->numPhysCPUs) {
 
222
      // UP kernel case, possibly
 
223
      Log(LGPFX" numPhysCPUs is 0, bumping to 1.\n");
 
224
      info->numPhysCPUs = 1;
 
225
   }
 
226
 
 
227
   info->numCores = info->numLogCPUs / numThreadsPerCore;
 
228
 
 
229
   if (0 == info->numCores) {
 
230
      // UP kernel case, possibly
 
231
      Log(LGPFX" numCores is 0, bumping to 1.\n");
 
232
      info->numCores = 1;
 
233
   }
 
234
 
 
235
   Log(LGPFX" This machine has %u physical CPUS, %u total cores, and %u "
 
236
            "logical CPUs.\n", info->numPhysCPUs, info->numCores,
 
237
       info->numLogCPUs);
 
238
 
 
239
   /*
 
240
    * Pull out versioning and feature information.
 
241
    */
 
242
 
 
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;
 
248
 
 
249
   info->extfeatures = cpuid.id1.ecxFeatures;
 
250
   info->features = cpuid.id1.edxFeatures;
 
251
 
 
252
   return TRUE;
 
253
}
 
254
 
 
255
 
 
256
/*
 
257
 *----------------------------------------------------------------------
 
258
 *
 
259
 *  Hostinfo_HypervisorCPUIDSig --
 
260
 *
 
261
 *      Get the hypervisor signature string from CPUID.
 
262
 *
 
263
 * Results:
 
264
 *      Unqualified 16 byte nul-terminated hypervisor string
 
265
 *      String may contain garbage and caller must free
 
266
 *
 
267
 * Side effects:
 
268
 *      None
 
269
 *
 
270
 *----------------------------------------------------------------------
 
271
 */
 
272
 
 
273
char * 
 
274
Hostinfo_HypervisorCPUIDSig(void)
 
275
{
 
276
   CPUIDRegs regs;
 
277
   uint32 *name;
 
278
 
 
279
   __GET_CPUID(1, &regs);
 
280
   if (!(regs.ecx & CPUID_FEATURE_COMMON_ID1ECX_HYPERVISOR)) {
 
281
      return NULL;
 
282
   }
 
283
 
 
284
   regs.ebx = 0;
 
285
   regs.ecx = 0;
 
286
   regs.edx = 0;
 
287
 
 
288
   __GET_CPUID(0x40000000, &regs);
 
289
 
 
290
   if (regs.eax < 0x40000000) {
 
291
      Log(LGPFX" CPUID hypervisor bit is set, but no "
 
292
          "hypervisor vendor signature is present\n");
 
293
   }
 
294
 
 
295
   name = Util_SafeMalloc(4 * sizeof *name);
 
296
 
 
297
   name[0] = regs.ebx;
 
298
   name[1] = regs.ecx;
 
299
   name[2] = regs.edx;
 
300
   name[3] = 0;
 
301
 
 
302
   return (char *)name;
 
303
}
 
304
 
 
305
 
 
306
/*
 
307
 *----------------------------------------------------------------------
 
308
 *
 
309
 *  Hostinfo_TouchXen --
 
310
 *
 
311
 *      Check for Xen.
 
312
 *
 
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).
 
318
 *
 
319
 * Results:
 
320
 *      TRUE if we are running in a Xen dom0 or domU.
 
321
 *      Linux:
 
322
 *         Illegal instruction exception on real hardware.
 
323
 *         Obscure Xen implementations might return FALSE.
 
324
 *      Windows:
 
325
 *         FALSE on real hardware.
 
326
 *
 
327
 * Side effects:
 
328
 *      Linux: Will raise exception on native hardware.
 
329
 *      Windows: None.
 
330
 *
 
331
 *----------------------------------------------------------------------
 
332
 */
 
333
 
 
334
Bool
 
335
Hostinfo_TouchXen(void)
 
336
{
 
337
#if defined(linux) && (defined(__i386__) || defined(__x86_64__))
 
338
#define XEN_CPUID 0x40000000
 
339
   CPUIDRegs regs;
 
340
   uint32 name[4];
 
341
 
 
342
   /* 
 
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.
 
346
    */
 
347
 
 
348
   regs.eax = XEN_CPUID;
 
349
   __asm__ __volatile__(
 
350
      "xchgl %%ebx, %0"  "\n\t"
 
351
      "ud2a ; .ascii \"xen\" ; cpuid" "\n\t"
 
352
      "xchgl %%ebx, %0"
 
353
      : "=&r" (regs.ebx), "=&c" (regs.ecx), "=&d" (regs.edx)
 
354
      : "a" (regs.eax)
 
355
   );
 
356
 
 
357
   name[0] = regs.ebx;
 
358
   name[1] = regs.ecx;
 
359
   name[2] = regs.edx;
 
360
   name[3] = 0;
 
361
 
 
362
   if (0 == strcmp(CPUID_XEN_HYPERVISOR_VENDOR_STRING, (const char*)name)) {
 
363
      return TRUE;
 
364
   }
 
365
 
 
366
   /* Passed checks.  But native and anything non-Xen would #UD before here. */
 
367
   NOT_TESTED();
 
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);
 
371
#endif
 
372
 
 
373
   return FALSE;
 
374
}