VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/SUPDrvAgnostic.c@ 24198

Last change on this file since 24198 was 23728, checked in by vboxsync, 15 years ago

SUPDrv: Moving more stuff over.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.8 KB
Line 
1/* $Revision: 23728 $ */
2/** @file
3 * VBoxDrv - The VirtualBox Support Driver - Common OS agnostic.
4 */
5
6/*
7 * Copyright (C) 2006-2009 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31/*******************************************************************************
32* Header Files *
33*******************************************************************************/
34#define LOG_GROUP LOG_GROUP_SUP_DRV
35#define SUPDRV_AGNOSTIC
36#include "SUPDrvInternal.h"
37
38/** @todo trim this down. */
39#include <iprt/param.h>
40#include <iprt/alloc.h>
41#include <iprt/cpuset.h>
42#include <iprt/handletable.h>
43#include <iprt/mp.h>
44#include <iprt/power.h>
45#include <iprt/process.h>
46#include <iprt/semaphore.h>
47#include <iprt/spinlock.h>
48#include <iprt/thread.h>
49#include <iprt/uuid.h>
50
51#include <VBox/param.h>
52#include <VBox/log.h>
53#include <VBox/err.h>
54#include <VBox/hwacc_svm.h>
55#include <VBox/hwacc_vmx.h>
56#include <VBox/x86.h>
57
58
59/**
60 * Gets the paging mode of the current CPU.
61 *
62 * @returns Paging mode, SUPPAGEINGMODE_INVALID on error.
63 */
64SUPR0DECL(SUPPAGINGMODE) SUPR0GetPagingMode(void)
65{
66 SUPPAGINGMODE enmMode;
67
68 RTR0UINTREG cr0 = ASMGetCR0();
69 if ((cr0 & (X86_CR0_PG | X86_CR0_PE)) != (X86_CR0_PG | X86_CR0_PE))
70 enmMode = SUPPAGINGMODE_INVALID;
71 else
72 {
73 RTR0UINTREG cr4 = ASMGetCR4();
74 uint32_t fNXEPlusLMA = 0;
75 if (cr4 & X86_CR4_PAE)
76 {
77 uint32_t fAmdFeatures = ASMCpuId_EDX(0x80000001);
78 if (fAmdFeatures & (X86_CPUID_AMD_FEATURE_EDX_NX | X86_CPUID_AMD_FEATURE_EDX_LONG_MODE))
79 {
80 uint64_t efer = ASMRdMsr(MSR_K6_EFER);
81 if ((fAmdFeatures & X86_CPUID_AMD_FEATURE_EDX_NX) && (efer & MSR_K6_EFER_NXE))
82 fNXEPlusLMA |= RT_BIT(0);
83 if ((fAmdFeatures & X86_CPUID_AMD_FEATURE_EDX_LONG_MODE) && (efer & MSR_K6_EFER_LMA))
84 fNXEPlusLMA |= RT_BIT(1);
85 }
86 }
87
88 switch ((cr4 & (X86_CR4_PAE | X86_CR4_PGE)) | fNXEPlusLMA)
89 {
90 case 0:
91 enmMode = SUPPAGINGMODE_32_BIT;
92 break;
93
94 case X86_CR4_PGE:
95 enmMode = SUPPAGINGMODE_32_BIT_GLOBAL;
96 break;
97
98 case X86_CR4_PAE:
99 enmMode = SUPPAGINGMODE_PAE;
100 break;
101
102 case X86_CR4_PAE | RT_BIT(0):
103 enmMode = SUPPAGINGMODE_PAE_NX;
104 break;
105
106 case X86_CR4_PAE | X86_CR4_PGE:
107 enmMode = SUPPAGINGMODE_PAE_GLOBAL;
108 break;
109
110 case X86_CR4_PAE | X86_CR4_PGE | RT_BIT(0):
111 enmMode = SUPPAGINGMODE_PAE_GLOBAL;
112 break;
113
114 case RT_BIT(1) | X86_CR4_PAE:
115 enmMode = SUPPAGINGMODE_AMD64;
116 break;
117
118 case RT_BIT(1) | X86_CR4_PAE | RT_BIT(0):
119 enmMode = SUPPAGINGMODE_AMD64_NX;
120 break;
121
122 case RT_BIT(1) | X86_CR4_PAE | X86_CR4_PGE:
123 enmMode = SUPPAGINGMODE_AMD64_GLOBAL;
124 break;
125
126 case RT_BIT(1) | X86_CR4_PAE | X86_CR4_PGE | RT_BIT(0):
127 enmMode = SUPPAGINGMODE_AMD64_GLOBAL_NX;
128 break;
129
130 default:
131 AssertMsgFailed(("Cannot happen! cr4=%#x fNXEPlusLMA=%d\n", cr4, fNXEPlusLMA));
132 enmMode = SUPPAGINGMODE_INVALID;
133 break;
134 }
135 }
136 return enmMode;
137}
138
139
140/**
141 * Enables or disabled hardware virtualization extensions using native OS APIs.
142 *
143 * @returns VBox status code.
144 * @retval VINF_SUCCESS on success.
145 * @retval VERR_NOT_SUPPORTED if not supported by the native OS.
146 *
147 * @param fEnable Whether to enable or disable.
148 */
149SUPR0DECL(int) SUPR0EnableVTx(bool fEnable)
150{
151#ifdef RT_OS_DARWIN
152 return supdrvOSEnableVTx(fEnable);
153#else
154 return VERR_NOT_SUPPORTED;
155#endif
156}
157
158
159
160SUPR0DECL(int) SUPR0QueryVTCaps(PSUPDRVSESSION pSession, uint32_t *pfCaps)
161{
162 /*
163 * Input validation.
164 */
165 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
166 AssertPtrReturn(pfCaps, VERR_INVALID_POINTER);
167
168 *pfCaps = 0;
169
170 if (ASMHasCpuId())
171 {
172 uint32_t u32FeaturesECX;
173 uint32_t u32Dummy;
174 uint32_t u32FeaturesEDX;
175 uint32_t u32VendorEBX, u32VendorECX, u32VendorEDX, u32AMDFeatureEDX, u32AMDFeatureECX;
176 uint64_t val;
177
178 ASMCpuId(0, &u32Dummy, &u32VendorEBX, &u32VendorECX, &u32VendorEDX);
179 ASMCpuId(1, &u32Dummy, &u32Dummy, &u32FeaturesECX, &u32FeaturesEDX);
180 /* Query AMD features. */
181 ASMCpuId(0x80000001, &u32Dummy, &u32Dummy, &u32AMDFeatureECX, &u32AMDFeatureEDX);
182
183 if ( u32VendorEBX == X86_CPUID_VENDOR_INTEL_EBX
184 && u32VendorECX == X86_CPUID_VENDOR_INTEL_ECX
185 && u32VendorEDX == X86_CPUID_VENDOR_INTEL_EDX
186 )
187 {
188 if ( (u32FeaturesECX & X86_CPUID_FEATURE_ECX_VMX)
189 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR)
190 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR)
191 )
192 {
193 val = ASMRdMsr(MSR_IA32_FEATURE_CONTROL);
194 /*
195 * Both the LOCK and VMXON bit must be set; otherwise VMXON will generate a #GP.
196 * Once the lock bit is set, this MSR can no longer be modified.
197 */
198 if ( (val & (MSR_IA32_FEATURE_CONTROL_VMXON|MSR_IA32_FEATURE_CONTROL_LOCK))
199 == (MSR_IA32_FEATURE_CONTROL_VMXON|MSR_IA32_FEATURE_CONTROL_LOCK) /* enabled and locked */
200 || !(val & MSR_IA32_FEATURE_CONTROL_LOCK) /* not enabled, but not locked either */
201 )
202 {
203 VMX_CAPABILITY vtCaps;
204
205 *pfCaps |= SUPVTCAPS_VT_X;
206
207 vtCaps.u = ASMRdMsr(MSR_IA32_VMX_PROCBASED_CTLS);
208 if (vtCaps.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL)
209 {
210 vtCaps.u = ASMRdMsr(MSR_IA32_VMX_PROCBASED_CTLS2);
211 if (vtCaps.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_EPT)
212 *pfCaps |= SUPVTCAPS_NESTED_PAGING;
213 }
214 return VINF_SUCCESS;
215 }
216 return VERR_VMX_MSR_LOCKED_OR_DISABLED;
217 }
218 return VERR_VMX_NO_VMX;
219 }
220
221 if ( u32VendorEBX == X86_CPUID_VENDOR_AMD_EBX
222 && u32VendorECX == X86_CPUID_VENDOR_AMD_ECX
223 && u32VendorEDX == X86_CPUID_VENDOR_AMD_EDX
224 )
225 {
226 if ( (u32AMDFeatureECX & X86_CPUID_AMD_FEATURE_ECX_SVM)
227 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR)
228 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR)
229 )
230 {
231 /* Check if SVM is disabled */
232 val = ASMRdMsr(MSR_K8_VM_CR);
233 if (!(val & MSR_K8_VM_CR_SVM_DISABLE))
234 {
235 *pfCaps |= SUPVTCAPS_AMD_V;
236
237 /* Query AMD features. */
238 ASMCpuId(0x8000000A, &u32Dummy, &u32Dummy, &u32Dummy, &u32FeaturesEDX);
239
240 if (u32FeaturesEDX & AMD_CPUID_SVM_FEATURE_EDX_NESTED_PAGING)
241 *pfCaps |= SUPVTCAPS_NESTED_PAGING;
242
243 return VINF_SUCCESS;
244 }
245 return VERR_SVM_DISABLED;
246 }
247 return VERR_SVM_NO_SVM;
248 }
249 }
250
251 return VERR_UNSUPPORTED_CPU;
252}
253
254
255/**
256 * Destructor for objects created by SUPSemEventCreate.
257 *
258 * @param pvObj The object handle.
259 * @param pvUser1 The IPRT event handle.
260 * @param pvUser2 NULL.
261 */
262static DECLCALLBACK(void) supR0SemEventDestructor(void *pvObj, void *pvUser1, void *pvUser2)
263{
264 Assert(pvUser2 == NULL);
265 NOREF(pvObj);
266 RTSemEventDestroy((RTSEMEVENT)pvUser1);
267}
268
269
270SUPDECL(int) SUPSemEventCreate(PSUPDRVSESSION pSession, PSUPSEMEVENT phEvent)
271{
272 int rc;
273 RTSEMEVENT hEventReal;
274
275 /*
276 * Input validation.
277 */
278 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
279 AssertPtrReturn(phEvent, VERR_INVALID_POINTER);
280
281 /*
282 * Create the event semaphore object.
283 */
284 rc = RTSemEventCreate(&hEventReal);
285 if (RT_SUCCESS(rc))
286 {
287 void *pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_SEM_EVENT, supR0SemEventDestructor, hEventReal, NULL);
288 if (pvObj)
289 {
290 uint32_t h32;
291 rc = RTHandleTableAllocWithCtx(pSession->hHandleTable, pvObj, SUPDRV_HANDLE_CTX_EVENT, &h32);
292 if (RT_SUCCESS(rc))
293 {
294 *phEvent = (SUPSEMEVENT)(uintptr_t)h32;
295 return VINF_SUCCESS;
296 }
297 SUPR0ObjRelease(pvObj, pSession);
298 }
299 else
300 RTSemEventDestroy(hEventReal);
301 }
302 return rc;
303}
304
305
306SUPDECL(int) SUPSemEventClose(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent)
307{
308 uint32_t h32;
309 PSUPDRVOBJ pObj;
310
311 /*
312 * Input validation.
313 */
314 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
315 if (hEvent == NIL_SUPSEMEVENT)
316 return VINF_SUCCESS;
317 h32 = (uint32_t)(uintptr_t)hEvent;
318 if (h32 != (uintptr_t)hEvent)
319 return VERR_INVALID_HANDLE;
320
321 /*
322 * Do the job.
323 */
324 pObj = (PSUPDRVOBJ)RTHandleTableFreeWithCtx(pSession->hHandleTable, h32, SUPDRV_HANDLE_CTX_EVENT);
325 if (!pObj)
326 return VERR_INVALID_HANDLE;
327
328 Assert(pObj->cUsage >= 2);
329 SUPR0ObjRelease(pObj, pSession); /* The free call above. */
330 return SUPR0ObjRelease(pObj, pSession); /* The handle table reference. */
331}
332
333
334SUPDECL(int) SUPSemEventSignal(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent)
335{
336 int rc;
337 uint32_t h32;
338 PSUPDRVOBJ pObj;
339
340 /*
341 * Input validation.
342 */
343 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
344 h32 = (uint32_t)(uintptr_t)hEvent;
345 if (h32 != (uintptr_t)hEvent)
346 return VERR_INVALID_HANDLE;
347 pObj = (PSUPDRVOBJ)RTHandleTableLookupWithCtx(pSession->hHandleTable, h32, SUPDRV_HANDLE_CTX_EVENT);
348 if (!pObj)
349 return VERR_INVALID_HANDLE;
350
351 /*
352 * Do the job.
353 */
354 rc = RTSemEventSignal((RTSEMEVENT)pObj->pvUser1);
355
356 SUPR0ObjRelease(pObj, pSession);
357 return rc;
358}
359
360
361SUPDECL(int) SUPSemEventWait(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent, uint32_t cMillies)
362{
363 int rc;
364 uint32_t h32;
365 PSUPDRVOBJ pObj;
366
367 /*
368 * Input validation.
369 */
370 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
371 h32 = (uint32_t)(uintptr_t)hEvent;
372 if (h32 != (uintptr_t)hEvent)
373 return VERR_INVALID_HANDLE;
374 pObj = (PSUPDRVOBJ)RTHandleTableLookupWithCtx(pSession->hHandleTable, h32, SUPDRV_HANDLE_CTX_EVENT);
375 if (!pObj)
376 return VERR_INVALID_HANDLE;
377
378 /*
379 * Do the job.
380 */
381 rc = RTSemEventWait((RTSEMEVENT)pObj->pvUser1, cMillies);
382
383 SUPR0ObjRelease(pObj, pSession);
384 return rc;
385}
386
387
388SUPDECL(int) SUPSemEventWaitNoResume(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent, uint32_t cMillies)
389{
390 int rc;
391 uint32_t h32;
392 PSUPDRVOBJ pObj;
393
394 /*
395 * Input validation.
396 */
397 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
398 h32 = (uint32_t)(uintptr_t)hEvent;
399 if (h32 != (uintptr_t)hEvent)
400 return VERR_INVALID_HANDLE;
401 pObj = (PSUPDRVOBJ)RTHandleTableLookupWithCtx(pSession->hHandleTable, h32, SUPDRV_HANDLE_CTX_EVENT);
402 if (!pObj)
403 return VERR_INVALID_HANDLE;
404
405 /*
406 * Do the job.
407 */
408 rc = RTSemEventWaitNoResume((RTSEMEVENT)pObj->pvUser1, cMillies);
409
410 SUPR0ObjRelease(pObj, pSession);
411 return rc;
412}
413
414
415/**
416 * Destructor for objects created by SUPSemEventMultiCreate.
417 *
418 * @param pvObj The object handle.
419 * @param pvUser1 The IPRT event handle.
420 * @param pvUser2 NULL.
421 */
422static DECLCALLBACK(void) supR0SemEventMultiDestructor(void *pvObj, void *pvUser1, void *pvUser2)
423{
424 Assert(pvUser2 == NULL);
425 NOREF(pvObj);
426 RTSemEventMultiDestroy((RTSEMEVENTMULTI)pvUser1);
427}
428
429
430SUPDECL(int) SUPSemEventMultiCreate(PSUPDRVSESSION pSession, PSUPSEMEVENTMULTI phEventMulti)
431{
432 int rc;
433 RTSEMEVENTMULTI hEventMultReal;
434
435 /*
436 * Input validation.
437 */
438 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
439 AssertPtrReturn(phEventMulti, VERR_INVALID_POINTER);
440
441 /*
442 * Create the event semaphore object.
443 */
444 rc = RTSemEventMultiCreate(&hEventMultReal);
445 if (RT_SUCCESS(rc))
446 {
447 void *pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_SEM_EVENT_MULTI, supR0SemEventMultiDestructor, hEventMultReal, NULL);
448 if (pvObj)
449 {
450 uint32_t h32;
451 rc = RTHandleTableAllocWithCtx(pSession->hHandleTable, pvObj, SUPDRV_HANDLE_CTX_EVENT_MULTI, &h32);
452 if (RT_SUCCESS(rc))
453 {
454 *phEventMulti = (SUPSEMEVENTMULTI)(uintptr_t)h32;
455 return VINF_SUCCESS;
456 }
457 SUPR0ObjRelease(pvObj, pSession);
458 }
459 else
460 RTSemEventMultiDestroy(hEventMultReal);
461 }
462 return rc;
463}
464
465
466SUPDECL(int) SUPSemEventMultiClose(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti)
467{
468 uint32_t h32;
469 PSUPDRVOBJ pObj;
470
471 /*
472 * Input validation.
473 */
474 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
475 if (hEventMulti == NIL_SUPSEMEVENTMULTI)
476 return VINF_SUCCESS;
477 h32 = (uint32_t)(uintptr_t)hEventMulti;
478 if (h32 != (uintptr_t)hEventMulti)
479 return VERR_INVALID_HANDLE;
480
481 /*
482 * Do the job.
483 */
484 pObj = (PSUPDRVOBJ)RTHandleTableFreeWithCtx(pSession->hHandleTable, h32, SUPDRV_HANDLE_CTX_EVENT_MULTI);
485 if (!pObj)
486 return VERR_INVALID_HANDLE;
487
488 Assert(pObj->cUsage >= 2);
489 SUPR0ObjRelease(pObj, pSession); /* The free call above. */
490 return SUPR0ObjRelease(pObj, pSession); /* The handle table reference. */
491}
492
493
494SUPDECL(int) SUPSemEventMultiSignal(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti)
495{
496 int rc;
497 uint32_t h32;
498 PSUPDRVOBJ pObj;
499
500 /*
501 * Input validation.
502 */
503 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
504 h32 = (uint32_t)(uintptr_t)hEventMulti;
505 if (h32 != (uintptr_t)hEventMulti)
506 return VERR_INVALID_HANDLE;
507 pObj = (PSUPDRVOBJ)RTHandleTableLookupWithCtx(pSession->hHandleTable, h32, SUPDRV_HANDLE_CTX_EVENT_MULTI);
508 if (!pObj)
509 return VERR_INVALID_HANDLE;
510
511 /*
512 * Do the job.
513 */
514 rc = RTSemEventMultiSignal((RTSEMEVENTMULTI)pObj->pvUser1);
515
516 SUPR0ObjRelease(pObj, pSession);
517 return rc;
518}
519
520
521SUPDECL(int) SUPSemEventMultiReset(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti)
522{
523 int rc;
524 uint32_t h32;
525 PSUPDRVOBJ pObj;
526
527 /*
528 * Input validation.
529 */
530 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
531 h32 = (uint32_t)(uintptr_t)hEventMulti;
532 if (h32 != (uintptr_t)hEventMulti)
533 return VERR_INVALID_HANDLE;
534 pObj = (PSUPDRVOBJ)RTHandleTableLookupWithCtx(pSession->hHandleTable, h32, SUPDRV_HANDLE_CTX_EVENT_MULTI);
535 if (!pObj)
536 return VERR_INVALID_HANDLE;
537
538 /*
539 * Do the job.
540 */
541 rc = RTSemEventMultiReset((RTSEMEVENTMULTI)pObj->pvUser1);
542
543 SUPR0ObjRelease(pObj, pSession);
544 return rc;
545}
546
547
548SUPDECL(int) SUPSemEventMultiWait(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti, uint32_t cMillies)
549{
550 int rc;
551 uint32_t h32;
552 PSUPDRVOBJ pObj;
553
554 /*
555 * Input validation.
556 */
557 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
558 h32 = (uint32_t)(uintptr_t)hEventMulti;
559 if (h32 != (uintptr_t)hEventMulti)
560 return VERR_INVALID_HANDLE;
561 pObj = (PSUPDRVOBJ)RTHandleTableLookupWithCtx(pSession->hHandleTable, h32, SUPDRV_HANDLE_CTX_EVENT_MULTI);
562 if (!pObj)
563 return VERR_INVALID_HANDLE;
564
565 /*
566 * Do the job.
567 */
568 rc = RTSemEventMultiWait((RTSEMEVENTMULTI)pObj->pvUser1, cMillies);
569
570 SUPR0ObjRelease(pObj, pSession);
571 return rc;
572}
573
574
575SUPDECL(int) SUPSemEventMultiWaitNoResume(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti, uint32_t cMillies)
576{
577 int rc;
578 uint32_t h32;
579 PSUPDRVOBJ pObj;
580
581 /*
582 * Input validation.
583 */
584 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
585 h32 = (uint32_t)(uintptr_t)hEventMulti;
586 if (h32 != (uintptr_t)hEventMulti)
587 return VERR_INVALID_HANDLE;
588 pObj = (PSUPDRVOBJ)RTHandleTableLookupWithCtx(pSession->hHandleTable, h32, SUPDRV_HANDLE_CTX_EVENT_MULTI);
589 if (!pObj)
590 return VERR_INVALID_HANDLE;
591
592 /*
593 * Do the job.
594 */
595 rc = RTSemEventMultiWaitNoResume((RTSEMEVENTMULTI)pObj->pvUser1, cMillies);
596
597 SUPR0ObjRelease(pObj, pSession);
598 return rc;
599}
600
601
602
603
604/**
605 * Determin the GIP TSC mode.
606 *
607 * @returns The most suitable TSC mode.
608 * @param pDevExt Pointer to the device instance data.
609 */
610SUPGIPMODE VBOXCALL supdrvGipDeterminTscMode(PSUPDRVDEVEXT pDevExt)
611{
612 /*
613 * On SMP we're faced with two problems:
614 * (1) There might be a skew between the CPU, so that cpu0
615 * returns a TSC that is sligtly different from cpu1.
616 * (2) Power management (and other things) may cause the TSC
617 * to run at a non-constant speed, and cause the speed
618 * to be different on the cpus. This will result in (1).
619 *
620 * So, on SMP systems we'll have to select the ASYNC update method
621 * if there are symphoms of these problems.
622 */
623 if (RTMpGetCount() > 1)
624 {
625 uint32_t uEAX, uEBX, uECX, uEDX;
626 uint64_t u64DiffCoresIgnored;
627
628 /* Permit the user and/or the OS specfic bits to force async mode. */
629 if (supdrvOSGetForcedAsyncTscMode(pDevExt))
630 return SUPGIPMODE_ASYNC_TSC;
631
632 /* Try check for current differences between the cpus. */
633 if (supdrvDetermineAsyncTsc(&u64DiffCoresIgnored))
634 return SUPGIPMODE_ASYNC_TSC;
635
636 /*
637 * If the CPU supports power management and is an AMD one we
638 * won't trust it unless it has the TscInvariant bit is set.
639 */
640 /* Check for "AuthenticAMD" */
641 ASMCpuId(0, &uEAX, &uEBX, &uECX, &uEDX);
642 if ( uEAX >= 1
643 && uEBX == X86_CPUID_VENDOR_AMD_EBX
644 && uECX == X86_CPUID_VENDOR_AMD_ECX
645 && uEDX == X86_CPUID_VENDOR_AMD_EDX)
646 {
647 /* Check for APM support and that TscInvariant is cleared. */
648 ASMCpuId(0x80000000, &uEAX, &uEBX, &uECX, &uEDX);
649 if (uEAX >= 0x80000007)
650 {
651 ASMCpuId(0x80000007, &uEAX, &uEBX, &uECX, &uEDX);
652 if ( !(uEDX & RT_BIT(8))/* TscInvariant */
653 && (uEDX & 0x3e)) /* STC|TM|THERMTRIP|VID|FID. Ignore TS. */
654 return SUPGIPMODE_ASYNC_TSC;
655 }
656 }
657 }
658 return SUPGIPMODE_SYNC_TSC;
659}
660
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette