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

« back to all changes in this revision

Viewing changes to lib/include/x86cpuid_asm.h

  • 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) 2003-2009 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
 * The contents of this file are subject to the terms of the Common
 
21
 * Development and Distribution License (the "License") version 1.0
 
22
 * and no later version.  You may not use this file except in
 
23
 * compliance with the License.
 
24
 *
 
25
 * You can obtain a copy of the License at
 
26
 *         http://www.opensource.org/licenses/cddl1.php
 
27
 *
 
28
 * See the License for the specific language governing permissions
 
29
 * and limitations under the License.
 
30
 *
 
31
 *********************************************************/
 
32
 
 
33
/*
 
34
 * x86cpuid_asm.h
 
35
 *
 
36
 *      CPUID-related assembly functions.
 
37
 */
 
38
 
 
39
#ifndef _X86CPUID_ASM_H_
 
40
#define _X86CPUID_ASM_H_
 
41
 
 
42
#define INCLUDE_ALLOW_USERLEVEL
 
43
#define INCLUDE_ALLOW_VMMEXT
 
44
#define INCLUDE_ALLOW_MODULE
 
45
#define INCLUDE_ALLOW_VMMON
 
46
#define INCLUDE_ALLOW_VMNIXMOD
 
47
#define INCLUDE_ALLOW_VMK_MODULE
 
48
#define INCLUDE_ALLOW_VMKERNEL
 
49
#define INCLUDE_ALLOW_DISTRIBUTE
 
50
#define INCLUDE_ALLOW_VMCORE
 
51
#include "includeCheck.h"
 
52
 
 
53
#include "vm_basic_asm.h"
 
54
#include "x86cpuid.h"
 
55
 
 
56
 
 
57
/*
 
58
 * x86-64 windows doesn't support inline asm so we have to use these
 
59
 * intrinsic functions defined in the compiler.  Not all of these are well
 
60
 * documented.  There is an array in the compiler dll (c1.dll) which has
 
61
 * an array of the names of all the intrinsics minus the leading
 
62
 * underscore.  Searching around in the ntddk.h file can also be helpful.
 
63
 *
 
64
 * The declarations for the intrinsic functions were taken from the DDK. 
 
65
 * Our declarations must match the ddk's otherwise the 64-bit c++ compiler
 
66
 * will complain about second linkage of the intrinsic functions.
 
67
 * We define the intrinsic using the basic types corresponding to the 
 
68
 * Windows typedefs. This avoids having to include windows header files
 
69
 * to get to the windows types.
 
70
 */
 
71
#ifdef _MSC_VER
 
72
#ifdef __cplusplus
 
73
extern "C" {
 
74
#endif
 
75
#ifdef VM_X86_64
 
76
/*
 
77
 * intrinsic functions only supported by x86-64 windows as of 2k3sp1
 
78
 */
 
79
void             __cpuid(unsigned int*, unsigned int);
 
80
#pragma intrinsic(__cpuid)
 
81
#endif /* VM_X86_64 */
 
82
 
 
83
#ifdef __cplusplus
 
84
}
 
85
#endif
 
86
#endif /* _MSC_VER */
 
87
 
 
88
 
 
89
#ifdef __GNUC__ // {
 
90
 
 
91
/*
 
92
 * Checked against the Intel manual and GCC --hpreg
 
93
 * 
 
94
 * Need __volatile__ and "memory" since CPUID has a synchronizing effect.
 
95
 * The CPUID may also change at runtime (APIC flag, etc).
 
96
 *
 
97
 */
 
98
 
 
99
static INLINE void
 
100
__GET_CPUID(int eax,         // IN
 
101
            CPUIDRegs *regs) // OUT
 
102
{
 
103
   __asm__ __volatile__(
 
104
#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler.
 
105
      "movl %%ebx, %1"  "\n\t"
 
106
      "cpuid"           "\n\t"
 
107
      "xchgl %%ebx, %1"
 
108
      : "=a" (regs->eax), "=&rm" (regs->ebx), "=c" (regs->ecx), "=d" (regs->edx)
 
109
#else
 
110
      "cpuid"
 
111
      : "=a" (regs->eax), "=b" (regs->ebx), "=c" (regs->ecx), "=d" (regs->edx)
 
112
#endif
 
113
      : "a" (eax)
 
114
      : "memory"
 
115
   );
 
116
}
 
117
 
 
118
static INLINE void
 
119
__GET_CPUID2(int eax,         // IN
 
120
             int ecx,         // IN
 
121
             CPUIDRegs *regs) // OUT
 
122
{
 
123
   __asm__ __volatile__(
 
124
#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler.
 
125
      "movl %%ebx, %1"  "\n\t"
 
126
      "cpuid"           "\n\t"
 
127
      "xchgl %%ebx, %1"
 
128
      : "=a" (regs->eax), "=&rm" (regs->ebx), "=c" (regs->ecx), "=d" (regs->edx)
 
129
#else
 
130
      "cpuid"
 
131
      : "=a" (regs->eax), "=b" (regs->ebx), "=c" (regs->ecx), "=d" (regs->edx)
 
132
#endif
 
133
      : "a" (eax), "c" (ecx)
 
134
      : "memory"
 
135
   );
 
136
}
 
137
 
 
138
static INLINE uint32
 
139
__GET_EAX_FROM_CPUID(int eax) // IN
 
140
{
 
141
#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler.
 
142
   uint32 ebx;
 
143
 
 
144
   __asm__ __volatile__(
 
145
      "movl %%ebx, %1"  "\n\t"
 
146
      "cpuid"           "\n\t"
 
147
      "xchgl %%ebx, %1"
 
148
      : "=a" (eax), "=&rm" (ebx)
 
149
      : "a" (eax)
 
150
      : "memory", "%ecx", "%edx"
 
151
   );
 
152
#else
 
153
   __asm__ __volatile__(
 
154
      "cpuid"
 
155
      : "=a" (eax)
 
156
      : "a" (eax)
 
157
      : "memory", "%ebx", "%ecx", "%edx"
 
158
   );
 
159
#endif
 
160
 
 
161
   return eax;
 
162
}
 
163
 
 
164
static INLINE uint32
 
165
__GET_EBX_FROM_CPUID(int eax) // IN
 
166
{
 
167
   uint32 ebx;
 
168
 
 
169
   __asm__ __volatile__(
 
170
#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler.
 
171
      "movl %%ebx, %1"  "\n\t"
 
172
      "cpuid"           "\n\t"
 
173
      "xchgl %%ebx, %1"
 
174
      : "=a" (eax), "=&rm" (ebx)
 
175
#else
 
176
      "cpuid"
 
177
      : "=a" (eax), "=b" (ebx)
 
178
#endif
 
179
      : "a" (eax)
 
180
      : "memory", "%ecx", "%edx"
 
181
   );
 
182
 
 
183
   return ebx;
 
184
}
 
185
 
 
186
static INLINE uint32
 
187
__GET_ECX_FROM_CPUID(int eax) // IN
 
188
{
 
189
   uint32 ecx;
 
190
#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler.
 
191
   uint32 ebx;
 
192
 
 
193
   __asm__ __volatile__(
 
194
      "movl %%ebx, %1"  "\n\t"
 
195
      "cpuid"           "\n\t"
 
196
      "xchgl %%ebx, %1"
 
197
      : "=a" (eax), "=&rm" (ebx), "=c" (ecx)
 
198
      : "a" (eax)
 
199
      : "memory", "%edx"
 
200
   );
 
201
#else
 
202
 
 
203
   __asm__ __volatile__(
 
204
      "cpuid"
 
205
      : "=a" (eax), "=c" (ecx)
 
206
      : "a" (eax)
 
207
      : "memory", "%ebx", "%edx"
 
208
   );
 
209
#endif
 
210
 
 
211
   return ecx;
 
212
}
 
213
 
 
214
static INLINE uint32
 
215
__GET_EDX_FROM_CPUID(int eax) // IN
 
216
{
 
217
   uint32 edx;
 
218
#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler.
 
219
   uint32 ebx;
 
220
 
 
221
   __asm__ __volatile__(
 
222
      "movl %%ebx, %1"  "\n\t"
 
223
      "cpuid"           "\n\t"
 
224
      "xchgl %%ebx, %1"
 
225
      : "=a" (eax), "=&rm" (ebx), "=d" (edx)
 
226
      : "a" (eax)
 
227
      : "memory", "%ecx"
 
228
   );
 
229
#else
 
230
 
 
231
   __asm__ __volatile__(
 
232
      "cpuid"
 
233
      : "=a" (eax), "=d" (edx)
 
234
      : "a" (eax)
 
235
      : "memory", "%ebx", "%ecx"
 
236
   );
 
237
#endif
 
238
 
 
239
   return edx;
 
240
}
 
241
 
 
242
 
 
243
static INLINE uint32
 
244
__GET_EAX_FROM_CPUID4(int ecx) // IN
 
245
{
 
246
   uint32 eax;
 
247
#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler.
 
248
   uint32 ebx;
 
249
 
 
250
   __asm__ __volatile__(
 
251
      "movl %%ebx, %1"  "\n\t"
 
252
      "cpuid"           "\n\t"
 
253
      "xchgl %%ebx, %1"
 
254
      : "=a" (eax), "=&rm" (ebx), "=c" (ecx)
 
255
      : "a" (4), "c" (ecx)
 
256
      : "memory", "%edx"
 
257
   );
 
258
#else
 
259
 
 
260
   __asm__ __volatile__(
 
261
      "cpuid"
 
262
      : "=a" (eax), "=c" (ecx)
 
263
      : "a" (4), "c" (ecx)
 
264
      : "memory", "%ebx", "%edx"
 
265
   );
 
266
#endif
 
267
 
 
268
   return eax;
 
269
}
 
270
 
 
271
#elif defined(_MSC_VER) // } {
 
272
 
 
273
static INLINE void
 
274
__GET_CPUID(int input, CPUIDRegs *regs)
 
275
{
 
276
#ifdef VM_X86_64
 
277
   __cpuid((unsigned int *)regs, input);
 
278
#else
 
279
   __asm push esi
 
280
   __asm push ebx
 
281
   __asm push ecx
 
282
   __asm push edx
 
283
 
 
284
   __asm mov  eax, input
 
285
   __asm mov  esi, regs
 
286
   __asm _emit 0x0f __asm _emit 0xa2
 
287
   __asm mov 0x0[esi], eax
 
288
   __asm mov 0x4[esi], ebx
 
289
   __asm mov 0x8[esi], ecx
 
290
   __asm mov 0xC[esi], edx
 
291
 
 
292
   __asm pop edx
 
293
   __asm pop ecx
 
294
   __asm pop ebx
 
295
   __asm pop esi
 
296
#endif
 
297
}
 
298
 
 
299
#ifdef VM_X86_64
 
300
 
 
301
/*
 
302
 * No inline assembly in Win64. Implemented in bora/lib/user in
 
303
 * cpuidMasm64.asm.
 
304
 */
 
305
 
 
306
extern void
 
307
__GET_CPUID2(int inputEax, int inputEcx, CPUIDRegs *regs);
 
308
 
 
309
#else // VM_X86_64
 
310
 
 
311
static INLINE void
 
312
__GET_CPUID2(int inputEax, int inputEcx, CPUIDRegs *regs)
 
313
{
 
314
   __asm push esi
 
315
   __asm push ebx
 
316
   __asm push ecx
 
317
   __asm push edx
 
318
 
 
319
   __asm mov  eax, inputEax
 
320
   __asm mov  ecx, inputEcx
 
321
   __asm mov  esi, regs
 
322
   __asm _emit 0x0f __asm _emit 0xa2
 
323
   __asm mov 0x0[esi], eax
 
324
   __asm mov 0x4[esi], ebx
 
325
   __asm mov 0x8[esi], ecx
 
326
   __asm mov 0xC[esi], edx
 
327
 
 
328
   __asm pop edx
 
329
   __asm pop ecx
 
330
   __asm pop ebx
 
331
   __asm pop esi
 
332
}
 
333
#endif
 
334
 
 
335
static INLINE uint32
 
336
__GET_EAX_FROM_CPUID(int input)
 
337
{
 
338
#ifdef VM_X86_64
 
339
   CPUIDRegs regs;
 
340
   __cpuid((unsigned int *)&regs, input);
 
341
   return regs.eax;
 
342
#else
 
343
   uint32 output;
 
344
 
 
345
   //NOT_TESTED();
 
346
   __asm push ebx
 
347
   __asm push ecx
 
348
   __asm push edx
 
349
 
 
350
   __asm mov  eax, input
 
351
   __asm _emit 0x0f __asm _emit 0xa2
 
352
   __asm mov  output, eax
 
353
 
 
354
   __asm pop edx
 
355
   __asm pop ecx
 
356
   __asm pop ebx
 
357
 
 
358
   return output;
 
359
#endif
 
360
}
 
361
 
 
362
static INLINE uint32
 
363
__GET_EBX_FROM_CPUID(int input)
 
364
{
 
365
#ifdef VM_X86_64
 
366
   CPUIDRegs regs;
 
367
   __cpuid((unsigned int *)&regs, input);
 
368
   return regs.ebx;
 
369
#else
 
370
   uint32 output;
 
371
 
 
372
   //NOT_TESTED();
 
373
   __asm push ebx
 
374
   __asm push ecx
 
375
   __asm push edx
 
376
 
 
377
   __asm mov  eax, input
 
378
   __asm _emit 0x0f __asm _emit 0xa2
 
379
   __asm mov  output, ebx
 
380
 
 
381
   __asm pop edx
 
382
   __asm pop ecx
 
383
   __asm pop ebx
 
384
 
 
385
   return output;
 
386
#endif
 
387
}
 
388
 
 
389
static INLINE uint32
 
390
__GET_ECX_FROM_CPUID(int input)
 
391
{
 
392
#ifdef VM_X86_64
 
393
   CPUIDRegs regs;
 
394
   __cpuid((unsigned int *)&regs, input);
 
395
   return regs.ecx;
 
396
#else
 
397
   uint32 output;
 
398
 
 
399
   //NOT_TESTED();
 
400
   __asm push ebx
 
401
   __asm push ecx
 
402
   __asm push edx
 
403
 
 
404
   __asm mov  eax, input
 
405
   __asm _emit 0x0f __asm _emit 0xa2
 
406
   __asm mov  output, ecx
 
407
 
 
408
   __asm pop edx
 
409
   __asm pop ecx
 
410
   __asm pop ebx
 
411
 
 
412
   return output;
 
413
#endif
 
414
}
 
415
 
 
416
static INLINE uint32
 
417
__GET_EDX_FROM_CPUID(int input)
 
418
{
 
419
#ifdef VM_X86_64
 
420
   CPUIDRegs regs;
 
421
   __cpuid((unsigned int *)&regs, input);
 
422
   return regs.edx;
 
423
#else
 
424
   uint32 output;
 
425
 
 
426
   //NOT_TESTED();
 
427
   __asm push ebx
 
428
   __asm push ecx
 
429
   __asm push edx
 
430
 
 
431
   __asm mov  eax, input
 
432
   __asm _emit 0x0f __asm _emit 0xa2
 
433
   __asm mov  output, edx
 
434
 
 
435
   __asm pop edx
 
436
   __asm pop ecx
 
437
   __asm pop ebx
 
438
 
 
439
   return output;
 
440
#endif
 
441
}
 
442
 
 
443
#ifdef VM_X86_64
 
444
 
 
445
/*
 
446
 * No inline assembly in Win64. Implemented in bora/lib/user in
 
447
 * cpuidMasm64.asm.
 
448
 */
 
449
 
 
450
extern uint32
 
451
__GET_EAX_FROM_CPUID4(int inputEcx);
 
452
 
 
453
#else // VM_X86_64
 
454
 
 
455
static INLINE uint32
 
456
__GET_EAX_FROM_CPUID4(int inputEcx)
 
457
{
 
458
   uint32 output;
 
459
 
 
460
   //NOT_TESTED();
 
461
   __asm push ebx
 
462
   __asm push ecx
 
463
   __asm push edx
 
464
 
 
465
   __asm mov  eax, 4
 
466
   __asm mov  ecx, inputEcx
 
467
   __asm _emit 0x0f __asm _emit 0xa2
 
468
   __asm mov  output, eax
 
469
 
 
470
   __asm pop edx
 
471
   __asm pop ecx
 
472
   __asm pop ebx
 
473
 
 
474
   return output;
 
475
}
 
476
 
 
477
#endif // VM_X86_64
 
478
 
 
479
#else // }
 
480
#error 
 
481
#endif
 
482
 
 
483
#define CPUID_FOR_SIDE_EFFECTS() ((void)__GET_EAX_FROM_CPUID(0))
 
484
 
 
485
static INLINE void
 
486
__GET_CPUID4(int inputEcx, CPUIDRegs *regs)
 
487
{
 
488
   __GET_CPUID2(4, inputEcx, regs);
 
489
}
 
490
 
 
491
/* The first parameter is used as an rvalue and then as an lvalue. */
 
492
#define GET_CPUID(_ax, _bx, _cx, _dx) { \
 
493
   CPUIDRegs regs;                      \
 
494
   __GET_CPUID(_ax, &regs);             \
 
495
   _ax = regs.eax;                      \
 
496
   _bx = regs.ebx;                      \
 
497
   _cx = regs.ecx;                      \
 
498
   _dx = regs.edx;                      \
 
499
}
 
500
 
 
501
 
 
502
#endif