VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/SUPDRVShared.c@ 8114

最後變更 在這個檔案從8114是 8114,由 vboxsync 提交於 17 年 前

ATTENTION: Driver version change (backwards compatible). Need more RTMp* stuff.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 146.4 KB
 
1/* $Revision: 8114 $ */
2/** @file
3 * VirtualBox Support Driver - Shared code.
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.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
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include "SUPDRV.h"
32#ifndef PAGE_SHIFT
33# include <iprt/param.h>
34#endif
35#include <iprt/alloc.h>
36#include <iprt/semaphore.h>
37#include <iprt/spinlock.h>
38#include <iprt/thread.h>
39#include <iprt/process.h>
40#include <iprt/mp.h>
41#include <iprt/cpuset.h>
42#include <iprt/log.h>
43
44/*
45 * Logging assignments:
46 * Log - useful stuff, like failures.
47 * LogFlow - program flow, except the really noisy bits.
48 * Log2 - Cleanup and IDTE
49 * Log3 - Loader flow noise.
50 * Log4 - Call VMMR0 flow noise.
51 * Log5 - Native yet-to-be-defined noise.
52 * Log6 - Native ioctl flow noise.
53 *
54 * Logging requires BUILD_TYPE=debug and possibly changes to the logger
55 * instanciation in log-vbox.c(pp).
56 */
57
58
59/*******************************************************************************
60* Defined Constants And Macros *
61*******************************************************************************/
62/* from x86.h - clashes with linux thus this duplication */
63#undef X86_CR0_PG
64#define X86_CR0_PG RT_BIT(31)
65#undef X86_CR0_PE
66#define X86_CR0_PE RT_BIT(0)
67#undef X86_CPUID_AMD_FEATURE_EDX_NX
68#define X86_CPUID_AMD_FEATURE_EDX_NX RT_BIT(20)
69#undef MSR_K6_EFER
70#define MSR_K6_EFER 0xc0000080
71#undef MSR_K6_EFER_NXE
72#define MSR_K6_EFER_NXE RT_BIT(11)
73#undef MSR_K6_EFER_LMA
74#define MSR_K6_EFER_LMA RT_BIT(10)
75#undef X86_CR4_PGE
76#define X86_CR4_PGE RT_BIT(7)
77#undef X86_CR4_PAE
78#define X86_CR4_PAE RT_BIT(5)
79#undef X86_CPUID_AMD_FEATURE_EDX_LONG_MODE
80#define X86_CPUID_AMD_FEATURE_EDX_LONG_MODE RT_BIT(29)
81
82
83/** The frequency by which we recalculate the u32UpdateHz and
84 * u32UpdateIntervalNS GIP members. The value must be a power of 2. */
85#define GIP_UPDATEHZ_RECALC_FREQ 0x800
86
87/**
88 * Validates a session pointer.
89 *
90 * @returns true/false accordingly.
91 * @param pSession The session.
92 */
93#define SUP_IS_SESSION_VALID(pSession) \
94 ( VALID_PTR(pSession) \
95 && pSession->u32Cookie == BIRD_INV)
96
97
98/*******************************************************************************
99* Global Variables *
100*******************************************************************************/
101/**
102 * Array of the R0 SUP API.
103 */
104static SUPFUNC g_aFunctions[] =
105{
106 /* name function */
107 { "SUPR0ObjRegister", (void *)SUPR0ObjRegister },
108 { "SUPR0ObjAddRef", (void *)SUPR0ObjAddRef },
109 { "SUPR0ObjRelease", (void *)SUPR0ObjRelease },
110 { "SUPR0ObjVerifyAccess", (void *)SUPR0ObjVerifyAccess },
111 { "SUPR0LockMem", (void *)SUPR0LockMem },
112 { "SUPR0UnlockMem", (void *)SUPR0UnlockMem },
113 { "SUPR0ContAlloc", (void *)SUPR0ContAlloc },
114 { "SUPR0ContFree", (void *)SUPR0ContFree },
115 { "SUPR0LowAlloc", (void *)SUPR0LowAlloc },
116 { "SUPR0LowFree", (void *)SUPR0LowFree },
117 { "SUPR0MemAlloc", (void *)SUPR0MemAlloc },
118 { "SUPR0MemGetPhys", (void *)SUPR0MemGetPhys },
119 { "SUPR0MemFree", (void *)SUPR0MemFree },
120 { "SUPR0PageAlloc", (void *)SUPR0PageAlloc },
121 { "SUPR0PageFree", (void *)SUPR0PageFree },
122 { "SUPR0Printf", (void *)SUPR0Printf },
123 { "RTMemAlloc", (void *)RTMemAlloc },
124 { "RTMemAllocZ", (void *)RTMemAllocZ },
125 { "RTMemFree", (void *)RTMemFree },
126 /*{ "RTMemDup", (void *)RTMemDup },*/
127 { "RTMemRealloc", (void *)RTMemRealloc },
128 { "RTR0MemObjAllocLow", (void *)RTR0MemObjAllocLow },
129 { "RTR0MemObjAllocPage", (void *)RTR0MemObjAllocPage },
130 { "RTR0MemObjAllocPhys", (void *)RTR0MemObjAllocPhys },
131 { "RTR0MemObjAllocPhysNC", (void *)RTR0MemObjAllocPhysNC },
132 { "RTR0MemObjAllocCont", (void *)RTR0MemObjAllocCont },
133 { "RTR0MemObjLockUser", (void *)RTR0MemObjLockUser },
134 { "RTR0MemObjMapKernel", (void *)RTR0MemObjMapKernel },
135 { "RTR0MemObjMapUser", (void *)RTR0MemObjMapUser },
136 { "RTR0MemObjAddress", (void *)RTR0MemObjAddress },
137 { "RTR0MemObjAddressR3", (void *)RTR0MemObjAddressR3 },
138 { "RTR0MemObjSize", (void *)RTR0MemObjSize },
139 { "RTR0MemObjIsMapping", (void *)RTR0MemObjIsMapping },
140 { "RTR0MemObjGetPagePhysAddr", (void *)RTR0MemObjGetPagePhysAddr },
141 { "RTR0MemObjFree", (void *)RTR0MemObjFree },
142/* These don't work yet on linux - use fast mutexes!
143 { "RTSemMutexCreate", (void *)RTSemMutexCreate },
144 { "RTSemMutexRequest", (void *)RTSemMutexRequest },
145 { "RTSemMutexRelease", (void *)RTSemMutexRelease },
146 { "RTSemMutexDestroy", (void *)RTSemMutexDestroy },
147*/
148 { "RTProcSelf", (void *)RTProcSelf },
149 { "RTR0ProcHandleSelf", (void *)RTR0ProcHandleSelf },
150 { "RTSemFastMutexCreate", (void *)RTSemFastMutexCreate },
151 { "RTSemFastMutexDestroy", (void *)RTSemFastMutexDestroy },
152 { "RTSemFastMutexRequest", (void *)RTSemFastMutexRequest },
153 { "RTSemFastMutexRelease", (void *)RTSemFastMutexRelease },
154 { "RTSemEventCreate", (void *)RTSemEventCreate },
155 { "RTSemEventSignal", (void *)RTSemEventSignal },
156 { "RTSemEventWait", (void *)RTSemEventWait },
157 { "RTSemEventWaitNoResume", (void *)RTSemEventWaitNoResume },
158 { "RTSemEventDestroy", (void *)RTSemEventDestroy },
159 { "RTSemEventMultiCreate", (void *)RTSemEventMultiCreate },
160 { "RTSemEventMultiSignal", (void *)RTSemEventMultiSignal },
161 { "RTSemEventMultiReset", (void *)RTSemEventMultiReset },
162 { "RTSemEventMultiWait", (void *)RTSemEventMultiWait },
163 { "RTSemEventMultiWaitNoResume", (void *)RTSemEventMultiWaitNoResume },
164 { "RTSemEventMultiDestroy", (void *)RTSemEventMultiDestroy },
165 { "RTSpinlockCreate", (void *)RTSpinlockCreate },
166 { "RTSpinlockDestroy", (void *)RTSpinlockDestroy },
167 { "RTSpinlockAcquire", (void *)RTSpinlockAcquire },
168 { "RTSpinlockRelease", (void *)RTSpinlockRelease },
169 { "RTSpinlockAcquireNoInts", (void *)RTSpinlockAcquireNoInts },
170 { "RTSpinlockReleaseNoInts", (void *)RTSpinlockReleaseNoInts },
171 { "RTThreadNativeSelf", (void *)RTThreadNativeSelf },
172 { "RTThreadSleep", (void *)RTThreadSleep },
173 { "RTThreadYield", (void *)RTThreadYield },
174#if 0 /* Thread APIs, Part 2. */
175 { "RTThreadSelf", (void *)RTThreadSelf },
176 { "RTThreadCreate", (void *)RTThreadCreate },
177 { "RTThreadGetNative", (void *)RTThreadGetNative },
178 { "RTThreadWait", (void *)RTThreadWait },
179 { "RTThreadWaitNoResume", (void *)RTThreadWaitNoResume },
180 { "RTThreadGetName", (void *)RTThreadGetName },
181 { "RTThreadSelfName", (void *)RTThreadSelfName },
182 { "RTThreadGetType", (void *)RTThreadGetType },
183 { "RTThreadUserSignal", (void *)RTThreadUserSignal },
184 { "RTThreadUserReset", (void *)RTThreadUserReset },
185 { "RTThreadUserWait", (void *)RTThreadUserWait },
186 { "RTThreadUserWaitNoResume", (void *)RTThreadUserWaitNoResume },
187#endif
188 { "RTLogDefaultInstance", (void *)RTLogDefaultInstance },
189 { "RTMpCpuIdFromSetIndex", (void *)RTMpCpuIdFromSetIndex },
190 { "RTMpCpuIdToSetIndex", (void *)RTMpCpuIdToSetIndex },
191 { "RTMpDoesCpuExist", (void *)RTMpDoesCpuExist },
192 { "RTMpGetCount", (void *)RTMpGetCount },
193 { "RTMpGetMaxCpuId", (void *)RTMpGetMaxCpuId },
194 { "RTMpGetOnlineCount", (void *)RTMpGetOnlineCount },
195 { "RTMpGetOnlineSet", (void *)RTMpGetOnlineSet },
196 { "RTMpGetSet", (void *)RTMpGetSet },
197 { "RTMpIsCpuOnline", (void *)RTMpIsCpuOnline },
198 { "RTMpOnAll", (void *)RTMpOnAll },
199 { "RTMpOnOthers", (void *)RTMpOnOthers },
200 { "RTMpOnSpecific", (void *)RTMpOnSpecific },
201 { "RTLogRelDefaultInstance", (void *)RTLogRelDefaultInstance },
202 { "RTLogSetDefaultInstanceThread", (void *)RTLogSetDefaultInstanceThread },
203 { "RTLogLogger", (void *)RTLogLogger },
204 { "RTLogLoggerEx", (void *)RTLogLoggerEx },
205 { "RTLogLoggerExV", (void *)RTLogLoggerExV },
206 { "RTLogPrintf", (void *)RTLogPrintf },
207 { "RTLogPrintfV", (void *)RTLogPrintfV },
208 { "AssertMsg1", (void *)AssertMsg1 },
209 { "AssertMsg2", (void *)AssertMsg2 },
210};
211
212
213/*******************************************************************************
214* Internal Functions *
215*******************************************************************************/
216static int supdrvMemAdd(PSUPDRVMEMREF pMem, PSUPDRVSESSION pSession);
217static int supdrvMemRelease(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr, SUPDRVMEMREFTYPE eType);
218#ifdef VBOX_WITH_IDT_PATCHING
219static int supdrvIOCtl_IdtInstall(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPIDTINSTALL pReq);
220static PSUPDRVPATCH supdrvIdtPatchOne(PSUPDRVDEVEXT pDevExt, PSUPDRVPATCH pPatch);
221static int supdrvIOCtl_IdtRemoveAll(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession);
222static void supdrvIdtRemoveOne(PSUPDRVDEVEXT pDevExt, PSUPDRVPATCH pPatch);
223static void supdrvIdtWrite(volatile void *pvIdtEntry, const SUPDRVIDTE *pNewIDTEntry);
224#endif /* VBOX_WITH_IDT_PATCHING */
225static int supdrvIOCtl_LdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDROPEN pReq);
226static int supdrvIOCtl_LdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDRLOAD pReq);
227static int supdrvIOCtl_LdrFree(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDRFREE pReq);
228static int supdrvIOCtl_LdrGetSymbol(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDRGETSYMBOL pReq);
229static int supdrvLdrSetR0EP(PSUPDRVDEVEXT pDevExt, void *pvVMMR0, void *pvVMMR0EntryInt, void *pvVMMR0EntryFast, void *pvVMMR0EntryEx);
230static void supdrvLdrUnsetR0EP(PSUPDRVDEVEXT pDevExt);
231static void supdrvLdrAddUsage(PSUPDRVSESSION pSession, PSUPDRVLDRIMAGE pImage);
232static void supdrvLdrFree(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage);
233static SUPPAGINGMODE supdrvIOCtl_GetPagingMode(void);
234static SUPGIPMODE supdrvGipDeterminTscMode(void);
235#ifdef RT_OS_WINDOWS
236static int supdrvPageGetPhys(PSUPDRVSESSION pSession, RTR3PTR pvR3, uint32_t cPages, PRTHCPHYS paPages);
237static bool supdrvPageWasLockedByPageAlloc(PSUPDRVSESSION pSession, RTR3PTR pvR3);
238#endif
239#ifdef USE_NEW_OS_INTERFACE_FOR_GIP
240static int supdrvGipCreate(PSUPDRVDEVEXT pDevExt);
241static void supdrvGipDestroy(PSUPDRVDEVEXT pDevExt);
242static DECLCALLBACK(void) supdrvGipTimer(PRTTIMER pTimer, void *pvUser);
243#endif
244
245
246/**
247 * Initializes the device extentsion structure.
248 *
249 * @returns IPRT status code.
250 * @param pDevExt The device extension to initialize.
251 */
252int VBOXCALL supdrvInitDevExt(PSUPDRVDEVEXT pDevExt)
253{
254 /*
255 * Initialize it.
256 */
257 int rc;
258 memset(pDevExt, 0, sizeof(*pDevExt));
259 rc = RTSpinlockCreate(&pDevExt->Spinlock);
260 if (!rc)
261 {
262 rc = RTSemFastMutexCreate(&pDevExt->mtxLdr);
263 if (!rc)
264 {
265 rc = RTSemFastMutexCreate(&pDevExt->mtxGip);
266 if (!rc)
267 {
268#ifdef USE_NEW_OS_INTERFACE_FOR_GIP
269 rc = supdrvGipCreate(pDevExt);
270 if (RT_SUCCESS(rc))
271 {
272 pDevExt->u32Cookie = BIRD; /** @todo make this random? */
273 return VINF_SUCCESS;
274 }
275#else
276 pDevExt->u32Cookie = BIRD;
277 return VINF_SUCCESS;
278#endif
279 }
280 RTSemFastMutexDestroy(pDevExt->mtxLdr);
281 pDevExt->mtxLdr = NIL_RTSEMFASTMUTEX;
282 }
283 RTSpinlockDestroy(pDevExt->Spinlock);
284 pDevExt->Spinlock = NIL_RTSPINLOCK;
285 }
286 return rc;
287}
288
289
290/**
291 * Delete the device extension (e.g. cleanup members).
292 *
293 * @param pDevExt The device extension to delete.
294 */
295void VBOXCALL supdrvDeleteDevExt(PSUPDRVDEVEXT pDevExt)
296{
297#ifdef VBOX_WITH_IDT_PATCHING
298 PSUPDRVPATCH pPatch;
299#endif
300 PSUPDRVOBJ pObj;
301 PSUPDRVUSAGE pUsage;
302
303 /*
304 * Kill mutexes and spinlocks.
305 */
306 RTSemFastMutexDestroy(pDevExt->mtxGip);
307 pDevExt->mtxGip = NIL_RTSEMFASTMUTEX;
308 RTSemFastMutexDestroy(pDevExt->mtxLdr);
309 pDevExt->mtxLdr = NIL_RTSEMFASTMUTEX;
310 RTSpinlockDestroy(pDevExt->Spinlock);
311 pDevExt->Spinlock = NIL_RTSPINLOCK;
312
313 /*
314 * Free lists.
315 */
316#ifdef VBOX_WITH_IDT_PATCHING
317 /* patches */
318 /** @todo make sure we don't uninstall patches which has been patched by someone else. */
319 pPatch = pDevExt->pIdtPatchesFree;
320 pDevExt->pIdtPatchesFree = NULL;
321 while (pPatch)
322 {
323 void *pvFree = pPatch;
324 pPatch = pPatch->pNext;
325 RTMemExecFree(pvFree);
326 }
327#endif /* VBOX_WITH_IDT_PATCHING */
328
329 /* objects. */
330 pObj = pDevExt->pObjs;
331#if !defined(DEBUG_bird) || !defined(RT_OS_LINUX) /* breaks unloading, temporary, remove me! */
332 Assert(!pObj); /* (can trigger on forced unloads) */
333#endif
334 pDevExt->pObjs = NULL;
335 while (pObj)
336 {
337 void *pvFree = pObj;
338 pObj = pObj->pNext;
339 RTMemFree(pvFree);
340 }
341
342 /* usage records. */
343 pUsage = pDevExt->pUsageFree;
344 pDevExt->pUsageFree = NULL;
345 while (pUsage)
346 {
347 void *pvFree = pUsage;
348 pUsage = pUsage->pNext;
349 RTMemFree(pvFree);
350 }
351
352#ifdef USE_NEW_OS_INTERFACE_FOR_GIP
353 /* kill the GIP */
354 supdrvGipDestroy(pDevExt);
355#endif
356}
357
358
359/**
360 * Create session.
361 *
362 * @returns IPRT status code.
363 * @param pDevExt Device extension.
364 * @param ppSession Where to store the pointer to the session data.
365 */
366int VBOXCALL supdrvCreateSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION *ppSession)
367{
368 /*
369 * Allocate memory for the session data.
370 */
371 int rc = VERR_NO_MEMORY;
372 PSUPDRVSESSION pSession = *ppSession = (PSUPDRVSESSION)RTMemAllocZ(sizeof(*pSession));
373 if (pSession)
374 {
375 /* Initialize session data. */
376 rc = RTSpinlockCreate(&pSession->Spinlock);
377 if (!rc)
378 {
379 Assert(pSession->Spinlock != NIL_RTSPINLOCK);
380 pSession->pDevExt = pDevExt;
381 pSession->u32Cookie = BIRD_INV;
382 /*pSession->pLdrUsage = NULL;
383 pSession->pPatchUsage = NULL;
384 pSession->pUsage = NULL;
385 pSession->pGip = NULL;
386 pSession->fGipReferenced = false;
387 pSession->Bundle.cUsed = 0 */
388
389 LogFlow(("Created session %p initial cookie=%#x\n", pSession, pSession->u32Cookie));
390 return VINF_SUCCESS;
391 }
392
393 RTMemFree(pSession);
394 *ppSession = NULL;
395 Log(("Failed to create spinlock, rc=%d!\n", rc));
396 }
397
398 return rc;
399}
400
401
402/**
403 * Shared code for cleaning up a session.
404 *
405 * @param pDevExt Device extension.
406 * @param pSession Session data.
407 * This data will be freed by this routine.
408 */
409void VBOXCALL supdrvCloseSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
410{
411 /*
412 * Cleanup the session first.
413 */
414 supdrvCleanupSession(pDevExt, pSession);
415
416 /*
417 * Free the rest of the session stuff.
418 */
419 RTSpinlockDestroy(pSession->Spinlock);
420 pSession->Spinlock = NIL_RTSPINLOCK;
421 pSession->pDevExt = NULL;
422 RTMemFree(pSession);
423 LogFlow(("supdrvCloseSession: returns\n"));
424}
425
426
427/**
428 * Shared code for cleaning up a session (but not quite freeing it).
429 *
430 * This is primarily intended for MAC OS X where we have to clean up the memory
431 * stuff before the file handle is closed.
432 *
433 * @param pDevExt Device extension.
434 * @param pSession Session data.
435 * This data will be freed by this routine.
436 */
437void VBOXCALL supdrvCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
438{
439 PSUPDRVBUNDLE pBundle;
440 LogFlow(("supdrvCleanupSession: pSession=%p\n", pSession));
441
442 /*
443 * Remove logger instances related to this session.
444 */
445 RTLogSetDefaultInstanceThread(NULL, (uintptr_t)pSession);
446
447#ifdef VBOX_WITH_IDT_PATCHING
448 /*
449 * Uninstall any IDT patches installed for this session.
450 */
451 supdrvIOCtl_IdtRemoveAll(pDevExt, pSession);
452#endif
453
454 /*
455 * Release object references made in this session.
456 * In theory there should be noone racing us in this session.
457 */
458 Log2(("release objects - start\n"));
459 if (pSession->pUsage)
460 {
461 RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
462 PSUPDRVUSAGE pUsage;
463 RTSpinlockAcquire(pDevExt->Spinlock, &SpinlockTmp);
464
465 while ((pUsage = pSession->pUsage) != NULL)
466 {
467 PSUPDRVOBJ pObj = pUsage->pObj;
468 pSession->pUsage = pUsage->pNext;
469
470 AssertMsg(pUsage->cUsage >= 1 && pObj->cUsage >= pUsage->cUsage, ("glob %d; sess %d\n", pObj->cUsage, pUsage->cUsage));
471 if (pUsage->cUsage < pObj->cUsage)
472 {
473 pObj->cUsage -= pUsage->cUsage;
474 RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
475 }
476 else
477 {
478 /* Destroy the object and free the record. */
479 if (pDevExt->pObjs == pObj)
480 pDevExt->pObjs = pObj->pNext;
481 else
482 {
483 PSUPDRVOBJ pObjPrev;
484 for (pObjPrev = pDevExt->pObjs; pObjPrev; pObjPrev = pObjPrev->pNext)
485 if (pObjPrev->pNext == pObj)
486 {
487 pObjPrev->pNext = pObj->pNext;
488 break;
489 }
490 Assert(pObjPrev);
491 }
492 RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
493
494 Log(("supdrvCleanupSession: destroying %p/%d (%p/%p) cpid=%RTproc pid=%RTproc dtor=%p\n",
495 pObj, pObj->enmType, pObj->pvUser1, pObj->pvUser2, pObj->CreatorProcess, RTProcSelf(), pObj->pfnDestructor));
496 if (pObj->pfnDestructor)
497 pObj->pfnDestructor(pObj, pObj->pvUser1, pObj->pvUser2);
498 RTMemFree(pObj);
499 }
500
501 /* free it and continue. */
502 RTMemFree(pUsage);
503
504 RTSpinlockAcquire(pDevExt->Spinlock, &SpinlockTmp);
505 }
506
507 RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
508 AssertMsg(!pSession->pUsage, ("Some buster reregistered an object during desturction!\n"));
509 }
510 Log2(("release objects - done\n"));
511
512 /*
513 * Release memory allocated in the session.
514 *
515 * We do not serialize this as we assume that the application will
516 * not allocated memory while closing the file handle object.
517 */
518 Log2(("freeing memory:\n"));
519 pBundle = &pSession->Bundle;
520 while (pBundle)
521 {
522 PSUPDRVBUNDLE pToFree;
523 unsigned i;
524
525 /*
526 * Check and unlock all entries in the bundle.
527 */
528 for (i = 0; i < RT_ELEMENTS(pBundle->aMem); i++)
529 {
530 if (pBundle->aMem[i].MemObj != NIL_RTR0MEMOBJ)
531 {
532 int rc;
533 Log2(("eType=%d pvR0=%p pvR3=%p cb=%ld\n", pBundle->aMem[i].eType, RTR0MemObjAddress(pBundle->aMem[i].MemObj),
534 (void *)RTR0MemObjAddressR3(pBundle->aMem[i].MapObjR3), (long)RTR0MemObjSize(pBundle->aMem[i].MemObj)));
535 if (pBundle->aMem[i].MapObjR3 != NIL_RTR0MEMOBJ)
536 {
537 rc = RTR0MemObjFree(pBundle->aMem[i].MapObjR3, false);
538 AssertRC(rc); /** @todo figure out how to handle this. */
539 pBundle->aMem[i].MapObjR3 = NIL_RTR0MEMOBJ;
540 }
541 rc = RTR0MemObjFree(pBundle->aMem[i].MemObj, false);
542 AssertRC(rc); /** @todo figure out how to handle this. */
543 pBundle->aMem[i].MemObj = NIL_RTR0MEMOBJ;
544 pBundle->aMem[i].eType = MEMREF_TYPE_UNUSED;
545 }
546 }
547
548 /*
549 * Advance and free previous bundle.
550 */
551 pToFree = pBundle;
552 pBundle = pBundle->pNext;
553
554 pToFree->pNext = NULL;
555 pToFree->cUsed = 0;
556 if (pToFree != &pSession->Bundle)
557 RTMemFree(pToFree);
558 }
559 Log2(("freeing memory - done\n"));
560
561 /*
562 * Loaded images needs to be dereferenced and possibly freed up.
563 */
564 RTSemFastMutexRequest(pDevExt->mtxLdr);
565 Log2(("freeing images:\n"));
566 if (pSession->pLdrUsage)
567 {
568 PSUPDRVLDRUSAGE pUsage = pSession->pLdrUsage;
569 pSession->pLdrUsage = NULL;
570 while (pUsage)
571 {
572 void *pvFree = pUsage;
573 PSUPDRVLDRIMAGE pImage = pUsage->pImage;
574 if (pImage->cUsage > pUsage->cUsage)
575 pImage->cUsage -= pUsage->cUsage;
576 else
577 supdrvLdrFree(pDevExt, pImage);
578 pUsage->pImage = NULL;
579 pUsage = pUsage->pNext;
580 RTMemFree(pvFree);
581 }
582 }
583 RTSemFastMutexRelease(pDevExt->mtxLdr);
584 Log2(("freeing images - done\n"));
585
586 /*
587 * Unmap the GIP.
588 */
589 Log2(("umapping GIP:\n"));
590#ifdef USE_NEW_OS_INTERFACE_FOR_GIP
591 if (pSession->GipMapObjR3 != NIL_RTR0MEMOBJ)
592#else
593 if (pSession->pGip)
594#endif
595 {
596 SUPR0GipUnmap(pSession);
597#ifndef USE_NEW_OS_INTERFACE_FOR_GIP
598 pSession->pGip = NULL;
599#endif
600 pSession->fGipReferenced = 0;
601 }
602 Log2(("umapping GIP - done\n"));
603}
604
605
606/**
607 * Fast path I/O Control worker.
608 *
609 * @returns VBox status code that should be passed down to ring-3 unchanged.
610 * @param uIOCtl Function number.
611 * @param pDevExt Device extention.
612 * @param pSession Session data.
613 */
614int VBOXCALL supdrvIOCtlFast(uintptr_t uIOCtl, PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
615{
616 int rc;
617
618 /*
619 * We check the two prereqs after doing this only to allow the compiler to optimize things better.
620 */
621 if (RT_LIKELY(pSession->pVM && pDevExt->pfnVMMR0EntryFast))
622 {
623 switch (uIOCtl)
624 {
625 case SUP_IOCTL_FAST_DO_RAW_RUN:
626 rc = pDevExt->pfnVMMR0EntryFast(pSession->pVM, SUP_VMMR0_DO_RAW_RUN);
627 break;
628 case SUP_IOCTL_FAST_DO_HWACC_RUN:
629 rc = pDevExt->pfnVMMR0EntryFast(pSession->pVM, SUP_VMMR0_DO_HWACC_RUN);
630 break;
631 case SUP_IOCTL_FAST_DO_NOP:
632 rc = pDevExt->pfnVMMR0EntryFast(pSession->pVM, SUP_VMMR0_DO_NOP);
633 break;
634 default:
635 rc = VERR_INTERNAL_ERROR;
636 break;
637 }
638 }
639 else
640 rc = VERR_INTERNAL_ERROR;
641
642 return rc;
643}
644
645
646/**
647 * Helper for supdrvIOCtl. Check if pszStr contains any character of pszChars.
648 * We would use strpbrk here if this function would be contained in the RedHat kABI white
649 * list, see http://www.kerneldrivers.org/RHEL5.
650 *
651 * @return 1 if pszStr does contain any character of pszChars, 0 otherwise.
652 * @param pszStr String to check
653 * @param pszChars Character set
654 */
655static int supdrvCheckInvalidChar(const char *pszStr, const char *pszChars)
656{
657 int chCur;
658 while ((chCur = *pszStr++) != '\0')
659 {
660 int ch;
661 const char *psz = pszChars;
662 while ((ch = *psz++) != '\0')
663 if (ch == chCur)
664 return 1;
665
666 }
667 return 0;
668}
669
670
671/**
672 * I/O Control worker.
673 *
674 * @returns 0 on success.
675 * @returns VERR_INVALID_PARAMETER if the request is invalid.
676 *
677 * @param uIOCtl Function number.
678 * @param pDevExt Device extention.
679 * @param pSession Session data.
680 * @param pReqHdr The request header.
681 */
682int VBOXCALL supdrvIOCtl(uintptr_t uIOCtl, PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPREQHDR pReqHdr)
683{
684 /*
685 * Validate the request.
686 */
687 /* this first check could probably be omitted as its also done by the OS specific code... */
688 if (RT_UNLIKELY( (pReqHdr->fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC
689 || pReqHdr->cbIn < sizeof(*pReqHdr)
690 || pReqHdr->cbOut < sizeof(*pReqHdr)))
691 {
692 OSDBGPRINT(("vboxdrv: Bad ioctl request header; cbIn=%#lx cbOut=%#lx fFlags=%#lx\n",
693 (long)pReqHdr->cbIn, (long)pReqHdr->cbOut, (long)pReqHdr->fFlags));
694 return VERR_INVALID_PARAMETER;
695 }
696 if (RT_UNLIKELY(uIOCtl == SUP_IOCTL_COOKIE))
697 {
698 if (pReqHdr->u32Cookie != SUPCOOKIE_INITIAL_COOKIE)
699 {
700 OSDBGPRINT(("SUP_IOCTL_COOKIE: bad cookie %#lx\n", (long)pReqHdr->u32Cookie));
701 return VERR_INVALID_PARAMETER;
702 }
703 }
704 else if (RT_UNLIKELY( pReqHdr->u32Cookie != pDevExt->u32Cookie
705 || pReqHdr->u32SessionCookie != pSession->u32Cookie))
706 {
707 OSDBGPRINT(("vboxdrv: bad cookie %#lx / %#lx.\n", (long)pReqHdr->u32Cookie, (long)pReqHdr->u32SessionCookie));
708 return VERR_INVALID_PARAMETER;
709 }
710
711/*
712 * Validation macros
713 */
714#define REQ_CHECK_SIZES_EX(Name, cbInExpect, cbOutExpect) \
715 do { \
716 if (RT_UNLIKELY(pReqHdr->cbIn != (cbInExpect) || pReqHdr->cbOut != (cbOutExpect))) \
717 { \
718 OSDBGPRINT(( #Name ": Invalid input/output sizes. cbIn=%ld expected %ld. cbOut=%ld expected %ld.\n", \
719 (long)pReq->Hdr.cbIn, (long)(cbInExpect), (long)pReq->Hdr.cbOut, (long)(cbOutExpect))); \
720 return pReq->Hdr.rc = VERR_INVALID_PARAMETER; \
721 } \
722 } while (0)
723
724#define REQ_CHECK_SIZES(Name) REQ_CHECK_SIZES_EX(Name, Name ## _SIZE_IN, Name ## _SIZE_OUT)
725
726#define REQ_CHECK_SIZE_IN(Name, cbInExpect) \
727 do { \
728 if (RT_UNLIKELY(pReqHdr->cbIn != (cbInExpect))) \
729 { \
730 OSDBGPRINT(( #Name ": Invalid input/output sizes. cbIn=%ld expected %ld.\n", \
731 (long)pReq->Hdr.cbIn, (long)(cbInExpect))); \
732 return pReq->Hdr.rc = VERR_INVALID_PARAMETER; \
733 } \
734 } while (0)
735
736#define REQ_CHECK_SIZE_OUT(Name, cbOutExpect) \
737 do { \
738 if (RT_UNLIKELY(pReqHdr->cbOut != (cbOutExpect))) \
739 { \
740 OSDBGPRINT(( #Name ": Invalid input/output sizes. cbOut=%ld expected %ld.\n", \
741 (long)pReq->Hdr.cbOut, (long)(cbOutExpect))); \
742 return pReq->Hdr.rc = VERR_INVALID_PARAMETER; \
743 } \
744 } while (0)
745
746#define REQ_CHECK_EXPR(Name, expr) \
747 do { \
748 if (RT_UNLIKELY(!(expr))) \
749 { \
750 OSDBGPRINT(( #Name ": %s\n", #expr)); \
751 return pReq->Hdr.rc = VERR_INVALID_PARAMETER; \
752 } \
753 } while (0)
754
755#define REQ_CHECK_EXPR_FMT(expr, fmt) \
756 do { \
757 if (RT_UNLIKELY(!(expr))) \
758 { \
759 OSDBGPRINT( fmt ); \
760 return pReq->Hdr.rc = VERR_INVALID_PARAMETER; \
761 } \
762 } while (0)
763
764
765 /*
766 * The switch.
767 */
768 switch (SUP_CTL_CODE_NO_SIZE(uIOCtl))
769 {
770 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_COOKIE):
771 {
772 PSUPCOOKIE pReq = (PSUPCOOKIE)pReqHdr;
773 REQ_CHECK_SIZES(SUP_IOCTL_COOKIE);
774 if (strncmp(pReq->u.In.szMagic, SUPCOOKIE_MAGIC, sizeof(pReq->u.In.szMagic)))
775 {
776 OSDBGPRINT(("SUP_IOCTL_COOKIE: invalid magic %.16s\n", pReq->u.In.szMagic));
777 pReq->Hdr.rc = VERR_INVALID_MAGIC;
778 return 0;
779 }
780
781#if 0
782 /*
783 * Call out to the OS specific code and let it do permission checks on the
784 * client process.
785 */
786 if (!supdrvOSValidateClientProcess(pDevExt, pSession))
787 {
788 pReq->u.Out.u32Cookie = 0xffffffff;
789 pReq->u.Out.u32SessionCookie = 0xffffffff;
790 pReq->u.Out.u32SessionVersion = 0xffffffff;
791 pReq->u.Out.u32DriverVersion = SUPDRVIOC_VERSION;
792 pReq->u.Out.pSession = NULL;
793 pReq->u.Out.cFunctions = 0;
794 pReq->Hdr.rc = VERR_PERMISSION_DENIED;
795 return 0;
796 }
797#endif
798
799 /*
800 * Match the version.
801 * The current logic is very simple, match the major interface version.
802 */
803 if ( pReq->u.In.u32MinVersion > SUPDRVIOC_VERSION
804 || (pReq->u.In.u32MinVersion & 0xffff0000) != (SUPDRVIOC_VERSION & 0xffff0000))
805 {
806 OSDBGPRINT(("SUP_IOCTL_COOKIE: Version mismatch. Requested: %#x Min: %#x Current: %#x\n",
807 pReq->u.In.u32ReqVersion, pReq->u.In.u32MinVersion, SUPDRVIOC_VERSION));
808 pReq->u.Out.u32Cookie = 0xffffffff;
809 pReq->u.Out.u32SessionCookie = 0xffffffff;
810 pReq->u.Out.u32SessionVersion = 0xffffffff;
811 pReq->u.Out.u32DriverVersion = SUPDRVIOC_VERSION;
812 pReq->u.Out.pSession = NULL;
813 pReq->u.Out.cFunctions = 0;
814 pReq->Hdr.rc = VERR_VERSION_MISMATCH;
815 return 0;
816 }
817
818 /*
819 * Fill in return data and be gone.
820 * N.B. The first one to change SUPDRVIOC_VERSION shall makes sure that
821 * u32SessionVersion <= u32ReqVersion!
822 */
823 /** @todo Somehow validate the client and negotiate a secure cookie... */
824 pReq->u.Out.u32Cookie = pDevExt->u32Cookie;
825 pReq->u.Out.u32SessionCookie = pSession->u32Cookie;
826 pReq->u.Out.u32SessionVersion = SUPDRVIOC_VERSION;
827 pReq->u.Out.u32DriverVersion = SUPDRVIOC_VERSION;
828 pReq->u.Out.pSession = pSession;
829 pReq->u.Out.cFunctions = sizeof(g_aFunctions) / sizeof(g_aFunctions[0]);
830 pReq->Hdr.rc = VINF_SUCCESS;
831 return 0;
832 }
833
834 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_QUERY_FUNCS(0)):
835 {
836 /* validate */
837 PSUPQUERYFUNCS pReq = (PSUPQUERYFUNCS)pReqHdr;
838 REQ_CHECK_SIZES_EX(SUP_IOCTL_QUERY_FUNCS, SUP_IOCTL_QUERY_FUNCS_SIZE_IN, SUP_IOCTL_QUERY_FUNCS_SIZE_OUT(RT_ELEMENTS(g_aFunctions)));
839
840 /* execute */
841 pReq->u.Out.cFunctions = RT_ELEMENTS(g_aFunctions);
842 memcpy(&pReq->u.Out.aFunctions[0], g_aFunctions, sizeof(g_aFunctions));
843 pReq->Hdr.rc = VINF_SUCCESS;
844 return 0;
845 }
846
847 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_IDT_INSTALL):
848 {
849 /* validate */
850 PSUPIDTINSTALL pReq = (PSUPIDTINSTALL)pReqHdr;
851 REQ_CHECK_SIZES(SUP_IOCTL_IDT_INSTALL);
852
853 /* execute */
854#ifdef VBOX_WITH_IDT_PATCHING
855 pReq->Hdr.rc = supdrvIOCtl_IdtInstall(pDevExt, pSession, pReq);
856#else
857 pReq->u.Out.u8Idt = 3;
858 pReq->Hdr.rc = VERR_NOT_SUPPORTED;
859#endif
860 return 0;
861 }
862
863 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_IDT_REMOVE):
864 {
865 /* validate */
866 PSUPIDTREMOVE pReq = (PSUPIDTREMOVE)pReqHdr;
867 REQ_CHECK_SIZES(SUP_IOCTL_IDT_REMOVE);
868
869 /* execute */
870#ifdef VBOX_WITH_IDT_PATCHING
871 pReq->Hdr.rc = supdrvIOCtl_IdtRemoveAll(pDevExt, pSession);
872#else
873 pReq->Hdr.rc = VERR_NOT_SUPPORTED;
874#endif
875 return 0;
876 }
877
878 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_PAGE_LOCK):
879 {
880 /* validate */
881 PSUPPAGELOCK pReq = (PSUPPAGELOCK)pReqHdr;
882 REQ_CHECK_SIZE_IN(SUP_IOCTL_PAGE_LOCK, SUP_IOCTL_PAGE_LOCK_SIZE_IN);
883 REQ_CHECK_SIZE_OUT(SUP_IOCTL_PAGE_LOCK, SUP_IOCTL_PAGE_LOCK_SIZE_OUT(pReq->u.In.cPages));
884 REQ_CHECK_EXPR(SUP_IOCTL_PAGE_LOCK, pReq->u.In.cPages > 0);
885 REQ_CHECK_EXPR(SUP_IOCTL_PAGE_LOCK, pReq->u.In.pvR3 >= PAGE_SIZE);
886
887 /* execute */
888 pReq->Hdr.rc = SUPR0LockMem(pSession, pReq->u.In.pvR3, pReq->u.In.cPages, &pReq->u.Out.aPages[0]);
889 if (RT_FAILURE(pReq->Hdr.rc))
890 pReq->Hdr.cbOut = sizeof(pReq->Hdr);
891 return 0;
892 }
893
894 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_PAGE_UNLOCK):
895 {
896 /* validate */
897 PSUPPAGEUNLOCK pReq = (PSUPPAGEUNLOCK)pReqHdr;
898 REQ_CHECK_SIZES(SUP_IOCTL_PAGE_UNLOCK);
899
900 /* execute */
901 pReq->Hdr.rc = SUPR0UnlockMem(pSession, pReq->u.In.pvR3);
902 return 0;
903 }
904
905 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_CONT_ALLOC):
906 {
907 /* validate */
908 PSUPCONTALLOC pReq = (PSUPCONTALLOC)pReqHdr;
909 REQ_CHECK_SIZES(SUP_IOCTL_CONT_ALLOC);
910
911 /* execute */
912 pReq->Hdr.rc = SUPR0ContAlloc(pSession, pReq->u.In.cPages, &pReq->u.Out.pvR0, &pReq->u.Out.pvR3, &pReq->u.Out.HCPhys);
913 if (RT_FAILURE(pReq->Hdr.rc))
914 pReq->Hdr.cbOut = sizeof(pReq->Hdr);
915 return 0;
916 }
917
918 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_CONT_FREE):
919 {
920 /* validate */
921 PSUPCONTFREE pReq = (PSUPCONTFREE)pReqHdr;
922 REQ_CHECK_SIZES(SUP_IOCTL_CONT_FREE);
923
924 /* execute */
925 pReq->Hdr.rc = SUPR0ContFree(pSession, (RTHCUINTPTR)pReq->u.In.pvR3);
926 return 0;
927 }
928
929 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_LDR_OPEN):
930 {
931 /* validate */
932 PSUPLDROPEN pReq = (PSUPLDROPEN)pReqHdr;
933 REQ_CHECK_SIZES(SUP_IOCTL_LDR_OPEN);
934 REQ_CHECK_EXPR(SUP_IOCTL_LDR_OPEN, pReq->u.In.cbImage > 0);
935 REQ_CHECK_EXPR(SUP_IOCTL_LDR_OPEN, pReq->u.In.cbImage < _1M*16);
936 REQ_CHECK_EXPR(SUP_IOCTL_LDR_OPEN, pReq->u.In.szName[0]);
937 REQ_CHECK_EXPR(SUP_IOCTL_LDR_OPEN, memchr(pReq->u.In.szName, '\0', sizeof(pReq->u.In.szName)));
938 REQ_CHECK_EXPR(SUP_IOCTL_LDR_OPEN, !supdrvCheckInvalidChar(pReq->u.In.szName, ";:()[]{}/\\|&*%#@!~`\"'"));
939
940 /* execute */
941 pReq->Hdr.rc = supdrvIOCtl_LdrOpen(pDevExt, pSession, pReq);
942 return 0;
943 }
944
945 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_LDR_LOAD):
946 {
947 /* validate */
948 PSUPLDRLOAD pReq = (PSUPLDRLOAD)pReqHdr;
949 REQ_CHECK_EXPR(Name, pReq->Hdr.cbIn >= sizeof(*pReq));
950 REQ_CHECK_SIZES_EX(SUP_IOCTL_LDR_LOAD, SUP_IOCTL_LDR_LOAD_SIZE_IN(pReq->u.In.cbImage), SUP_IOCTL_LDR_LOAD_SIZE_OUT);
951 REQ_CHECK_EXPR(SUP_IOCTL_LDR_LOAD, pReq->u.In.cSymbols <= 16384);
952 REQ_CHECK_EXPR_FMT( !pReq->u.In.cSymbols
953 || ( pReq->u.In.offSymbols < pReq->u.In.cbImage
954 && pReq->u.In.offSymbols + pReq->u.In.cSymbols * sizeof(SUPLDRSYM) <= pReq->u.In.cbImage),
955 ("SUP_IOCTL_LDR_LOAD: offSymbols=%#lx cSymbols=%#lx cbImage=%#lx\n", (long)pReq->u.In.offSymbols,
956 (long)pReq->u.In.cSymbols, (long)pReq->u.In.cbImage));
957 REQ_CHECK_EXPR_FMT( !pReq->u.In.cbStrTab
958 || ( pReq->u.In.offStrTab < pReq->u.In.cbImage
959 && pReq->u.In.offStrTab + pReq->u.In.cbStrTab <= pReq->u.In.cbImage
960 && pReq->u.In.cbStrTab <= pReq->u.In.cbImage),
961 ("SUP_IOCTL_LDR_LOAD: offStrTab=%#lx cbStrTab=%#lx cbImage=%#lx\n", (long)pReq->u.In.offStrTab,
962 (long)pReq->u.In.cbStrTab, (long)pReq->u.In.cbImage));
963
964 if (pReq->u.In.cSymbols)
965 {
966 uint32_t i;
967 PSUPLDRSYM paSyms = (PSUPLDRSYM)&pReq->u.In.achImage[pReq->u.In.offSymbols];
968 for (i = 0; i < pReq->u.In.cSymbols; i++)
969 {
970 REQ_CHECK_EXPR_FMT(paSyms[i].offSymbol < pReq->u.In.cbImage,
971 ("SUP_IOCTL_LDR_LOAD: sym #%ld: symb off %#lx (max=%#lx)\n", (long)i, (long)paSyms[i].offSymbol, (long)pReq->u.In.cbImage));
972 REQ_CHECK_EXPR_FMT(paSyms[i].offName < pReq->u.In.cbStrTab,
973 ("SUP_IOCTL_LDR_LOAD: sym #%ld: name off %#lx (max=%#lx)\n", (long)i, (long)paSyms[i].offName, (long)pReq->u.In.cbImage));
974 REQ_CHECK_EXPR_FMT(memchr(&pReq->u.In.achImage[pReq->u.In.offStrTab + paSyms[i].offName], '\0', pReq->u.In.cbStrTab - paSyms[i].offName),
975 ("SUP_IOCTL_LDR_LOAD: sym #%ld: unterminated name! (%#lx / %#lx)\n", (long)i, (long)paSyms[i].offName, (long)pReq->u.In.cbImage));
976 }
977 }
978
979 /* execute */
980 pReq->Hdr.rc = supdrvIOCtl_LdrLoad(pDevExt, pSession, pReq);
981 return 0;
982 }
983
984 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_LDR_FREE):
985 {
986 /* validate */
987 PSUPLDRFREE pReq = (PSUPLDRFREE)pReqHdr;
988 REQ_CHECK_SIZES(SUP_IOCTL_LDR_FREE);
989
990 /* execute */
991 pReq->Hdr.rc = supdrvIOCtl_LdrFree(pDevExt, pSession, pReq);
992 return 0;
993 }
994
995 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_LDR_GET_SYMBOL):
996 {
997 /* validate */
998 PSUPLDRGETSYMBOL pReq = (PSUPLDRGETSYMBOL)pReqHdr;
999 REQ_CHECK_SIZES(SUP_IOCTL_LDR_GET_SYMBOL);
1000 REQ_CHECK_EXPR(SUP_IOCTL_LDR_GET_SYMBOL, memchr(pReq->u.In.szSymbol, '\0', sizeof(pReq->u.In.szSymbol)));
1001
1002 /* execute */
1003 pReq->Hdr.rc = supdrvIOCtl_LdrGetSymbol(pDevExt, pSession, pReq);
1004 return 0;
1005 }
1006
1007 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_CALL_VMMR0(0)):
1008 {
1009 /* validate */
1010 PSUPCALLVMMR0 pReq = (PSUPCALLVMMR0)pReqHdr;
1011 Log4(("SUP_IOCTL_CALL_VMMR0: op=%u in=%u arg=%RX64 p/t=%RTproc/%RTthrd\n",
1012 pReq->u.In.uOperation, pReq->Hdr.cbIn, pReq->u.In.u64Arg, RTProcSelf(), RTThreadNativeSelf()));
1013
1014 if (pReq->Hdr.cbIn == SUP_IOCTL_CALL_VMMR0_SIZE(0))
1015 {
1016 REQ_CHECK_SIZES_EX(SUP_IOCTL_CALL_VMMR0, SUP_IOCTL_CALL_VMMR0_SIZE_IN(0), SUP_IOCTL_CALL_VMMR0_SIZE_OUT(0));
1017
1018 /* execute */
1019 if (RT_LIKELY(pDevExt->pfnVMMR0EntryEx))
1020 pReq->Hdr.rc = pDevExt->pfnVMMR0EntryEx(pReq->u.In.pVMR0, pReq->u.In.uOperation, NULL, pReq->u.In.u64Arg);
1021 else
1022 pReq->Hdr.rc = VERR_WRONG_ORDER;
1023 }
1024 else
1025 {
1026 PSUPVMMR0REQHDR pVMMReq = (PSUPVMMR0REQHDR)&pReq->abReqPkt[0];
1027 REQ_CHECK_EXPR_FMT(pReq->Hdr.cbIn >= SUP_IOCTL_CALL_VMMR0_SIZE(sizeof(SUPVMMR0REQHDR)),
1028 ("SUP_IOCTL_CALL_VMMR0: cbIn=%#x < %#x\n", pReq->Hdr.cbIn, SUP_IOCTL_CALL_VMMR0_SIZE(sizeof(SUPVMMR0REQHDR))));
1029 REQ_CHECK_EXPR(SUP_IOCTL_CALL_VMMR0, pVMMReq->u32Magic == SUPVMMR0REQHDR_MAGIC);
1030 REQ_CHECK_SIZES_EX(SUP_IOCTL_CALL_VMMR0, SUP_IOCTL_CALL_VMMR0_SIZE_IN(pVMMReq->cbReq), SUP_IOCTL_CALL_VMMR0_SIZE_OUT(pVMMReq->cbReq));
1031
1032 /* execute */
1033 if (RT_LIKELY(pDevExt->pfnVMMR0EntryEx))
1034 pReq->Hdr.rc = pDevExt->pfnVMMR0EntryEx(pReq->u.In.pVMR0, pReq->u.In.uOperation, pVMMReq, pReq->u.In.u64Arg);
1035 else
1036 pReq->Hdr.rc = VERR_WRONG_ORDER;
1037 }
1038
1039 if ( RT_FAILURE(pReq->Hdr.rc)
1040 && pReq->Hdr.rc != VERR_INTERRUPTED
1041 && pReq->Hdr.rc != VERR_TIMEOUT)
1042 Log(("SUP_IOCTL_CALL_VMMR0: rc=%Rrc op=%u out=%u arg=%RX64 p/t=%RTproc/%RTthrd\n",
1043 pReq->Hdr.rc, pReq->u.In.uOperation, pReq->Hdr.cbOut, pReq->u.In.u64Arg, RTProcSelf(), RTThreadNativeSelf()));
1044 else
1045 Log4(("SUP_IOCTL_CALL_VMMR0: rc=%Rrc op=%u out=%u arg=%RX64 p/t=%RTproc/%RTthrd\n",
1046 pReq->Hdr.rc, pReq->u.In.uOperation, pReq->Hdr.cbOut, pReq->u.In.u64Arg, RTProcSelf(), RTThreadNativeSelf()));
1047 return 0;
1048 }
1049
1050 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_GET_PAGING_MODE):
1051 {
1052 /* validate */
1053 PSUPGETPAGINGMODE pReq = (PSUPGETPAGINGMODE)pReqHdr;
1054 REQ_CHECK_SIZES(SUP_IOCTL_GET_PAGING_MODE);
1055
1056 /* execute */
1057 pReq->Hdr.rc = VINF_SUCCESS;
1058 pReq->u.Out.enmMode = supdrvIOCtl_GetPagingMode();
1059 return 0;
1060 }
1061
1062 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_LOW_ALLOC):
1063 {
1064 /* validate */
1065 PSUPLOWALLOC pReq = (PSUPLOWALLOC)pReqHdr;
1066 REQ_CHECK_EXPR(SUP_IOCTL_LOW_ALLOC, pReq->Hdr.cbIn <= SUP_IOCTL_LOW_ALLOC_SIZE_IN);
1067 REQ_CHECK_SIZES_EX(SUP_IOCTL_LOW_ALLOC, SUP_IOCTL_LOW_ALLOC_SIZE_IN, SUP_IOCTL_LOW_ALLOC_SIZE_OUT(pReq->u.In.cPages));
1068
1069 /* execute */
1070 pReq->Hdr.rc = SUPR0LowAlloc(pSession, pReq->u.In.cPages, &pReq->u.Out.pvR0, &pReq->u.Out.pvR3, &pReq->u.Out.aPages[0]);
1071 if (RT_FAILURE(pReq->Hdr.rc))
1072 pReq->Hdr.cbOut = sizeof(pReq->Hdr);
1073 return 0;
1074 }
1075
1076 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_LOW_FREE):
1077 {
1078 /* validate */
1079 PSUPLOWFREE pReq = (PSUPLOWFREE)pReqHdr;
1080 REQ_CHECK_SIZES(SUP_IOCTL_LOW_FREE);
1081
1082 /* execute */
1083 pReq->Hdr.rc = SUPR0LowFree(pSession, (RTHCUINTPTR)pReq->u.In.pvR3);
1084 return 0;
1085 }
1086
1087 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_GIP_MAP):
1088 {
1089 /* validate */
1090 PSUPGIPMAP pReq = (PSUPGIPMAP)pReqHdr;
1091 REQ_CHECK_SIZES(SUP_IOCTL_GIP_MAP);
1092
1093 /* execute */
1094 pReq->Hdr.rc = SUPR0GipMap(pSession, &pReq->u.Out.pGipR3, &pReq->u.Out.HCPhysGip);
1095 if (RT_SUCCESS(pReq->Hdr.rc))
1096 pReq->u.Out.pGipR0 = pDevExt->pGip;
1097 return 0;
1098 }
1099
1100 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_GIP_UNMAP):
1101 {
1102 /* validate */
1103 PSUPGIPUNMAP pReq = (PSUPGIPUNMAP)pReqHdr;
1104 REQ_CHECK_SIZES(SUP_IOCTL_GIP_UNMAP);
1105
1106 /* execute */
1107 pReq->Hdr.rc = SUPR0GipUnmap(pSession);
1108 return 0;
1109 }
1110
1111 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_SET_VM_FOR_FAST):
1112 {
1113 /* validate */
1114 PSUPSETVMFORFAST pReq = (PSUPSETVMFORFAST)pReqHdr;
1115 REQ_CHECK_SIZES(SUP_IOCTL_SET_VM_FOR_FAST);
1116 REQ_CHECK_EXPR_FMT( !pReq->u.In.pVMR0
1117 || ( VALID_PTR(pReq->u.In.pVMR0)
1118 && !((uintptr_t)pReq->u.In.pVMR0 & (PAGE_SIZE - 1))),
1119 ("SUP_IOCTL_SET_VM_FOR_FAST: pVMR0=%p!\n", pReq->u.In.pVMR0));
1120 /* execute */
1121 pSession->pVM = pReq->u.In.pVMR0;
1122 pReq->Hdr.rc = VINF_SUCCESS;
1123 return 0;
1124 }
1125
1126 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_PAGE_ALLOC):
1127 {
1128 /* validate */
1129 PSUPPAGEALLOC pReq = (PSUPPAGEALLOC)pReqHdr;
1130 REQ_CHECK_EXPR(SUP_IOCTL_PAGE_ALLOC, pReq->Hdr.cbIn <= SUP_IOCTL_PAGE_ALLOC_SIZE_IN);
1131 REQ_CHECK_SIZES_EX(SUP_IOCTL_PAGE_ALLOC, SUP_IOCTL_PAGE_ALLOC_SIZE_IN, SUP_IOCTL_PAGE_ALLOC_SIZE_OUT(pReq->u.In.cPages));
1132
1133 /* execute */
1134 pReq->Hdr.rc = SUPR0PageAlloc(pSession, pReq->u.In.cPages, &pReq->u.Out.pvR3, &pReq->u.Out.aPages[0]);
1135 if (RT_FAILURE(pReq->Hdr.rc))
1136 pReq->Hdr.cbOut = sizeof(pReq->Hdr);
1137 return 0;
1138 }
1139
1140 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_PAGE_FREE):
1141 {
1142 /* validate */
1143 PSUPPAGEFREE pReq = (PSUPPAGEFREE)pReqHdr;
1144 REQ_CHECK_SIZES(SUP_IOCTL_PAGE_FREE);
1145
1146 /* execute */
1147 pReq->Hdr.rc = SUPR0PageFree(pSession, pReq->u.In.pvR3);
1148 return 0;
1149 }
1150
1151 default:
1152 Log(("Unknown IOCTL %#lx\n", (long)uIOCtl));
1153 break;
1154 }
1155 return SUPDRV_ERR_GENERAL_FAILURE;
1156}
1157
1158
1159/**
1160 * Register a object for reference counting.
1161 * The object is registered with one reference in the specified session.
1162 *
1163 * @returns Unique identifier on success (pointer).
1164 * All future reference must use this identifier.
1165 * @returns NULL on failure.
1166 * @param pfnDestructor The destructore function which will be called when the reference count reaches 0.
1167 * @param pvUser1 The first user argument.
1168 * @param pvUser2 The second user argument.
1169 */
1170SUPR0DECL(void *) SUPR0ObjRegister(PSUPDRVSESSION pSession, SUPDRVOBJTYPE enmType, PFNSUPDRVDESTRUCTOR pfnDestructor, void *pvUser1, void *pvUser2)
1171{
1172 RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
1173 PSUPDRVDEVEXT pDevExt = pSession->pDevExt;
1174 PSUPDRVOBJ pObj;
1175 PSUPDRVUSAGE pUsage;
1176
1177 /*
1178 * Validate the input.
1179 */
1180 AssertReturn(SUP_IS_SESSION_VALID(pSession), NULL);
1181 AssertReturn(enmType > SUPDRVOBJTYPE_INVALID && enmType < SUPDRVOBJTYPE_END, NULL);
1182 AssertPtrReturn(pfnDestructor, NULL);
1183
1184 /*
1185 * Allocate and initialize the object.
1186 */
1187 pObj = (PSUPDRVOBJ)RTMemAlloc(sizeof(*pObj));
1188 if (!pObj)
1189 return NULL;
1190 pObj->u32Magic = SUPDRVOBJ_MAGIC;
1191 pObj->enmType = enmType;
1192 pObj->pNext = NULL;
1193 pObj->cUsage = 1;
1194 pObj->pfnDestructor = pfnDestructor;
1195 pObj->pvUser1 = pvUser1;
1196 pObj->pvUser2 = pvUser2;
1197 pObj->CreatorUid = pSession->Uid;
1198 pObj->CreatorGid = pSession->Gid;
1199 pObj->CreatorProcess= pSession->Process;
1200 supdrvOSObjInitCreator(pObj, pSession);
1201
1202 /*
1203 * Allocate the usage record.
1204 * (We keep freed usage records around to simplity SUPR0ObjAddRef().)
1205 */
1206 RTSpinlockAcquire(pDevExt->Spinlock, &SpinlockTmp);
1207
1208 pUsage = pDevExt->pUsageFree;
1209 if (pUsage)
1210 pDevExt->pUsageFree = pUsage->pNext;
1211 else
1212 {
1213 RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
1214 pUsage = (PSUPDRVUSAGE)RTMemAlloc(sizeof(*pUsage));
1215 if (!pUsage)
1216 {
1217 RTMemFree(pObj);
1218 return NULL;
1219 }
1220 RTSpinlockAcquire(pDevExt->Spinlock, &SpinlockTmp);
1221 }
1222
1223 /*
1224 * Insert the object and create the session usage record.
1225 */
1226 /* The object. */
1227 pObj->pNext = pDevExt->pObjs;
1228 pDevExt->pObjs = pObj;
1229
1230 /* The session record. */
1231 pUsage->cUsage = 1;
1232 pUsage->pObj = pObj;
1233 pUsage->pNext = pSession->pUsage;
1234 Log2(("SUPR0ObjRegister: pUsage=%p:{.pObj=%p, .pNext=%p}\n", pUsage, pUsage->pObj, pUsage->pNext));
1235 pSession->pUsage = pUsage;
1236
1237 RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
1238
1239 Log(("SUPR0ObjRegister: returns %p (pvUser1=%p, pvUser=%p)\n", pObj, pvUser1, pvUser2));
1240 return pObj;
1241}
1242
1243
1244/**
1245 * Increment the reference counter for the object associating the reference
1246 * with the specified session.
1247 *
1248 * @returns IPRT status code.
1249 * @param pvObj The identifier returned by SUPR0ObjRegister().
1250 * @param pSession The session which is referencing the object.
1251 */
1252SUPR0DECL(int) SUPR0ObjAddRef(void *pvObj, PSUPDRVSESSION pSession)
1253{
1254 RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
1255 PSUPDRVDEVEXT pDevExt = pSession->pDevExt;
1256 PSUPDRVOBJ pObj = (PSUPDRVOBJ)pvObj;
1257 PSUPDRVUSAGE pUsagePre;
1258 PSUPDRVUSAGE pUsage;
1259
1260 /*
1261 * Validate the input.
1262 */
1263 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
1264 AssertMsgReturn(VALID_PTR(pObj) && pObj->u32Magic == SUPDRVOBJ_MAGIC,
1265 ("Invalid pvObj=%p magic=%#x (exepcted %#x)\n", pvObj, pObj ? pObj->u32Magic : 0, SUPDRVOBJ_MAGIC),
1266 VERR_INVALID_PARAMETER);
1267
1268 /*
1269 * Preallocate the usage record.
1270 */
1271 RTSpinlockAcquire(pDevExt->Spinlock, &SpinlockTmp);
1272
1273 pUsagePre = pDevExt->pUsageFree;
1274 if (pUsagePre)
1275 pDevExt->pUsageFree = pUsagePre->pNext;
1276 else
1277 {
1278 RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
1279 pUsagePre = (PSUPDRVUSAGE)RTMemAlloc(sizeof(*pUsagePre));
1280 if (!pUsagePre)
1281 return VERR_NO_MEMORY;
1282 RTSpinlockAcquire(pDevExt->Spinlock, &SpinlockTmp);
1283 }
1284
1285 /*
1286 * Reference the object.
1287 */
1288 pObj->cUsage++;
1289
1290 /*
1291 * Look for the session record.
1292 */
1293 for (pUsage = pSession->pUsage; pUsage; pUsage = pUsage->pNext)
1294 {
1295 Log(("SUPR0AddRef: pUsage=%p:{.pObj=%p, .pNext=%p}\n", pUsage, pUsage->pObj, pUsage->pNext));
1296 if (pUsage->pObj == pObj)
1297 break;
1298 }
1299 if (pUsage)
1300 pUsage->cUsage++;
1301 else
1302 {
1303 /* create a new session record. */
1304 pUsagePre->cUsage = 1;
1305 pUsagePre->pObj = pObj;
1306 pUsagePre->pNext = pSession->pUsage;
1307 pSession->pUsage = pUsagePre;
1308 Log(("SUPR0AddRef: pUsagePre=%p:{.pObj=%p, .pNext=%p}\n", pUsagePre, pUsagePre->pObj, pUsagePre->pNext));
1309
1310 pUsagePre = NULL;
1311 }
1312
1313 /*
1314 * Put any unused usage record into the free list..
1315 */
1316 if (pUsagePre)
1317 {
1318 pUsagePre->pNext = pDevExt->pUsageFree;
1319 pDevExt->pUsageFree = pUsagePre;
1320 }
1321
1322 RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
1323
1324 return VINF_SUCCESS;
1325}
1326
1327
1328/**
1329 * Decrement / destroy a reference counter record for an object.
1330 *
1331 * The object is uniquely identified by pfnDestructor+pvUser1+pvUser2.
1332 *
1333 * @returns IPRT status code.
1334 * @param pvObj The identifier returned by SUPR0ObjRegister().
1335 * @param pSession The session which is referencing the object.
1336 */
1337SUPR0DECL(int) SUPR0ObjRelease(void *pvObj, PSUPDRVSESSION pSession)
1338{
1339 RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
1340 PSUPDRVDEVEXT pDevExt = pSession->pDevExt;
1341 PSUPDRVOBJ pObj = (PSUPDRVOBJ)pvObj;
1342 bool fDestroy = false;
1343 PSUPDRVUSAGE pUsage;
1344 PSUPDRVUSAGE pUsagePrev;
1345
1346 /*
1347 * Validate the input.
1348 */
1349 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
1350 AssertMsgReturn(VALID_PTR(pObj) && pObj->u32Magic == SUPDRVOBJ_MAGIC,
1351 ("Invalid pvObj=%p magic=%#x (exepcted %#x)\n", pvObj, pObj ? pObj->u32Magic : 0, SUPDRVOBJ_MAGIC),
1352 VERR_INVALID_PARAMETER);
1353
1354 /*
1355 * Acquire the spinlock and look for the usage record.
1356 */
1357 RTSpinlockAcquire(pDevExt->Spinlock, &SpinlockTmp);
1358
1359 for (pUsagePrev = NULL, pUsage = pSession->pUsage;
1360 pUsage;
1361 pUsagePrev = pUsage, pUsage = pUsage->pNext)
1362 {
1363 Log2(("SUPR0ObjRelease: pUsage=%p:{.pObj=%p, .pNext=%p}\n", pUsage, pUsage->pObj, pUsage->pNext));
1364 if (pUsage->pObj == pObj)
1365 {
1366 AssertMsg(pUsage->cUsage >= 1 && pObj->cUsage >= pUsage->cUsage, ("glob %d; sess %d\n", pObj->cUsage, pUsage->cUsage));
1367 if (pUsage->cUsage > 1)
1368 {
1369 pObj->cUsage--;
1370 pUsage->cUsage--;
1371 }
1372 else
1373 {
1374 /*
1375 * Free the session record.
1376 */
1377 if (pUsagePrev)
1378 pUsagePrev->pNext = pUsage->pNext;
1379 else
1380 pSession->pUsage = pUsage->pNext;
1381 pUsage->pNext = pDevExt->pUsageFree;
1382 pDevExt->pUsageFree = pUsage;
1383
1384 /* What about the object? */
1385 if (pObj->cUsage > 1)
1386 pObj->cUsage--;
1387 else
1388 {
1389 /*
1390 * Object is to be destroyed, unlink it.
1391 */
1392 pObj->u32Magic = SUPDRVOBJ_MAGIC + 1;
1393 fDestroy = true;
1394 if (pDevExt->pObjs == pObj)
1395 pDevExt->pObjs = pObj->pNext;
1396 else
1397 {
1398 PSUPDRVOBJ pObjPrev;
1399 for (pObjPrev = pDevExt->pObjs; pObjPrev; pObjPrev = pObjPrev->pNext)
1400 if (pObjPrev->pNext == pObj)
1401 {
1402 pObjPrev->pNext = pObj->pNext;
1403 break;
1404 }
1405 Assert(pObjPrev);
1406 }
1407 }
1408 }
1409 break;
1410 }
1411 }
1412
1413 RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
1414
1415 /*
1416 * Call the destructor and free the object if required.
1417 */
1418 if (fDestroy)
1419 {
1420 Log(("SUPR0ObjRelease: destroying %p/%d (%p/%p) cpid=%RTproc pid=%RTproc dtor=%p\n",
1421 pObj, pObj->enmType, pObj->pvUser1, pObj->pvUser2, pObj->CreatorProcess, RTProcSelf(), pObj->pfnDestructor));
1422 if (pObj->pfnDestructor)
1423 pObj->pfnDestructor(pObj, pObj->pvUser1, pObj->pvUser2);
1424 RTMemFree(pObj);
1425 }
1426
1427 AssertMsg(pUsage, ("pvObj=%p\n", pvObj));
1428 return pUsage ? VINF_SUCCESS : VERR_INVALID_PARAMETER;
1429}
1430
1431/**
1432 * Verifies that the current process can access the specified object.
1433 *
1434 * @returns The following IPRT status code:
1435 * @retval VINF_SUCCESS if access was granted.
1436 * @retval VERR_PERMISSION_DENIED if denied access.
1437 * @retval VERR_INVALID_PARAMETER if invalid parameter.
1438 *
1439 * @param pvObj The identifier returned by SUPR0ObjRegister().
1440 * @param pSession The session which wishes to access the object.
1441 * @param pszObjName Object string name. This is optional and depends on the object type.
1442 *
1443 * @remark The caller is responsible for making sure the object isn't removed while
1444 * we're inside this function. If uncertain about this, just call AddRef before calling us.
1445 */
1446SUPR0DECL(int) SUPR0ObjVerifyAccess(void *pvObj, PSUPDRVSESSION pSession, const char *pszObjName)
1447{
1448 PSUPDRVOBJ pObj = (PSUPDRVOBJ)pvObj;
1449 int rc;
1450
1451 /*
1452 * Validate the input.
1453 */
1454 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
1455 AssertMsgReturn(VALID_PTR(pObj) && pObj->u32Magic == SUPDRVOBJ_MAGIC,
1456 ("Invalid pvObj=%p magic=%#x (exepcted %#x)\n", pvObj, pObj ? pObj->u32Magic : 0, SUPDRVOBJ_MAGIC),
1457 VERR_INVALID_PARAMETER);
1458
1459 /*
1460 * Check access. (returns true if a decision has been made.)
1461 */
1462 rc = VERR_INTERNAL_ERROR;
1463 if (supdrvOSObjCanAccess(pObj, pSession, pszObjName, &rc))
1464 return rc;
1465
1466 /*
1467 * Default policy is to allow the user to access his own
1468 * stuff but nothing else.
1469 */
1470 if (pObj->CreatorUid == pSession->Uid)
1471 return VINF_SUCCESS;
1472 return VERR_PERMISSION_DENIED;
1473}
1474
1475
1476/**
1477 * Lock pages.
1478 *
1479 * @returns IPRT status code.
1480 * @param pSession Session to which the locked memory should be associated.
1481 * @param pvR3 Start of the memory range to lock.
1482 * This must be page aligned.
1483 * @param cb Size of the memory range to lock.
1484 * This must be page aligned.
1485 */
1486SUPR0DECL(int) SUPR0LockMem(PSUPDRVSESSION pSession, RTR3PTR pvR3, uint32_t cPages, PRTHCPHYS paPages)
1487{
1488 int rc;
1489 SUPDRVMEMREF Mem = {0};
1490 const size_t cb = (size_t)cPages << PAGE_SHIFT;
1491 LogFlow(("SUPR0LockMem: pSession=%p pvR3=%p cPages=%d paPages=%p\n", pSession, (void *)pvR3, cPages, paPages));
1492
1493 /*
1494 * Verify input.
1495 */
1496 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
1497 AssertPtrReturn(paPages, VERR_INVALID_PARAMETER);
1498 if ( RT_ALIGN_R3PT(pvR3, PAGE_SIZE, RTR3PTR) != pvR3
1499 || !pvR3)
1500 {
1501 Log(("pvR3 (%p) must be page aligned and not NULL!\n", (void *)pvR3));
1502 return VERR_INVALID_PARAMETER;
1503 }
1504
1505#ifdef RT_OS_WINDOWS /* A temporary hack for windows, will be removed once all ring-3 code has been cleaned up. */
1506 /* First check if we allocated it using SUPPageAlloc; if so then we don't need to lock it again */
1507 rc = supdrvPageGetPhys(pSession, pvR3, cPages, paPages);
1508 if (RT_SUCCESS(rc))
1509 return rc;
1510#endif
1511
1512 /*
1513 * Let IPRT do the job.
1514 */
1515 Mem.eType = MEMREF_TYPE_LOCKED;
1516 rc = RTR0MemObjLockUser(&Mem.MemObj, pvR3, cb, RTR0ProcHandleSelf());
1517 if (RT_SUCCESS(rc))
1518 {
1519 uint32_t iPage = cPages;
1520 AssertMsg(RTR0MemObjAddressR3(Mem.MemObj) == pvR3, ("%p == %p\n", RTR0MemObjAddressR3(Mem.MemObj), pvR3));
1521 AssertMsg(RTR0MemObjSize(Mem.MemObj) == cb, ("%x == %x\n", RTR0MemObjSize(Mem.MemObj), cb));
1522
1523 while (iPage-- > 0)
1524 {
1525 paPages[iPage] = RTR0MemObjGetPagePhysAddr(Mem.MemObj, iPage);
1526 if (RT_UNLIKELY(paPages[iPage] == NIL_RTCCPHYS))
1527 {
1528 AssertMsgFailed(("iPage=%d\n", iPage));
1529 rc = VERR_INTERNAL_ERROR;
1530 break;
1531 }
1532 }
1533 if (RT_SUCCESS(rc))
1534 rc = supdrvMemAdd(&Mem, pSession);
1535 if (RT_FAILURE(rc))
1536 {
1537 int rc2 = RTR0MemObjFree(Mem.MemObj, false);
1538 AssertRC(rc2);
1539 }
1540 }
1541
1542 return rc;
1543}
1544
1545
1546/**
1547 * Unlocks the memory pointed to by pv.
1548 *
1549 * @returns IPRT status code.
1550 * @param pSession Session to which the memory was locked.
1551 * @param pvR3 Memory to unlock.
1552 */
1553SUPR0DECL(int) SUPR0UnlockMem(PSUPDRVSESSION pSession, RTR3PTR pvR3)
1554{
1555 LogFlow(("SUPR0UnlockMem: pSession=%p pvR3=%p\n", pSession, (void *)pvR3));
1556 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
1557#ifdef RT_OS_WINDOWS
1558 /*
1559 * Temporary hack for windows - SUPR0PageFree will unlock SUPR0PageAlloc
1560 * allocations; ignore this call.
1561 */
1562 if (supdrvPageWasLockedByPageAlloc(pSession, pvR3))
1563 {
1564 LogFlow(("Page will be unlocked in SUPR0PageFree -> ignore\n"));
1565 return VINF_SUCCESS;
1566 }
1567#endif
1568 return supdrvMemRelease(pSession, (RTHCUINTPTR)pvR3, MEMREF_TYPE_LOCKED);
1569}
1570
1571
1572/**
1573 * Allocates a chunk of page aligned memory with contiguous and fixed physical
1574 * backing.
1575 *
1576 * @returns IPRT status code.
1577 * @param pSession Session data.
1578 * @param cb Number of bytes to allocate.
1579 * @param ppvR0 Where to put the address of Ring-0 mapping the allocated memory.
1580 * @param ppvR3 Where to put the address of Ring-3 mapping the allocated memory.
1581 * @param pHCPhys Where to put the physical address of allocated memory.
1582 */
1583SUPR0DECL(int) SUPR0ContAlloc(PSUPDRVSESSION pSession, uint32_t cPages, PRTR0PTR ppvR0, PRTR3PTR ppvR3, PRTHCPHYS pHCPhys)
1584{
1585 int rc;
1586 SUPDRVMEMREF Mem = {0};
1587 LogFlow(("SUPR0ContAlloc: pSession=%p cPages=%d ppvR0=%p ppvR3=%p pHCPhys=%p\n", pSession, cPages, ppvR0, ppvR3, pHCPhys));
1588
1589 /*
1590 * Validate input.
1591 */
1592 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
1593 if (!ppvR3 || !ppvR0 || !pHCPhys)
1594 {
1595 Log(("Null pointer. All of these should be set: pSession=%p ppvR0=%p ppvR3=%p pHCPhys=%p\n",
1596 pSession, ppvR0, ppvR3, pHCPhys));
1597 return VERR_INVALID_PARAMETER;
1598
1599 }
1600 if (cPages < 1 || cPages >= 256)
1601 {
1602 Log(("Illegal request cPages=%d, must be greater than 0 and smaller than 256\n", cPages));
1603 return VERR_INVALID_PARAMETER;
1604 }
1605
1606 /*
1607 * Let IPRT do the job.
1608 */
1609 rc = RTR0MemObjAllocCont(&Mem.MemObj, cPages << PAGE_SHIFT, true /* executable R0 mapping */);
1610 if (RT_SUCCESS(rc))
1611 {
1612 int rc2;
1613 rc = RTR0MemObjMapUser(&Mem.MapObjR3, Mem.MemObj, (RTR3PTR)-1, 0,
1614 RTMEM_PROT_EXEC | RTMEM_PROT_WRITE | RTMEM_PROT_READ, RTR0ProcHandleSelf());
1615 if (RT_SUCCESS(rc))
1616 {
1617 Mem.eType = MEMREF_TYPE_CONT;
1618 rc = supdrvMemAdd(&Mem, pSession);
1619 if (!rc)
1620 {
1621 *ppvR0 = RTR0MemObjAddress(Mem.MemObj);
1622 *ppvR3 = RTR0MemObjAddressR3(Mem.MapObjR3);
1623 *pHCPhys = RTR0MemObjGetPagePhysAddr(Mem.MemObj, 0);
1624 return 0;
1625 }
1626
1627 rc2 = RTR0MemObjFree(Mem.MapObjR3, false);
1628 AssertRC(rc2);
1629 }
1630 rc2 = RTR0MemObjFree(Mem.MemObj, false);
1631 AssertRC(rc2);
1632 }
1633
1634 return rc;
1635}
1636
1637
1638/**
1639 * Frees memory allocated using SUPR0ContAlloc().
1640 *
1641 * @returns IPRT status code.
1642 * @param pSession The session to which the memory was allocated.
1643 * @param uPtr Pointer to the memory (ring-3 or ring-0).
1644 */
1645SUPR0DECL(int) SUPR0ContFree(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr)
1646{
1647 LogFlow(("SUPR0ContFree: pSession=%p uPtr=%p\n", pSession, (void *)uPtr));
1648 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
1649 return supdrvMemRelease(pSession, uPtr, MEMREF_TYPE_CONT);
1650}
1651
1652
1653/**
1654 * Allocates a chunk of page aligned memory with fixed physical backing below 4GB.
1655 *
1656 * The memory isn't zeroed.
1657 *
1658 * @returns IPRT status code.
1659 * @param pSession Session data.
1660 * @param cPages Number of pages to allocate.
1661 * @param ppvR0 Where to put the address of Ring-0 mapping of the allocated memory.
1662 * @param ppvR3 Where to put the address of Ring-3 mapping of the allocated memory.
1663 * @param paPages Where to put the physical addresses of allocated memory.
1664 */
1665SUPR0DECL(int) SUPR0LowAlloc(PSUPDRVSESSION pSession, uint32_t cPages, PRTR0PTR ppvR0, PRTR3PTR ppvR3, PRTHCPHYS paPages)
1666{
1667 unsigned iPage;
1668 int rc;
1669 SUPDRVMEMREF Mem = {0};
1670 LogFlow(("SUPR0LowAlloc: pSession=%p cPages=%d ppvR3=%p ppvR0=%p paPages=%p\n", pSession, cPages, ppvR3, ppvR0, paPages));
1671
1672 /*
1673 * Validate input.
1674 */
1675 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
1676 if (!ppvR3 || !ppvR0 || !paPages)
1677 {
1678 Log(("Null pointer. All of these should be set: pSession=%p ppvR3=%p ppvR0=%p paPages=%p\n",
1679 pSession, ppvR3, ppvR0, paPages));
1680 return VERR_INVALID_PARAMETER;
1681
1682 }
1683 if (cPages < 1 || cPages > 256)
1684 {
1685 Log(("Illegal request cPages=%d, must be greater than 0 and smaller than 256.\n", cPages));
1686 return VERR_INVALID_PARAMETER;
1687 }
1688
1689 /*
1690 * Let IPRT do the work.
1691 */
1692 rc = RTR0MemObjAllocLow(&Mem.MemObj, cPages << PAGE_SHIFT, true /* executable ring-0 mapping */);
1693 if (RT_SUCCESS(rc))
1694 {
1695 int rc2;
1696 rc = RTR0MemObjMapUser(&Mem.MapObjR3, Mem.MemObj, (RTR3PTR)-1, 0,
1697 RTMEM_PROT_EXEC | RTMEM_PROT_WRITE | RTMEM_PROT_READ, RTR0ProcHandleSelf());
1698 if (RT_SUCCESS(rc))
1699 {
1700 Mem.eType = MEMREF_TYPE_LOW;
1701 rc = supdrvMemAdd(&Mem, pSession);
1702 if (!rc)
1703 {
1704 for (iPage = 0; iPage < cPages; iPage++)
1705 {
1706 paPages[iPage] = RTR0MemObjGetPagePhysAddr(Mem.MemObj, iPage);
1707 AssertMsg(!(paPages[iPage] & (PAGE_SIZE - 1)), ("iPage=%d Phys=%VHp\n", paPages[iPage]));
1708 }
1709 *ppvR0 = RTR0MemObjAddress(Mem.MemObj);
1710 *ppvR3 = RTR0MemObjAddressR3(Mem.MapObjR3);
1711 return 0;
1712 }
1713
1714 rc2 = RTR0MemObjFree(Mem.MapObjR3, false);
1715 AssertRC(rc2);
1716 }
1717
1718 rc2 = RTR0MemObjFree(Mem.MemObj, false);
1719 AssertRC(rc2);
1720 }
1721
1722 return rc;
1723}
1724
1725
1726/**
1727 * Frees memory allocated using SUPR0LowAlloc().
1728 *
1729 * @returns IPRT status code.
1730 * @param pSession The session to which the memory was allocated.
1731 * @param uPtr Pointer to the memory (ring-3 or ring-0).
1732 */
1733SUPR0DECL(int) SUPR0LowFree(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr)
1734{
1735 LogFlow(("SUPR0LowFree: pSession=%p uPtr=%p\n", pSession, (void *)uPtr));
1736 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
1737 return supdrvMemRelease(pSession, uPtr, MEMREF_TYPE_LOW);
1738}
1739
1740
1741
1742/**
1743 * Allocates a chunk of memory with both R0 and R3 mappings.
1744 * The memory is fixed and it's possible to query the physical addresses using SUPR0MemGetPhys().
1745 *
1746 * @returns IPRT status code.
1747 * @param pSession The session to associated the allocation with.
1748 * @param cb Number of bytes to allocate.
1749 * @param ppvR0 Where to store the address of the Ring-0 mapping.
1750 * @param ppvR3 Where to store the address of the Ring-3 mapping.
1751 */
1752SUPR0DECL(int) SUPR0MemAlloc(PSUPDRVSESSION pSession, uint32_t cb, PRTR0PTR ppvR0, PRTR3PTR ppvR3)
1753{
1754 int rc;
1755 SUPDRVMEMREF Mem = {0};
1756 LogFlow(("SUPR0MemAlloc: pSession=%p cb=%d ppvR0=%p ppvR3=%p\n", pSession, cb, ppvR0, ppvR3));
1757
1758 /*
1759 * Validate input.
1760 */
1761 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
1762 AssertPtrReturn(ppvR0, VERR_INVALID_POINTER);
1763 AssertPtrReturn(ppvR3, VERR_INVALID_POINTER);
1764 if (cb < 1 || cb >= _4M)
1765 {
1766 Log(("Illegal request cb=%u; must be greater than 0 and smaller than 4MB.\n", cb));
1767 return VERR_INVALID_PARAMETER;
1768 }
1769
1770 /*
1771 * Let IPRT do the work.
1772 */
1773 rc = RTR0MemObjAllocPage(&Mem.MemObj, cb, true /* executable ring-0 mapping */);
1774 if (RT_SUCCESS(rc))
1775 {
1776 int rc2;
1777 rc = RTR0MemObjMapUser(&Mem.MapObjR3, Mem.MemObj, (RTR3PTR)-1, 0,
1778 RTMEM_PROT_EXEC | RTMEM_PROT_WRITE | RTMEM_PROT_READ, RTR0ProcHandleSelf());
1779 if (RT_SUCCESS(rc))
1780 {
1781 Mem.eType = MEMREF_TYPE_MEM;
1782 rc = supdrvMemAdd(&Mem, pSession);
1783 if (!rc)
1784 {
1785 *ppvR0 = RTR0MemObjAddress(Mem.MemObj);
1786 *ppvR3 = RTR0MemObjAddressR3(Mem.MapObjR3);
1787 return VINF_SUCCESS;
1788 }
1789 rc2 = RTR0MemObjFree(Mem.MapObjR3, false);
1790 AssertRC(rc2);
1791 }
1792
1793 rc2 = RTR0MemObjFree(Mem.MemObj, false);
1794 AssertRC(rc2);
1795 }
1796
1797 return rc;
1798}
1799
1800
1801/**
1802 * Get the physical addresses of memory allocated using SUPR0MemAlloc().
1803 *
1804 * @returns IPRT status code.
1805 * @param pSession The session to which the memory was allocated.
1806 * @param uPtr The Ring-0 or Ring-3 address returned by SUPR0MemAlloc().
1807 * @param paPages Where to store the physical addresses.
1808 */
1809SUPR0DECL(int) SUPR0MemGetPhys(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr, PSUPPAGE paPages) /** @todo switch this bugger to RTHCPHYS */
1810{
1811 PSUPDRVBUNDLE pBundle;
1812 RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
1813 LogFlow(("SUPR0MemGetPhys: pSession=%p uPtr=%p paPages=%p\n", pSession, (void *)uPtr, paPages));
1814
1815 /*
1816 * Validate input.
1817 */
1818 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
1819 AssertPtrReturn(paPages, VERR_INVALID_POINTER);
1820 AssertReturn(uPtr, VERR_INVALID_PARAMETER);
1821
1822 /*
1823 * Search for the address.
1824 */
1825 RTSpinlockAcquire(pSession->Spinlock, &SpinlockTmp);
1826 for (pBundle = &pSession->Bundle; pBundle; pBundle = pBundle->pNext)
1827 {
1828 if (pBundle->cUsed > 0)
1829 {
1830 unsigned i;
1831 for (i = 0; i < RT_ELEMENTS(pBundle->aMem); i++)
1832 {
1833 if ( pBundle->aMem[i].eType == MEMREF_TYPE_MEM
1834 && pBundle->aMem[i].MemObj != NIL_RTR0MEMOBJ
1835 && ( (RTHCUINTPTR)RTR0MemObjAddress(pBundle->aMem[i].MemObj) == uPtr
1836 || ( pBundle->aMem[i].MapObjR3 != NIL_RTR0MEMOBJ
1837 && RTR0MemObjAddressR3(pBundle->aMem[i].MapObjR3) == uPtr)
1838 )
1839 )
1840 {
1841 const unsigned cPages = RTR0MemObjSize(pBundle->aMem[i].MemObj) >> PAGE_SHIFT;
1842 unsigned iPage;
1843 for (iPage = 0; iPage < cPages; iPage++)
1844 {
1845 paPages[iPage].Phys = RTR0MemObjGetPagePhysAddr(pBundle->aMem[i].MemObj, iPage);
1846 paPages[iPage].uReserved = 0;
1847 }
1848 RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
1849 return VINF_SUCCESS;
1850 }
1851 }
1852 }
1853 }
1854 RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
1855 Log(("Failed to find %p!!!\n", (void *)uPtr));
1856 return VERR_INVALID_PARAMETER;
1857}
1858
1859
1860/**
1861 * Free memory allocated by SUPR0MemAlloc().
1862 *
1863 * @returns IPRT status code.
1864 * @param pSession The session owning the allocation.
1865 * @param uPtr The Ring-0 or Ring-3 address returned by SUPR0MemAlloc().
1866 */
1867SUPR0DECL(int) SUPR0MemFree(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr)
1868{
1869 LogFlow(("SUPR0MemFree: pSession=%p uPtr=%p\n", pSession, (void *)uPtr));
1870 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
1871 return supdrvMemRelease(pSession, uPtr, MEMREF_TYPE_MEM);
1872}
1873
1874
1875/**
1876 * Allocates a chunk of memory with only a R3 mappings.
1877 * The memory is fixed and it's possible to query the physical addresses using SUPR0MemGetPhys().
1878 *
1879 * @returns IPRT status code.
1880 * @param pSession The session to associated the allocation with.
1881 * @param cPages The number of pages to allocate.
1882 * @param ppvR3 Where to store the address of the Ring-3 mapping.
1883 * @param paPages Where to store the addresses of the pages. Optional.
1884 */
1885SUPR0DECL(int) SUPR0PageAlloc(PSUPDRVSESSION pSession, uint32_t cPages, PRTR3PTR ppvR3, PRTHCPHYS paPages)
1886{
1887 int rc;
1888 SUPDRVMEMREF Mem = {0};
1889 LogFlow(("SUPR0PageAlloc: pSession=%p cb=%d ppvR3=%p\n", pSession, cPages, ppvR3));
1890
1891 /*
1892 * Validate input. The allowed allocation size must be at least equal to the maximum guest VRAM size.
1893 */
1894 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
1895 AssertPtrReturn(ppvR3, VERR_INVALID_POINTER);
1896 if (cPages < 1 || cPages > (128 * _1M)/PAGE_SIZE)
1897 {
1898 Log(("SUPR0PageAlloc: Illegal request cb=%u; must be greater than 0 and smaller than 128MB.\n", cPages));
1899 return VERR_INVALID_PARAMETER;
1900 }
1901
1902 /*
1903 * Let IPRT do the work.
1904 */
1905 rc = RTR0MemObjAllocPhysNC(&Mem.MemObj, (size_t)cPages * PAGE_SIZE, NIL_RTHCPHYS);
1906 if (RT_SUCCESS(rc))
1907 {
1908 int rc2;
1909 rc = RTR0MemObjMapUser(&Mem.MapObjR3, Mem.MemObj, (RTR3PTR)-1, 0,
1910 RTMEM_PROT_EXEC | RTMEM_PROT_WRITE | RTMEM_PROT_READ, RTR0ProcHandleSelf());
1911 if (RT_SUCCESS(rc))
1912 {
1913 Mem.eType = MEMREF_TYPE_LOCKED_SUP;
1914 rc = supdrvMemAdd(&Mem, pSession);
1915 if (!rc)
1916 {
1917 *ppvR3 = RTR0MemObjAddressR3(Mem.MapObjR3);
1918 if (paPages)
1919 {
1920 uint32_t iPage = cPages;
1921 while (iPage-- > 0)
1922 {
1923 paPages[iPage] = RTR0MemObjGetPagePhysAddr(Mem.MapObjR3, iPage);
1924 Assert(paPages[iPage] != NIL_RTHCPHYS);
1925 }
1926 }
1927 return VINF_SUCCESS;
1928 }
1929 rc2 = RTR0MemObjFree(Mem.MapObjR3, false);
1930 AssertRC(rc2);
1931 }
1932
1933 rc2 = RTR0MemObjFree(Mem.MemObj, false);
1934 AssertRC(rc2);
1935 }
1936 return rc;
1937}
1938
1939
1940#ifdef RT_OS_WINDOWS
1941/**
1942 * Check if the pages were locked by SUPR0PageAlloc
1943 *
1944 * This function will be removed along with the lock/unlock hacks when
1945 * we've cleaned up the ring-3 code properly.
1946 *
1947 * @returns boolean
1948 * @param pSession The session to which the memory was allocated.
1949 * @param pvR3 The Ring-3 address returned by SUPR0PageAlloc().
1950 */
1951static bool supdrvPageWasLockedByPageAlloc(PSUPDRVSESSION pSession, RTR3PTR pvR3)
1952{
1953 PSUPDRVBUNDLE pBundle;
1954 RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
1955 LogFlow(("SUPR0PageIsLockedByPageAlloc: pSession=%p pvR3=%p\n", pSession, (void *)pvR3));
1956
1957 /*
1958 * Search for the address.
1959 */
1960 RTSpinlockAcquire(pSession->Spinlock, &SpinlockTmp);
1961 for (pBundle = &pSession->Bundle; pBundle; pBundle = pBundle->pNext)
1962 {
1963 if (pBundle->cUsed > 0)
1964 {
1965 unsigned i;
1966 for (i = 0; i < RT_ELEMENTS(pBundle->aMem); i++)
1967 {
1968 if ( pBundle->aMem[i].eType == MEMREF_TYPE_LOCKED_SUP
1969 && pBundle->aMem[i].MemObj != NIL_RTR0MEMOBJ
1970 && pBundle->aMem[i].MapObjR3 != NIL_RTR0MEMOBJ
1971 && RTR0MemObjAddressR3(pBundle->aMem[i].MapObjR3) == pvR3)
1972 {
1973 RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
1974 return true;
1975 }
1976 }
1977 }
1978 }
1979 RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
1980 return false;
1981}
1982
1983
1984/**
1985 * Get the physical addresses of memory allocated using SUPR0PageAlloc().
1986 *
1987 * This function will be removed along with the lock/unlock hacks when
1988 * we've cleaned up the ring-3 code properly.
1989 *
1990 * @returns IPRT status code.
1991 * @param pSession The session to which the memory was allocated.
1992 * @param pvR3 The Ring-3 address returned by SUPR0PageAlloc().
1993 * @param cPages Number of pages in paPages
1994 * @param paPages Where to store the physical addresses.
1995 */
1996static int supdrvPageGetPhys(PSUPDRVSESSION pSession, RTR3PTR pvR3, uint32_t cPages, PRTHCPHYS paPages)
1997{
1998 PSUPDRVBUNDLE pBundle;
1999 RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
2000 LogFlow(("supdrvPageGetPhys: pSession=%p pvR3=%p cPages=%#lx paPages=%p\n", pSession, (void *)pvR3, (long)cPages, paPages));
2001
2002 /*
2003 * Search for the address.
2004 */
2005 RTSpinlockAcquire(pSession->Spinlock, &SpinlockTmp);
2006 for (pBundle = &pSession->Bundle; pBundle; pBundle = pBundle->pNext)
2007 {
2008 if (pBundle->cUsed > 0)
2009 {
2010 unsigned i;
2011 for (i = 0; i < RT_ELEMENTS(pBundle->aMem); i++)
2012 {
2013 if ( pBundle->aMem[i].eType == MEMREF_TYPE_LOCKED_SUP
2014 && pBundle->aMem[i].MemObj != NIL_RTR0MEMOBJ
2015 && pBundle->aMem[i].MapObjR3 != NIL_RTR0MEMOBJ
2016 && RTR0MemObjAddressR3(pBundle->aMem[i].MapObjR3) == pvR3)
2017 {
2018 uint32_t iPage = RTR0MemObjSize(pBundle->aMem[i].MemObj) >> PAGE_SHIFT;
2019 cPages = RT_MIN(iPage, cPages);
2020 for (iPage = 0; iPage < cPages; iPage++)
2021 paPages[iPage] = RTR0MemObjGetPagePhysAddr(pBundle->aMem[i].MemObj, iPage);
2022 RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
2023 return VINF_SUCCESS;
2024 }
2025 }
2026 }
2027 }
2028 RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
2029 return VERR_INVALID_PARAMETER;
2030}
2031#endif /* RT_OS_WINDOWS */
2032
2033
2034/**
2035 * Free memory allocated by SUPR0PageAlloc().
2036 *
2037 * @returns IPRT status code.
2038 * @param pSession The session owning the allocation.
2039 * @param pvR3 The Ring-3 address returned by SUPR0PageAlloc().
2040 */
2041SUPR0DECL(int) SUPR0PageFree(PSUPDRVSESSION pSession, RTR3PTR pvR3)
2042{
2043 LogFlow(("SUPR0PageFree: pSession=%p pvR3=%p\n", pSession, (void *)pvR3));
2044 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
2045 return supdrvMemRelease(pSession, (RTHCUINTPTR)pvR3, MEMREF_TYPE_LOCKED_SUP);
2046}
2047
2048
2049/**
2050 * Maps the GIP into userspace and/or get the physical address of the GIP.
2051 *
2052 * @returns IPRT status code.
2053 * @param pSession Session to which the GIP mapping should belong.
2054 * @param ppGipR3 Where to store the address of the ring-3 mapping. (optional)
2055 * @param pHCPhysGip Where to store the physical address. (optional)
2056 *
2057 * @remark There is no reference counting on the mapping, so one call to this function
2058 * count globally as one reference. One call to SUPR0GipUnmap() is will unmap GIP
2059 * and remove the session as a GIP user.
2060 */
2061SUPR0DECL(int) SUPR0GipMap(PSUPDRVSESSION pSession, PRTR3PTR ppGipR3, PRTHCPHYS pHCPhysGip)
2062{
2063 int rc = 0;
2064 PSUPDRVDEVEXT pDevExt = pSession->pDevExt;
2065 RTR3PTR pGip = NIL_RTR3PTR;
2066 RTHCPHYS HCPhys = NIL_RTHCPHYS;
2067 LogFlow(("SUPR0GipMap: pSession=%p ppGipR3=%p pHCPhysGip=%p\n", pSession, ppGipR3, pHCPhysGip));
2068
2069 /*
2070 * Validate
2071 */
2072 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
2073 AssertPtrNullReturn(ppGipR3, VERR_INVALID_POINTER);
2074 AssertPtrNullReturn(pHCPhysGip, VERR_INVALID_POINTER);
2075
2076 RTSemFastMutexRequest(pDevExt->mtxGip);
2077 if (pDevExt->pGip)
2078 {
2079 /*
2080 * Map it?
2081 */
2082 if (ppGipR3)
2083 {
2084#ifdef USE_NEW_OS_INTERFACE_FOR_GIP
2085 if (pSession->GipMapObjR3 == NIL_RTR0MEMOBJ)
2086 rc = RTR0MemObjMapUser(&pSession->GipMapObjR3, pDevExt->GipMemObj, (RTR3PTR)-1, 0,
2087 RTMEM_PROT_READ, RTR0ProcHandleSelf());
2088 if (RT_SUCCESS(rc))
2089 {
2090 pGip = RTR0MemObjAddressR3(pSession->GipMapObjR3);
2091 rc = VINF_SUCCESS; /** @todo remove this and replace the !rc below with RT_SUCCESS(rc). */
2092 }
2093#else /* !USE_NEW_OS_INTERFACE_FOR_GIP */
2094 if (!pSession->pGip)
2095 rc = supdrvOSGipMap(pSession->pDevExt, &pSession->pGip);
2096 if (!rc)
2097 pGip = (RTR3PTR)pSession->pGip;
2098#endif /* !USE_NEW_OS_INTERFACE_FOR_GIP */
2099 }
2100
2101 /*
2102 * Get physical address.
2103 */
2104 if (pHCPhysGip && !rc)
2105 HCPhys = pDevExt->HCPhysGip;
2106
2107 /*
2108 * Reference globally.
2109 */
2110 if (!pSession->fGipReferenced && !rc)
2111 {
2112 pSession->fGipReferenced = 1;
2113 pDevExt->cGipUsers++;
2114 if (pDevExt->cGipUsers == 1)
2115 {
2116 PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
2117 unsigned i;
2118
2119 LogFlow(("SUPR0GipMap: Resumes GIP updating\n"));
2120
2121 for (i = 0; i < RT_ELEMENTS(pGip->aCPUs); i++)
2122 ASMAtomicXchgU32(&pGip->aCPUs[i].u32TransactionId, pGip->aCPUs[i].u32TransactionId & ~(GIP_UPDATEHZ_RECALC_FREQ * 2 - 1));
2123 ASMAtomicXchgU64(&pGip->u64NanoTSLastUpdateHz, 0);
2124
2125#ifdef USE_NEW_OS_INTERFACE_FOR_GIP
2126 rc = RTTimerStart(pDevExt->pGipTimer, 0);
2127 AssertRC(rc); rc = VINF_SUCCESS;
2128#else
2129 supdrvOSGipResume(pDevExt);
2130#endif
2131 }
2132 }
2133 }
2134 else
2135 {
2136 rc = SUPDRV_ERR_GENERAL_FAILURE;
2137 Log(("SUPR0GipMap: GIP is not available!\n"));
2138 }
2139 RTSemFastMutexRelease(pDevExt->mtxGip);
2140
2141 /*
2142 * Write returns.
2143 */
2144 if (pHCPhysGip)
2145 *pHCPhysGip = HCPhys;
2146 if (ppGipR3)
2147 *ppGipR3 = pGip;
2148
2149#ifdef DEBUG_DARWIN_GIP
2150 OSDBGPRINT(("SUPR0GipMap: returns %d *pHCPhysGip=%lx *ppGip=%p GipMapObjR3\n", rc, (unsigned long)HCPhys, pGip, pSession->GipMapObjR3));
2151#else
2152 LogFlow(("SUPR0GipMap: returns %d *pHCPhysGip=%lx *ppGipR3=%p\n", rc, (unsigned long)HCPhys, (void *)(uintptr_t)pGip));
2153#endif
2154 return rc;
2155}
2156
2157
2158/**
2159 * Unmaps any user mapping of the GIP and terminates all GIP access
2160 * from this session.
2161 *
2162 * @returns IPRT status code.
2163 * @param pSession Session to which the GIP mapping should belong.
2164 */
2165SUPR0DECL(int) SUPR0GipUnmap(PSUPDRVSESSION pSession)
2166{
2167 int rc = VINF_SUCCESS;
2168 PSUPDRVDEVEXT pDevExt = pSession->pDevExt;
2169#ifdef DEBUG_DARWIN_GIP
2170 OSDBGPRINT(("SUPR0GipUnmap: pSession=%p pGip=%p GipMapObjR3=%p\n",
2171 pSession,
2172 pSession->GipMapObjR3 != NIL_RTR0MEMOBJ ? RTR0MemObjAddress(pSession->GipMapObjR3) : NULL,
2173 pSession->GipMapObjR3));
2174#else
2175 LogFlow(("SUPR0GipUnmap: pSession=%p\n", pSession));
2176#endif
2177 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
2178
2179 RTSemFastMutexRequest(pDevExt->mtxGip);
2180
2181 /*
2182 * Unmap anything?
2183 */
2184#ifdef USE_NEW_OS_INTERFACE_FOR_GIP
2185 if (pSession->GipMapObjR3 != NIL_RTR0MEMOBJ)
2186 {
2187 rc = RTR0MemObjFree(pSession->GipMapObjR3, false);
2188 AssertRC(rc);
2189 if (RT_SUCCESS(rc))
2190 pSession->GipMapObjR3 = NIL_RTR0MEMOBJ;
2191 }
2192#else
2193 if (pSession->pGip)
2194 {
2195 rc = supdrvOSGipUnmap(pDevExt, pSession->pGip);
2196 if (!rc)
2197 pSession->pGip = NULL;
2198 }
2199#endif
2200
2201 /*
2202 * Dereference global GIP.
2203 */
2204 if (pSession->fGipReferenced && !rc)
2205 {
2206 pSession->fGipReferenced = 0;
2207 if ( pDevExt->cGipUsers > 0
2208 && !--pDevExt->cGipUsers)
2209 {
2210 LogFlow(("SUPR0GipUnmap: Suspends GIP updating\n"));
2211#ifdef USE_NEW_OS_INTERFACE_FOR_GIP
2212 rc = RTTimerStop(pDevExt->pGipTimer); AssertRC(rc); rc = 0;
2213#else
2214 supdrvOSGipSuspend(pDevExt);
2215#endif
2216 }
2217 }
2218
2219 RTSemFastMutexRelease(pDevExt->mtxGip);
2220
2221 return rc;
2222}
2223
2224
2225/**
2226 * Adds a memory object to the session.
2227 *
2228 * @returns IPRT status code.
2229 * @param pMem Memory tracking structure containing the
2230 * information to track.
2231 * @param pSession The session.
2232 */
2233static int supdrvMemAdd(PSUPDRVMEMREF pMem, PSUPDRVSESSION pSession)
2234{
2235 PSUPDRVBUNDLE pBundle;
2236 RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
2237
2238 /*
2239 * Find free entry and record the allocation.
2240 */
2241 RTSpinlockAcquire(pSession->Spinlock, &SpinlockTmp);
2242 for (pBundle = &pSession->Bundle; pBundle; pBundle = pBundle->pNext)
2243 {
2244 if (pBundle->cUsed < RT_ELEMENTS(pBundle->aMem))
2245 {
2246 unsigned i;
2247 for (i = 0; i < RT_ELEMENTS(pBundle->aMem); i++)
2248 {
2249 if (pBundle->aMem[i].MemObj == NIL_RTR0MEMOBJ)
2250 {
2251 pBundle->cUsed++;
2252 pBundle->aMem[i] = *pMem;
2253 RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
2254 return VINF_SUCCESS;
2255 }
2256 }
2257 AssertFailed(); /* !!this can't be happening!!! */
2258 }
2259 }
2260 RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
2261
2262 /*
2263 * Need to allocate a new bundle.
2264 * Insert into the last entry in the bundle.
2265 */
2266 pBundle = (PSUPDRVBUNDLE)RTMemAllocZ(sizeof(*pBundle));
2267 if (!pBundle)
2268 return VERR_NO_MEMORY;
2269
2270 /* take last entry. */
2271 pBundle->cUsed++;
2272 pBundle->aMem[RT_ELEMENTS(pBundle->aMem) - 1] = *pMem;
2273
2274 /* insert into list. */
2275 RTSpinlockAcquire(pSession->Spinlock, &SpinlockTmp);
2276 pBundle->pNext = pSession->Bundle.pNext;
2277 pSession->Bundle.pNext = pBundle;
2278 RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
2279
2280 return VINF_SUCCESS;
2281}
2282
2283
2284/**
2285 * Releases a memory object referenced by pointer and type.
2286 *
2287 * @returns IPRT status code.
2288 * @param pSession Session data.
2289 * @param uPtr Pointer to memory. This is matched against both the R0 and R3 addresses.
2290 * @param eType Memory type.
2291 */
2292static int supdrvMemRelease(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr, SUPDRVMEMREFTYPE eType)
2293{
2294 PSUPDRVBUNDLE pBundle;
2295 RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
2296
2297 /*
2298 * Validate input.
2299 */
2300 if (!uPtr)
2301 {
2302 Log(("Illegal address %p\n", (void *)uPtr));
2303 return VERR_INVALID_PARAMETER;
2304 }
2305
2306 /*
2307 * Search for the address.
2308 */
2309 RTSpinlockAcquire(pSession->Spinlock, &SpinlockTmp);
2310 for (pBundle = &pSession->Bundle; pBundle; pBundle = pBundle->pNext)
2311 {
2312 if (pBundle->cUsed > 0)
2313 {
2314 unsigned i;
2315 for (i = 0; i < RT_ELEMENTS(pBundle->aMem); i++)
2316 {
2317 if ( pBundle->aMem[i].eType == eType
2318 && pBundle->aMem[i].MemObj != NIL_RTR0MEMOBJ
2319 && ( (RTHCUINTPTR)RTR0MemObjAddress(pBundle->aMem[i].MemObj) == uPtr
2320 || ( pBundle->aMem[i].MapObjR3 != NIL_RTR0MEMOBJ
2321 && RTR0MemObjAddressR3(pBundle->aMem[i].MapObjR3) == uPtr))
2322 )
2323 {
2324 /* Make a copy of it and release it outside the spinlock. */
2325 SUPDRVMEMREF Mem = pBundle->aMem[i];
2326 pBundle->aMem[i].eType = MEMREF_TYPE_UNUSED;
2327 pBundle->aMem[i].MemObj = NIL_RTR0MEMOBJ;
2328 pBundle->aMem[i].MapObjR3 = NIL_RTR0MEMOBJ;
2329 RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
2330
2331 if (Mem.MapObjR3)
2332 {
2333 int rc = RTR0MemObjFree(Mem.MapObjR3, false);
2334 AssertRC(rc); /** @todo figure out how to handle this. */
2335 }
2336 if (Mem.MemObj)
2337 {
2338 int rc = RTR0MemObjFree(Mem.MemObj, false);
2339 AssertRC(rc); /** @todo figure out how to handle this. */
2340 }
2341 return VINF_SUCCESS;
2342 }
2343 }
2344 }
2345 }
2346 RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
2347 Log(("Failed to find %p!!! (eType=%d)\n", (void *)uPtr, eType));
2348 return VERR_INVALID_PARAMETER;
2349}
2350
2351
2352#ifdef VBOX_WITH_IDT_PATCHING
2353/**
2354 * Install IDT for the current CPU.
2355 *
2356 * @returns One of the following IPRT status codes:
2357 * @retval VINF_SUCCESS on success.
2358 * @retval VERR_IDT_FAILED.
2359 * @retval VERR_NO_MEMORY.
2360 * @param pDevExt The device extension.
2361 * @param pSession The session data.
2362 * @param pReq The request.
2363 */
2364static int supdrvIOCtl_IdtInstall(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPIDTINSTALL pReq)
2365{
2366 PSUPDRVPATCHUSAGE pUsagePre;
2367 PSUPDRVPATCH pPatchPre;
2368 RTIDTR Idtr;
2369 PSUPDRVPATCH pPatch;
2370 RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
2371 LogFlow(("supdrvIOCtl_IdtInstall\n"));
2372
2373 /*
2374 * Preallocate entry for this CPU cause we don't wanna do
2375 * that inside the spinlock!
2376 */
2377 pUsagePre = (PSUPDRVPATCHUSAGE)RTMemAlloc(sizeof(*pUsagePre));
2378 if (!pUsagePre)
2379 return VERR_NO_MEMORY;
2380
2381 /*
2382 * Take the spinlock and see what we need to do.
2383 */
2384 RTSpinlockAcquireNoInts(pDevExt->Spinlock, &SpinlockTmp);
2385
2386 /* check if we already got a free patch. */
2387 if (!pDevExt->pIdtPatchesFree)
2388 {
2389 /*
2390 * Allocate a patch - outside the spinlock of course.
2391 */
2392 RTSpinlockReleaseNoInts(pDevExt->Spinlock, &SpinlockTmp);
2393
2394 pPatchPre = (PSUPDRVPATCH)RTMemExecAlloc(sizeof(*pPatchPre));
2395 if (!pPatchPre)
2396 return VERR_NO_MEMORY;
2397
2398 RTSpinlockAcquireNoInts(pDevExt->Spinlock, &SpinlockTmp);
2399 }
2400 else
2401 {
2402 pPatchPre = pDevExt->pIdtPatchesFree;
2403 pDevExt->pIdtPatchesFree = pPatchPre->pNext;
2404 }
2405
2406 /* look for matching patch entry */
2407 ASMGetIDTR(&Idtr);
2408 pPatch = pDevExt->pIdtPatches;
2409 while (pPatch && pPatch->pvIdt != (void *)Idtr.pIdt)
2410 pPatch = pPatch->pNext;
2411
2412 if (!pPatch)
2413 {
2414 /*
2415 * Create patch.
2416 */
2417 pPatch = supdrvIdtPatchOne(pDevExt, pPatchPre);
2418 if (pPatch)
2419 pPatchPre = NULL; /* mark as used. */
2420 }
2421 else
2422 {
2423 /*
2424 * Simply increment patch usage.
2425 */
2426 pPatch->cUsage++;
2427 }
2428
2429 if (pPatch)
2430 {
2431 /*
2432 * Increment and add if need be the session usage record for this patch.
2433 */
2434 PSUPDRVPATCHUSAGE pUsage = pSession->pPatchUsage;
2435 while (pUsage && pUsage->pPatch != pPatch)
2436 pUsage = pUsage->pNext;
2437
2438 if (!pUsage)
2439 {
2440 /*
2441 * Add usage record.
2442 */
2443 pUsagePre->cUsage = 1;
2444 pUsagePre->pPatch = pPatch;
2445 pUsagePre->pNext = pSession->pPatchUsage;
2446 pSession->pPatchUsage = pUsagePre;
2447 pUsagePre = NULL; /* mark as used. */
2448 }
2449 else
2450 {
2451 /*
2452 * Increment usage count.
2453 */
2454 pUsage->cUsage++;
2455 }
2456 }
2457
2458 /* free patch - we accumulate them for paranoid saftly reasons. */
2459 if (pPatchPre)
2460 {
2461 pPatchPre->pNext = pDevExt->pIdtPatchesFree;
2462 pDevExt->pIdtPatchesFree = pPatchPre;
2463 }
2464
2465 RTSpinlockReleaseNoInts(pDevExt->Spinlock, &SpinlockTmp);
2466
2467 /*
2468 * Free unused preallocated buffers.
2469 */
2470 if (pUsagePre)
2471 RTMemFree(pUsagePre);
2472
2473 pReq->u.Out.u8Idt = pDevExt->u8Idt;
2474
2475 return pPatch ? VINF_SUCCESS : VERR_IDT_FAILED;
2476}
2477
2478
2479/**
2480 * This creates a IDT patch entry.
2481 * If the first patch being installed it'll also determin the IDT entry
2482 * to use.
2483 *
2484 * @returns pPatch on success.
2485 * @returns NULL on failure.
2486 * @param pDevExt Pointer to globals.
2487 * @param pPatch Patch entry to use.
2488 * This will be linked into SUPDRVDEVEXT::pIdtPatches on
2489 * successful return.
2490 * @remark Call must be owning the SUPDRVDEVEXT::Spinlock!
2491 */
2492static PSUPDRVPATCH supdrvIdtPatchOne(PSUPDRVDEVEXT pDevExt, PSUPDRVPATCH pPatch)
2493{
2494 RTIDTR Idtr;
2495 PSUPDRVIDTE paIdt;
2496 LogFlow(("supdrvIOCtl_IdtPatchOne: pPatch=%p\n", pPatch));
2497
2498 /*
2499 * Get IDT.
2500 */
2501 ASMGetIDTR(&Idtr);
2502 paIdt = (PSUPDRVIDTE)Idtr.pIdt;
2503 /*
2504 * Recent Linux kernels can be configured to 1G user /3G kernel.
2505 */
2506 if ((uintptr_t)paIdt < 0x40000000)
2507 {
2508 AssertMsgFailed(("bad paIdt=%p\n", paIdt));
2509 return NULL;
2510 }
2511
2512 if (!pDevExt->u8Idt)
2513 {
2514 /*
2515 * Test out the alternatives.
2516 *
2517 * At the moment we do not support chaining thus we ASSUME that one of
2518 * these 48 entries is unused (which is not a problem on Win32 and
2519 * Linux to my knowledge).
2520 */
2521 /** @todo we MUST change this detection to try grab an entry which is NOT in use. This can be
2522 * combined with gathering info about which guest system call gates we can hook up directly. */
2523 unsigned i;
2524 uint8_t u8Idt = 0;
2525 static uint8_t au8Ints[] =
2526 {
2527#ifdef RT_OS_WINDOWS /* We don't use 0xef and above because they are system stuff on linux (ef is IPI,
2528 * local apic timer, or some other frequently fireing thing). */
2529 0xef, 0xee, 0xed, 0xec,
2530#endif
2531 0xeb, 0xea, 0xe9, 0xe8,
2532 0xdf, 0xde, 0xdd, 0xdc,
2533 0x7b, 0x7a, 0x79, 0x78,
2534 0xbf, 0xbe, 0xbd, 0xbc,
2535 };
2536#if defined(RT_ARCH_AMD64) && defined(DEBUG)
2537 static int s_iWobble = 0;
2538 unsigned iMax = !(s_iWobble++ % 2) ? 0x80 : 0x100;
2539 Log2(("IDT: Idtr=%p:%#x\n", (void *)Idtr.pIdt, (unsigned)Idtr.cbIdt));
2540 for (i = iMax - 0x80; i*16+15 < Idtr.cbIdt && i < iMax; i++)
2541 {
2542 Log2(("%#x: %04x:%08x%04x%04x P=%d DPL=%d IST=%d Type1=%#x u32Reserved=%#x u5Reserved=%#x\n",
2543 i, paIdt[i].u16SegSel, paIdt[i].u32OffsetTop, paIdt[i].u16OffsetHigh, paIdt[i].u16OffsetLow,
2544 paIdt[i].u1Present, paIdt[i].u2DPL, paIdt[i].u3IST, paIdt[i].u5Type2,
2545 paIdt[i].u32Reserved, paIdt[i].u5Reserved));
2546 }
2547#endif
2548 /* look for entries which are not present or otherwise unused. */
2549 for (i = 0; i < sizeof(au8Ints) / sizeof(au8Ints[0]); i++)
2550 {
2551 u8Idt = au8Ints[i];
2552 if ( u8Idt * sizeof(SUPDRVIDTE) < Idtr.cbIdt
2553 && ( !paIdt[u8Idt].u1Present
2554 || paIdt[u8Idt].u5Type2 == 0))
2555 break;
2556 u8Idt = 0;
2557 }
2558 if (!u8Idt)
2559 {
2560 /* try again, look for a compatible entry .*/
2561 for (i = 0; i < sizeof(au8Ints) / sizeof(au8Ints[0]); i++)
2562 {
2563 u8Idt = au8Ints[i];
2564 if ( u8Idt * sizeof(SUPDRVIDTE) < Idtr.cbIdt
2565 && paIdt[u8Idt].u1Present
2566 && paIdt[u8Idt].u5Type2 == SUPDRV_IDTE_TYPE2_INTERRUPT_GATE
2567 && !(paIdt[u8Idt].u16SegSel & 3))
2568 break;
2569 u8Idt = 0;
2570 }
2571 if (!u8Idt)
2572 {
2573 Log(("Failed to find appropirate IDT entry!!\n"));
2574 return NULL;
2575 }
2576 }
2577 pDevExt->u8Idt = u8Idt;
2578 LogFlow(("supdrvIOCtl_IdtPatchOne: u8Idt=%x\n", u8Idt));
2579 }
2580
2581 /*
2582 * Prepare the patch
2583 */
2584 memset(pPatch, 0, sizeof(*pPatch));
2585 pPatch->pvIdt = paIdt;
2586 pPatch->cUsage = 1;
2587 pPatch->pIdtEntry = &paIdt[pDevExt->u8Idt];
2588 pPatch->SavedIdt = paIdt[pDevExt->u8Idt];
2589 pPatch->ChangedIdt.u16OffsetLow = (uint32_t)((uintptr_t)&pPatch->auCode[0] & 0xffff);
2590 pPatch->ChangedIdt.u16OffsetHigh = (uint32_t)((uintptr_t)&pPatch->auCode[0] >> 16);
2591#ifdef RT_ARCH_AMD64
2592 pPatch->ChangedIdt.u32OffsetTop = (uint32_t)((uintptr_t)&pPatch->auCode[0] >> 32);
2593#endif
2594 pPatch->ChangedIdt.u16SegSel = ASMGetCS();
2595#ifdef RT_ARCH_AMD64
2596 pPatch->ChangedIdt.u3IST = 0;
2597 pPatch->ChangedIdt.u5Reserved = 0;
2598#else /* x86 */
2599 pPatch->ChangedIdt.u5Reserved = 0;
2600 pPatch->ChangedIdt.u3Type1 = 0;
2601#endif /* x86 */
2602 pPatch->ChangedIdt.u5Type2 = SUPDRV_IDTE_TYPE2_INTERRUPT_GATE;
2603 pPatch->ChangedIdt.u2DPL = 3;
2604 pPatch->ChangedIdt.u1Present = 1;
2605
2606 /*
2607 * Generate the patch code.
2608 */
2609 {
2610#ifdef RT_ARCH_AMD64
2611 union
2612 {
2613 uint8_t *pb;
2614 uint32_t *pu32;
2615 uint64_t *pu64;
2616 } u, uFixJmp, uFixCall, uNotNested;
2617 u.pb = &pPatch->auCode[0];
2618
2619 /* check the cookie */
2620 *u.pb++ = 0x3d; // cmp eax, GLOBALCOOKIE
2621 *u.pu32++ = pDevExt->u32Cookie;
2622
2623 *u.pb++ = 0x74; // jz @VBoxCall
2624 *u.pb++ = 2;
2625
2626 /* jump to forwarder code. */
2627 *u.pb++ = 0xeb;
2628 uFixJmp = u;
2629 *u.pb++ = 0xfe;
2630
2631 // @VBoxCall:
2632 *u.pb++ = 0x0f; // swapgs
2633 *u.pb++ = 0x01;
2634 *u.pb++ = 0xf8;
2635
2636 /*
2637 * Call VMMR0Entry
2638 * We don't have to push the arguments here, but we have top
2639 * reserve some stack space for the interrupt forwarding.
2640 */
2641# ifdef RT_OS_WINDOWS
2642 *u.pb++ = 0x50; // push rax ; alignment filler.
2643 *u.pb++ = 0x41; // push r8 ; uArg
2644 *u.pb++ = 0x50;
2645 *u.pb++ = 0x52; // push rdx ; uOperation
2646 *u.pb++ = 0x51; // push rcx ; pVM
2647# else
2648 *u.pb++ = 0x51; // push rcx ; alignment filler.
2649 *u.pb++ = 0x52; // push rdx ; uArg
2650 *u.pb++ = 0x56; // push rsi ; uOperation
2651 *u.pb++ = 0x57; // push rdi ; pVM
2652# endif
2653
2654 *u.pb++ = 0xff; // call qword [pfnVMMR0EntryInt wrt rip]
2655 *u.pb++ = 0x15;
2656 uFixCall = u;
2657 *u.pu32++ = 0;
2658
2659 *u.pb++ = 0x48; // add rsp, 20h ; remove call frame.
2660 *u.pb++ = 0x81;
2661 *u.pb++ = 0xc4;
2662 *u.pu32++ = 0x20;
2663
2664 *u.pb++ = 0x0f; // swapgs
2665 *u.pb++ = 0x01;
2666 *u.pb++ = 0xf8;
2667
2668 /* Return to R3. */
2669 uNotNested = u;
2670 *u.pb++ = 0x48; // iretq
2671 *u.pb++ = 0xcf;
2672
2673 while ((uintptr_t)u.pb & 0x7) // align 8
2674 *u.pb++ = 0xcc;
2675
2676 /* Pointer to the VMMR0Entry. */ // pfnVMMR0EntryInt dq StubVMMR0Entry
2677 *uFixCall.pu32 = (uint32_t)(u.pb - uFixCall.pb - 4); uFixCall.pb = NULL;
2678 pPatch->offVMMR0EntryFixup = (uint16_t)(u.pb - &pPatch->auCode[0]);
2679 *u.pu64++ = pDevExt->pvVMMR0 ? (uint64_t)pDevExt->pfnVMMR0EntryInt : (uint64_t)u.pb + 8;
2680
2681 /* stub entry. */ // StubVMMR0Entry:
2682 pPatch->offStub = (uint16_t)(u.pb - &pPatch->auCode[0]);
2683 *u.pb++ = 0x33; // xor eax, eax
2684 *u.pb++ = 0xc0;
2685
2686 *u.pb++ = 0x48; // dec rax
2687 *u.pb++ = 0xff;
2688 *u.pb++ = 0xc8;
2689
2690 *u.pb++ = 0xc3; // ret
2691
2692 /* forward to the original handler using a retf. */
2693 *uFixJmp.pb = (uint8_t)(u.pb - uFixJmp.pb - 1); uFixJmp.pb = NULL;
2694
2695 *u.pb++ = 0x68; // push <target cs>
2696 *u.pu32++ = !pPatch->SavedIdt.u5Type2 ? ASMGetCS() : pPatch->SavedIdt.u16SegSel;
2697
2698 *u.pb++ = 0x68; // push <low target rip>
2699 *u.pu32++ = !pPatch->SavedIdt.u5Type2
2700 ? (uint32_t)(uintptr_t)uNotNested.pb
2701 : (uint32_t)pPatch->SavedIdt.u16OffsetLow
2702 | (uint32_t)pPatch->SavedIdt.u16OffsetHigh << 16;
2703
2704 *u.pb++ = 0xc7; // mov dword [rsp + 4], <high target rip>
2705 *u.pb++ = 0x44;
2706 *u.pb++ = 0x24;
2707 *u.pb++ = 0x04;
2708 *u.pu32++ = !pPatch->SavedIdt.u5Type2
2709 ? (uint32_t)((uint64_t)uNotNested.pb >> 32)
2710 : pPatch->SavedIdt.u32OffsetTop;
2711
2712 *u.pb++ = 0x48; // retf ; does this require prefix?
2713 *u.pb++ = 0xcb;
2714
2715#else /* RT_ARCH_X86 */
2716
2717 union
2718 {
2719 uint8_t *pb;
2720 uint16_t *pu16;
2721 uint32_t *pu32;
2722 } u, uFixJmpNotNested, uFixJmp, uFixCall, uNotNested;
2723 u.pb = &pPatch->auCode[0];
2724
2725 /* check the cookie */
2726 *u.pb++ = 0x81; // cmp esi, GLOBALCOOKIE
2727 *u.pb++ = 0xfe;
2728 *u.pu32++ = pDevExt->u32Cookie;
2729
2730 *u.pb++ = 0x74; // jz VBoxCall
2731 uFixJmp = u;
2732 *u.pb++ = 0;
2733
2734 /* jump (far) to the original handler / not-nested-stub. */
2735 *u.pb++ = 0xea; // jmp far NotNested
2736 uFixJmpNotNested = u;
2737 *u.pu32++ = 0;
2738 *u.pu16++ = 0;
2739
2740 /* save selector registers. */ // VBoxCall:
2741 *uFixJmp.pb = (uint8_t)(u.pb - uFixJmp.pb - 1);
2742 *u.pb++ = 0x0f; // push fs
2743 *u.pb++ = 0xa0;
2744
2745 *u.pb++ = 0x1e; // push ds
2746
2747 *u.pb++ = 0x06; // push es
2748
2749 /* call frame */
2750 *u.pb++ = 0x51; // push ecx
2751
2752 *u.pb++ = 0x52; // push edx
2753
2754 *u.pb++ = 0x50; // push eax
2755
2756 /* load ds, es and perhaps fs before call. */
2757 *u.pb++ = 0xb8; // mov eax, KernelDS
2758 *u.pu32++ = ASMGetDS();
2759
2760 *u.pb++ = 0x8e; // mov ds, eax
2761 *u.pb++ = 0xd8;
2762
2763 *u.pb++ = 0x8e; // mov es, eax
2764 *u.pb++ = 0xc0;
2765
2766#ifdef RT_OS_WINDOWS
2767 *u.pb++ = 0xb8; // mov eax, KernelFS
2768 *u.pu32++ = ASMGetFS();
2769
2770 *u.pb++ = 0x8e; // mov fs, eax
2771 *u.pb++ = 0xe0;
2772#endif
2773
2774 /* do the call. */
2775 *u.pb++ = 0xe8; // call _VMMR0Entry / StubVMMR0Entry
2776 uFixCall = u;
2777 pPatch->offVMMR0EntryFixup = (uint16_t)(u.pb - &pPatch->auCode[0]);
2778 *u.pu32++ = 0xfffffffb;
2779
2780 *u.pb++ = 0x83; // add esp, 0ch ; cdecl
2781 *u.pb++ = 0xc4;
2782 *u.pb++ = 0x0c;
2783
2784 /* restore selector registers. */
2785 *u.pb++ = 0x07; // pop es
2786 //
2787 *u.pb++ = 0x1f; // pop ds
2788
2789 *u.pb++ = 0x0f; // pop fs
2790 *u.pb++ = 0xa1;
2791
2792 uNotNested = u; // NotNested:
2793 *u.pb++ = 0xcf; // iretd
2794
2795 /* the stub VMMR0Entry. */ // StubVMMR0Entry:
2796 pPatch->offStub = (uint16_t)(u.pb - &pPatch->auCode[0]);
2797 *u.pb++ = 0x33; // xor eax, eax
2798 *u.pb++ = 0xc0;
2799
2800 *u.pb++ = 0x48; // dec eax
2801
2802 *u.pb++ = 0xc3; // ret
2803
2804 /* Fixup the VMMR0Entry call. */
2805 if (pDevExt->pvVMMR0)
2806 *uFixCall.pu32 = (uint32_t)pDevExt->pfnVMMR0EntryInt - (uint32_t)(uFixCall.pu32 + 1);
2807 else
2808 *uFixCall.pu32 = (uint32_t)&pPatch->auCode[pPatch->offStub] - (uint32_t)(uFixCall.pu32 + 1);
2809
2810 /* Fixup the forward / nested far jump. */
2811 if (!pPatch->SavedIdt.u5Type2)
2812 {
2813 *uFixJmpNotNested.pu32++ = (uint32_t)uNotNested.pb;
2814 *uFixJmpNotNested.pu16++ = ASMGetCS();
2815 }
2816 else
2817 {
2818 *uFixJmpNotNested.pu32++ = ((uint32_t)pPatch->SavedIdt.u16OffsetHigh << 16) | pPatch->SavedIdt.u16OffsetLow;
2819 *uFixJmpNotNested.pu16++ = pPatch->SavedIdt.u16SegSel;
2820 }
2821#endif /* RT_ARCH_X86 */
2822 Assert(u.pb <= &pPatch->auCode[sizeof(pPatch->auCode)]);
2823#if 0
2824 /* dump the patch code */
2825 Log2(("patch code: %p\n", &pPatch->auCode[0]));
2826 for (uFixCall.pb = &pPatch->auCode[0]; uFixCall.pb < u.pb; uFixCall.pb++)
2827 Log2(("0x%02x,\n", *uFixCall.pb));
2828#endif
2829 }
2830
2831 /*
2832 * Install the patch.
2833 */
2834 supdrvIdtWrite(pPatch->pIdtEntry, &pPatch->ChangedIdt);
2835 AssertMsg(!memcmp((void *)pPatch->pIdtEntry, &pPatch->ChangedIdt, sizeof(pPatch->ChangedIdt)), ("The stupid change code didn't work!!!!!\n"));
2836
2837 /*
2838 * Link in the patch.
2839 */
2840 pPatch->pNext = pDevExt->pIdtPatches;
2841 pDevExt->pIdtPatches = pPatch;
2842
2843 return pPatch;
2844}
2845
2846
2847/**
2848 * Removes the sessions IDT references.
2849 * This will uninstall our IDT patch if we left unreferenced.
2850 *
2851 * @returns VINF_SUCCESS.
2852 * @param pDevExt Device globals.
2853 * @param pSession Session data.
2854 */
2855static int supdrvIOCtl_IdtRemoveAll(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
2856{
2857 PSUPDRVPATCHUSAGE pUsage;
2858 RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
2859 LogFlow(("supdrvIOCtl_IdtRemoveAll: pSession=%p\n", pSession));
2860
2861 /*
2862 * Take the spinlock.
2863 */
2864 RTSpinlockAcquireNoInts(pDevExt->Spinlock, &SpinlockTmp);
2865
2866 /*
2867 * Walk usage list, removing patches as their usage count reaches zero.
2868 */
2869 pUsage = pSession->pPatchUsage;
2870 while (pUsage)
2871 {
2872 if (pUsage->pPatch->cUsage <= pUsage->cUsage)
2873 supdrvIdtRemoveOne(pDevExt, pUsage->pPatch);
2874 else
2875 pUsage->pPatch->cUsage -= pUsage->cUsage;
2876
2877 /* next */
2878 pUsage = pUsage->pNext;
2879 }
2880
2881 /*
2882 * Empty the usage chain and we're done inside the spinlock.
2883 */
2884 pUsage = pSession->pPatchUsage;
2885 pSession->pPatchUsage = NULL;
2886
2887 RTSpinlockReleaseNoInts(pDevExt->Spinlock, &SpinlockTmp);
2888
2889 /*
2890 * Free usage entries.
2891 */
2892 while (pUsage)
2893 {
2894 void *pvToFree = pUsage;
2895 pUsage->cUsage = 0;
2896 pUsage->pPatch = NULL;
2897 pUsage = pUsage->pNext;
2898 RTMemFree(pvToFree);
2899 }
2900
2901 return VINF_SUCCESS;
2902}
2903
2904
2905/**
2906 * Remove one patch.
2907 *
2908 * Worker for supdrvIOCtl_IdtRemoveAll.
2909 *
2910 * @param pDevExt Device globals.
2911 * @param pPatch Patch entry to remove.
2912 * @remark Caller must own SUPDRVDEVEXT::Spinlock!
2913 */
2914static void supdrvIdtRemoveOne(PSUPDRVDEVEXT pDevExt, PSUPDRVPATCH pPatch)
2915{
2916 LogFlow(("supdrvIdtRemoveOne: pPatch=%p\n", pPatch));
2917
2918 pPatch->cUsage = 0;
2919
2920 /*
2921 * If the IDT entry was changed it have to kick around for ever!
2922 * This will be attempted freed again, perhaps next time we'll succeed :-)
2923 */
2924 if (memcmp((void *)pPatch->pIdtEntry, &pPatch->ChangedIdt, sizeof(pPatch->ChangedIdt)))
2925 {
2926 AssertMsgFailed(("The hijacked IDT entry has CHANGED!!!\n"));
2927 return;
2928 }
2929
2930 /*
2931 * Unlink it.
2932 */
2933 if (pDevExt->pIdtPatches != pPatch)
2934 {
2935 PSUPDRVPATCH pPatchPrev = pDevExt->pIdtPatches;
2936 while (pPatchPrev)
2937 {
2938 if (pPatchPrev->pNext == pPatch)
2939 {
2940 pPatchPrev->pNext = pPatch->pNext;
2941 break;
2942 }
2943 pPatchPrev = pPatchPrev->pNext;
2944 }
2945 Assert(!pPatchPrev);
2946 }
2947 else
2948 pDevExt->pIdtPatches = pPatch->pNext;
2949 pPatch->pNext = NULL;
2950
2951
2952 /*
2953 * Verify and restore the IDT.
2954 */
2955 AssertMsg(!memcmp((void *)pPatch->pIdtEntry, &pPatch->ChangedIdt, sizeof(pPatch->ChangedIdt)), ("The hijacked IDT entry has CHANGED!!!\n"));
2956 supdrvIdtWrite(pPatch->pIdtEntry, &pPatch->SavedIdt);
2957 AssertMsg(!memcmp((void *)pPatch->pIdtEntry, &pPatch->SavedIdt, sizeof(pPatch->SavedIdt)), ("The hijacked IDT entry has CHANGED!!!\n"));
2958
2959 /*
2960 * Put it in the free list.
2961 * (This free list stuff is to calm my paranoia.)
2962 */
2963 pPatch->pvIdt = NULL;
2964 pPatch->pIdtEntry = NULL;
2965
2966 pPatch->pNext = pDevExt->pIdtPatchesFree;
2967 pDevExt->pIdtPatchesFree = pPatch;
2968}
2969
2970
2971/**
2972 * Write to an IDT entry.
2973 *
2974 * @param pvIdtEntry Where to write.
2975 * @param pNewIDTEntry What to write.
2976 */
2977static void supdrvIdtWrite(volatile void *pvIdtEntry, const SUPDRVIDTE *pNewIDTEntry)
2978{
2979 RTUINTREG uCR0;
2980 RTUINTREG uFlags;
2981
2982 /*
2983 * On SMP machines (P4 hyperthreading included) we must preform a
2984 * 64-bit locked write when updating the IDT entry.
2985 *
2986 * The F00F bugfix for linux (and probably other OSes) causes
2987 * the IDT to be pointing to an readonly mapping. We get around that
2988 * by temporarily turning of WP. Since we're inside a spinlock at this
2989 * point, interrupts are disabled and there isn't any way the WP bit
2990 * flipping can cause any trouble.
2991 */
2992
2993 /* Save & Clear interrupt flag; Save & clear WP. */
2994 uFlags = ASMGetFlags();
2995 ASMSetFlags(uFlags & ~(RTUINTREG)(1 << 9)); /*X86_EFL_IF*/
2996 Assert(!(ASMGetFlags() & (1 << 9)));
2997 uCR0 = ASMGetCR0();
2998 ASMSetCR0(uCR0 & ~(RTUINTREG)(1 << 16)); /*X86_CR0_WP*/
2999
3000 /* Update IDT Entry */
3001#ifdef RT_ARCH_AMD64
3002 ASMAtomicXchgU128((volatile uint128_t *)pvIdtEntry, *(uint128_t *)(uintptr_t)pNewIDTEntry);
3003#else
3004 ASMAtomicXchgU64((volatile uint64_t *)pvIdtEntry, *(uint64_t *)(uintptr_t)pNewIDTEntry);
3005#endif
3006
3007 /* Restore CR0 & Flags */
3008 ASMSetCR0(uCR0);
3009 ASMSetFlags(uFlags);
3010}
3011#endif /* VBOX_WITH_IDT_PATCHING */
3012
3013
3014/**
3015 * Opens an image. If it's the first time it's opened the call must upload
3016 * the bits using the supdrvIOCtl_LdrLoad() / SUPDRV_IOCTL_LDR_LOAD function.
3017 *
3018 * This is the 1st step of the loading.
3019 *
3020 * @returns IPRT status code.
3021 * @param pDevExt Device globals.
3022 * @param pSession Session data.
3023 * @param pReq The open request.
3024 */
3025static int supdrvIOCtl_LdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDROPEN pReq)
3026{
3027 PSUPDRVLDRIMAGE pImage;
3028 unsigned cb;
3029 void *pv;
3030 LogFlow(("supdrvIOCtl_LdrOpen: szName=%s cbImage=%d\n", pReq->u.In.szName, pReq->u.In.cbImage));
3031
3032 /*
3033 * Check if we got an instance of the image already.
3034 */
3035 RTSemFastMutexRequest(pDevExt->mtxLdr);
3036 for (pImage = pDevExt->pLdrImages; pImage; pImage = pImage->pNext)
3037 {
3038 if (!strcmp(pImage->szName, pReq->u.In.szName))
3039 {
3040 pImage->cUsage++;
3041 pReq->u.Out.pvImageBase = pImage->pvImage;
3042 pReq->u.Out.fNeedsLoading = pImage->uState == SUP_IOCTL_LDR_OPEN;
3043 supdrvLdrAddUsage(pSession, pImage);
3044 RTSemFastMutexRelease(pDevExt->mtxLdr);
3045 return VINF_SUCCESS;
3046 }
3047 }
3048 /* (not found - add it!) */
3049
3050 /*
3051 * Allocate memory.
3052 */
3053 cb = pReq->u.In.cbImage + sizeof(SUPDRVLDRIMAGE) + 31;
3054 pv = RTMemExecAlloc(cb);
3055 if (!pv)
3056 {
3057 RTSemFastMutexRelease(pDevExt->mtxLdr);
3058 Log(("supdrvIOCtl_LdrOpen: RTMemExecAlloc(%u) failed\n", cb));
3059 return VERR_NO_MEMORY;
3060 }
3061
3062 /*
3063 * Setup and link in the LDR stuff.
3064 */
3065 pImage = (PSUPDRVLDRIMAGE)pv;
3066 pImage->pvImage = RT_ALIGN_P(pImage + 1, 32);
3067 pImage->cbImage = pReq->u.In.cbImage;
3068 pImage->pfnModuleInit = NULL;
3069 pImage->pfnModuleTerm = NULL;
3070 pImage->uState = SUP_IOCTL_LDR_OPEN;
3071 pImage->cUsage = 1;
3072 strcpy(pImage->szName, pReq->u.In.szName);
3073
3074 pImage->pNext = pDevExt->pLdrImages;
3075 pDevExt->pLdrImages = pImage;
3076
3077 supdrvLdrAddUsage(pSession, pImage);
3078
3079 pReq->u.Out.pvImageBase = pImage->pvImage;
3080 pReq->u.Out.fNeedsLoading = true;
3081 RTSemFastMutexRelease(pDevExt->mtxLdr);
3082 return VINF_SUCCESS;
3083}
3084
3085
3086/**
3087 * Loads the image bits.
3088 *
3089 * This is the 2nd step of the loading.
3090 *
3091 * @returns IPRT status code.
3092 * @param pDevExt Device globals.
3093 * @param pSession Session data.
3094 * @param pReq The request.
3095 */
3096static int supdrvIOCtl_LdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDRLOAD pReq)
3097{
3098 PSUPDRVLDRUSAGE pUsage;
3099 PSUPDRVLDRIMAGE pImage;
3100 int rc;
3101 LogFlow(("supdrvIOCtl_LdrLoad: pvImageBase=%p cbImage=%d\n", pReq->u.In.pvImageBase, pReq->u.In.cbImage));
3102
3103 /*
3104 * Find the ldr image.
3105 */
3106 RTSemFastMutexRequest(pDevExt->mtxLdr);
3107 pUsage = pSession->pLdrUsage;
3108 while (pUsage && pUsage->pImage->pvImage != pReq->u.In.pvImageBase)
3109 pUsage = pUsage->pNext;
3110 if (!pUsage)
3111 {
3112 RTSemFastMutexRelease(pDevExt->mtxLdr);
3113 Log(("SUP_IOCTL_LDR_LOAD: couldn't find image!\n"));
3114 return VERR_INVALID_HANDLE;
3115 }
3116 pImage = pUsage->pImage;
3117 if (pImage->cbImage != pReq->u.In.cbImage)
3118 {
3119 RTSemFastMutexRelease(pDevExt->mtxLdr);
3120 Log(("SUP_IOCTL_LDR_LOAD: image size mismatch!! %d(prep) != %d(load)\n", pImage->cbImage, pReq->u.In.cbImage));
3121 return VERR_INVALID_HANDLE;
3122 }
3123 if (pImage->uState != SUP_IOCTL_LDR_OPEN)
3124 {
3125 unsigned uState = pImage->uState;
3126 RTSemFastMutexRelease(pDevExt->mtxLdr);
3127 if (uState != SUP_IOCTL_LDR_LOAD)
3128 AssertMsgFailed(("SUP_IOCTL_LDR_LOAD: invalid image state %d (%#x)!\n", uState, uState));
3129 return SUPDRV_ERR_ALREADY_LOADED;
3130 }
3131 switch (pReq->u.In.eEPType)
3132 {
3133 case SUPLDRLOADEP_NOTHING:
3134 break;
3135 case SUPLDRLOADEP_VMMR0:
3136 if ( !pReq->u.In.EP.VMMR0.pvVMMR0
3137 || !pReq->u.In.EP.VMMR0.pvVMMR0EntryInt
3138 || !pReq->u.In.EP.VMMR0.pvVMMR0EntryFast
3139 || !pReq->u.In.EP.VMMR0.pvVMMR0EntryEx)
3140 {
3141 RTSemFastMutexRelease(pDevExt->mtxLdr);
3142 Log(("NULL pointer: pvVMMR0=%p pvVMMR0EntryInt=%p pvVMMR0EntryFast=%p pvVMMR0EntryEx=%p!\n",
3143 pReq->u.In.EP.VMMR0.pvVMMR0, pReq->u.In.EP.VMMR0.pvVMMR0EntryInt,
3144 pReq->u.In.EP.VMMR0.pvVMMR0EntryFast, pReq->u.In.EP.VMMR0.pvVMMR0EntryEx));
3145 return VERR_INVALID_PARAMETER;
3146 }
3147 if ( (uintptr_t)pReq->u.In.EP.VMMR0.pvVMMR0EntryInt - (uintptr_t)pImage->pvImage >= pReq->u.In.cbImage
3148 || (uintptr_t)pReq->u.In.EP.VMMR0.pvVMMR0EntryFast - (uintptr_t)pImage->pvImage >= pReq->u.In.cbImage
3149 || (uintptr_t)pReq->u.In.EP.VMMR0.pvVMMR0EntryEx - (uintptr_t)pImage->pvImage >= pReq->u.In.cbImage)
3150 {
3151 RTSemFastMutexRelease(pDevExt->mtxLdr);
3152 Log(("Out of range (%p LB %#x): pvVMMR0EntryInt=%p, pvVMMR0EntryFast=%p or pvVMMR0EntryEx=%p is NULL!\n",
3153 pImage->pvImage, pReq->u.In.cbImage, pReq->u.In.EP.VMMR0.pvVMMR0EntryInt,
3154 pReq->u.In.EP.VMMR0.pvVMMR0EntryFast, pReq->u.In.EP.VMMR0.pvVMMR0EntryEx));
3155 return VERR_INVALID_PARAMETER;
3156 }
3157 break;
3158 default:
3159 RTSemFastMutexRelease(pDevExt->mtxLdr);
3160 Log(("Invalid eEPType=%d\n", pReq->u.In.eEPType));
3161 return VERR_INVALID_PARAMETER;
3162 }
3163 if ( pReq->u.In.pfnModuleInit
3164 && (uintptr_t)pReq->u.In.pfnModuleInit - (uintptr_t)pImage->pvImage >= pReq->u.In.cbImage)
3165 {
3166 RTSemFastMutexRelease(pDevExt->mtxLdr);
3167 Log(("SUP_IOCTL_LDR_LOAD: pfnModuleInit=%p is outside the image (%p %d bytes)\n",
3168 pReq->u.In.pfnModuleInit, pImage->pvImage, pReq->u.In.cbImage));
3169 return VERR_INVALID_PARAMETER;
3170 }
3171 if ( pReq->u.In.pfnModuleTerm
3172 && (uintptr_t)pReq->u.In.pfnModuleTerm - (uintptr_t)pImage->pvImage >= pReq->u.In.cbImage)
3173 {
3174 RTSemFastMutexRelease(pDevExt->mtxLdr);
3175 Log(("SUP_IOCTL_LDR_LOAD: pfnModuleTerm=%p is outside the image (%p %d bytes)\n",
3176 pReq->u.In.pfnModuleTerm, pImage->pvImage, pReq->u.In.cbImage));
3177 return VERR_INVALID_PARAMETER;
3178 }
3179
3180 /*
3181 * Copy the memory.
3182 */
3183 /* no need to do try/except as this is a buffered request. */
3184 memcpy(pImage->pvImage, &pReq->u.In.achImage[0], pImage->cbImage);
3185 pImage->uState = SUP_IOCTL_LDR_LOAD;
3186 pImage->pfnModuleInit = pReq->u.In.pfnModuleInit;
3187 pImage->pfnModuleTerm = pReq->u.In.pfnModuleTerm;
3188 pImage->offSymbols = pReq->u.In.offSymbols;
3189 pImage->cSymbols = pReq->u.In.cSymbols;
3190 pImage->offStrTab = pReq->u.In.offStrTab;
3191 pImage->cbStrTab = pReq->u.In.cbStrTab;
3192
3193 /*
3194 * Update any entry points.
3195 */
3196 switch (pReq->u.In.eEPType)
3197 {
3198 default:
3199 case SUPLDRLOADEP_NOTHING:
3200 rc = VINF_SUCCESS;
3201 break;
3202 case SUPLDRLOADEP_VMMR0:
3203 rc = supdrvLdrSetR0EP(pDevExt, pReq->u.In.EP.VMMR0.pvVMMR0, pReq->u.In.EP.VMMR0.pvVMMR0EntryInt,
3204 pReq->u.In.EP.VMMR0.pvVMMR0EntryFast, pReq->u.In.EP.VMMR0.pvVMMR0EntryEx);
3205 break;
3206 }
3207
3208 /*
3209 * On success call the module initialization.
3210 */
3211 LogFlow(("supdrvIOCtl_LdrLoad: pfnModuleInit=%p\n", pImage->pfnModuleInit));
3212 if (RT_SUCCESS(rc) && pImage->pfnModuleInit)
3213 {
3214 Log(("supdrvIOCtl_LdrLoad: calling pfnModuleInit=%p\n", pImage->pfnModuleInit));
3215 rc = pImage->pfnModuleInit();
3216 if (rc && pDevExt->pvVMMR0 == pImage->pvImage)
3217 supdrvLdrUnsetR0EP(pDevExt);
3218 }
3219
3220 if (rc)
3221 pImage->uState = SUP_IOCTL_LDR_OPEN;
3222
3223 RTSemFastMutexRelease(pDevExt->mtxLdr);
3224 return rc;
3225}
3226
3227
3228/**
3229 * Frees a previously loaded (prep'ed) image.
3230 *
3231 * @returns IPRT status code.
3232 * @param pDevExt Device globals.
3233 * @param pSession Session data.
3234 * @param pReq The request.
3235 */
3236static int supdrvIOCtl_LdrFree(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDRFREE pReq)
3237{
3238 int rc;
3239 PSUPDRVLDRUSAGE pUsagePrev;
3240 PSUPDRVLDRUSAGE pUsage;
3241 PSUPDRVLDRIMAGE pImage;
3242 LogFlow(("supdrvIOCtl_LdrFree: pvImageBase=%p\n", pReq->u.In.pvImageBase));
3243
3244 /*
3245 * Find the ldr image.
3246 */
3247 RTSemFastMutexRequest(pDevExt->mtxLdr);
3248 pUsagePrev = NULL;
3249 pUsage = pSession->pLdrUsage;
3250 while (pUsage && pUsage->pImage->pvImage != pReq->u.In.pvImageBase)
3251 {
3252 pUsagePrev = pUsage;
3253 pUsage = pUsage->pNext;
3254 }
3255 if (!pUsage)
3256 {
3257 RTSemFastMutexRelease(pDevExt->mtxLdr);
3258 Log(("SUP_IOCTL_LDR_FREE: couldn't find image!\n"));
3259 return VERR_INVALID_HANDLE;
3260 }
3261
3262 /*
3263 * Check if we can remove anything.
3264 */
3265 rc = VINF_SUCCESS;
3266 pImage = pUsage->pImage;
3267 if (pImage->cUsage <= 1 || pUsage->cUsage <= 1)
3268 {
3269 /*
3270 * Check if there are any objects with destructors in the image, if
3271 * so leave it for the session cleanup routine so we get a chance to
3272 * clean things up in the right order and not leave them all dangling.
3273 */
3274 RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
3275 RTSpinlockAcquire(pDevExt->Spinlock, &SpinlockTmp);
3276 if (pImage->cUsage <= 1)
3277 {
3278 PSUPDRVOBJ pObj;
3279 for (pObj = pDevExt->pObjs; pObj; pObj = pObj->pNext)
3280 if (RT_UNLIKELY((uintptr_t)pObj->pfnDestructor - (uintptr_t)pImage->pvImage < pImage->cbImage))
3281 {
3282 rc = VERR_SHARING_VIOLATION; /** @todo VERR_DANGLING_OBJECTS */
3283 break;
3284 }
3285 }
3286 else
3287 {
3288 PSUPDRVUSAGE pGenUsage;
3289 for (pGenUsage = pSession->pUsage; pGenUsage; pGenUsage = pGenUsage->pNext)
3290 if (RT_UNLIKELY((uintptr_t)pGenUsage->pObj->pfnDestructor - (uintptr_t)pImage->pvImage < pImage->cbImage))
3291 {
3292 rc = VERR_SHARING_VIOLATION; /** @todo VERR_DANGLING_OBJECTS */
3293 break;
3294 }
3295 }
3296 RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
3297 if (rc == VINF_SUCCESS)
3298 {
3299 /* unlink it */
3300 if (pUsagePrev)
3301 pUsagePrev->pNext = pUsage->pNext;
3302 else
3303 pSession->pLdrUsage = pUsage->pNext;
3304
3305 /* free it */
3306 pUsage->pImage = NULL;
3307 pUsage->pNext = NULL;
3308 RTMemFree(pUsage);
3309
3310 /*
3311 * Derefrence the image.
3312 */
3313 if (pImage->cUsage <= 1)
3314 supdrvLdrFree(pDevExt, pImage);
3315 else
3316 pImage->cUsage--;
3317 }
3318 else
3319 Log(("supdrvIOCtl_LdrFree: Dangling objects in %p/%s!\n", pImage->pvImage, pImage->szName));
3320 }
3321 else
3322 {
3323 /*
3324 * Dereference both image and usage.
3325 */
3326 pImage->cUsage--;
3327 pUsage->cUsage--;
3328 }
3329
3330 RTSemFastMutexRelease(pDevExt->mtxLdr);
3331 return VINF_SUCCESS;
3332}
3333
3334
3335/**
3336 * Gets the address of a symbol in an open image.
3337 *
3338 * @returns 0 on success.
3339 * @returns SUPDRV_ERR_* on failure.
3340 * @param pDevExt Device globals.
3341 * @param pSession Session data.
3342 * @param pReq The request buffer.
3343 */
3344static int supdrvIOCtl_LdrGetSymbol(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDRGETSYMBOL pReq)
3345{
3346 PSUPDRVLDRIMAGE pImage;
3347 PSUPDRVLDRUSAGE pUsage;
3348 uint32_t i;
3349 PSUPLDRSYM paSyms;
3350 const char *pchStrings;
3351 const size_t cbSymbol = strlen(pReq->u.In.szSymbol) + 1;
3352 void *pvSymbol = NULL;
3353 int rc = VERR_GENERAL_FAILURE;
3354 Log3(("supdrvIOCtl_LdrGetSymbol: pvImageBase=%p szSymbol=\"%s\"\n", pReq->u.In.pvImageBase, pReq->u.In.szSymbol));
3355
3356 /*
3357 * Find the ldr image.
3358 */
3359 RTSemFastMutexRequest(pDevExt->mtxLdr);
3360 pUsage = pSession->pLdrUsage;
3361 while (pUsage && pUsage->pImage->pvImage != pReq->u.In.pvImageBase)
3362 pUsage = pUsage->pNext;
3363 if (!pUsage)
3364 {
3365 RTSemFastMutexRelease(pDevExt->mtxLdr);
3366 Log(("SUP_IOCTL_LDR_GET_SYMBOL: couldn't find image!\n"));
3367 return VERR_INVALID_HANDLE;
3368 }
3369 pImage = pUsage->pImage;
3370 if (pImage->uState != SUP_IOCTL_LDR_LOAD)
3371 {
3372 unsigned uState = pImage->uState;
3373 RTSemFastMutexRelease(pDevExt->mtxLdr);
3374 Log(("SUP_IOCTL_LDR_GET_SYMBOL: invalid image state %d (%#x)!\n", uState, uState)); NOREF(uState);
3375 return VERR_ALREADY_LOADED;
3376 }
3377
3378 /*
3379 * Search the symbol string.
3380 */
3381 pchStrings = (const char *)((uint8_t *)pImage->pvImage + pImage->offStrTab);
3382 paSyms = (PSUPLDRSYM)((uint8_t *)pImage->pvImage + pImage->offSymbols);
3383 for (i = 0; i < pImage->cSymbols; i++)
3384 {
3385 if ( paSyms[i].offSymbol < pImage->cbImage /* paranoia */
3386 && paSyms[i].offName + cbSymbol <= pImage->cbStrTab
3387 && !memcmp(pchStrings + paSyms[i].offName, pReq->u.In.szSymbol, cbSymbol))
3388 {
3389 pvSymbol = (uint8_t *)pImage->pvImage + paSyms[i].offSymbol;
3390 rc = VINF_SUCCESS;
3391 break;
3392 }
3393 }
3394 RTSemFastMutexRelease(pDevExt->mtxLdr);
3395 pReq->u.Out.pvSymbol = pvSymbol;
3396 return rc;
3397}
3398
3399
3400/**
3401 * Updates the IDT patches to point to the specified VMM R0 entry
3402 * point (i.e. VMMR0Enter()).
3403 *
3404 * @returns IPRT status code.
3405 * @param pDevExt Device globals.
3406 * @param pSession Session data.
3407 * @param pVMMR0 VMMR0 image handle.
3408 * @param pvVMMR0EntryInt VMMR0EntryInt address.
3409 * @param pvVMMR0EntryFast VMMR0EntryFast address.
3410 * @param pvVMMR0EntryEx VMMR0EntryEx address.
3411 * @remark Caller must own the loader mutex.
3412 */
3413static int supdrvLdrSetR0EP(PSUPDRVDEVEXT pDevExt, void *pvVMMR0, void *pvVMMR0EntryInt, void *pvVMMR0EntryFast, void *pvVMMR0EntryEx)
3414{
3415 int rc = VINF_SUCCESS;
3416 LogFlow(("supdrvLdrSetR0EP pvVMMR0=%p pvVMMR0EntryInt=%p\n", pvVMMR0, pvVMMR0EntryInt));
3417
3418
3419 /*
3420 * Check if not yet set.
3421 */
3422 if (!pDevExt->pvVMMR0)
3423 {
3424#ifdef VBOX_WITH_IDT_PATCHING
3425 PSUPDRVPATCH pPatch;
3426#endif
3427
3428 /*
3429 * Set it and update IDT patch code.
3430 */
3431 pDevExt->pvVMMR0 = pvVMMR0;
3432 pDevExt->pfnVMMR0EntryInt = pvVMMR0EntryInt;
3433 pDevExt->pfnVMMR0EntryFast = pvVMMR0EntryFast;
3434 pDevExt->pfnVMMR0EntryEx = pvVMMR0EntryEx;
3435#ifdef VBOX_WITH_IDT_PATCHING
3436 for (pPatch = pDevExt->pIdtPatches; pPatch; pPatch = pPatch->pNext)
3437 {
3438# ifdef RT_ARCH_AMD64
3439 ASMAtomicXchgU64((volatile uint64_t *)&pPatch->auCode[pPatch->offVMMR0EntryFixup], (uint64_t)pvVMMR0);
3440# else /* RT_ARCH_X86 */
3441 ASMAtomicXchgU32((volatile uint32_t *)&pPatch->auCode[pPatch->offVMMR0EntryFixup],
3442 (uint32_t)pvVMMR0 - (uint32_t)&pPatch->auCode[pPatch->offVMMR0EntryFixup + 4]);
3443# endif
3444 }
3445#endif /* VBOX_WITH_IDT_PATCHING */
3446 }
3447 else
3448 {
3449 /*
3450 * Return failure or success depending on whether the values match or not.
3451 */
3452 if ( pDevExt->pvVMMR0 != pvVMMR0
3453 || (void *)pDevExt->pfnVMMR0EntryInt != pvVMMR0EntryInt
3454 || (void *)pDevExt->pfnVMMR0EntryFast != pvVMMR0EntryFast
3455 || (void *)pDevExt->pfnVMMR0EntryEx != pvVMMR0EntryEx)
3456 {
3457 AssertMsgFailed(("SUP_IOCTL_LDR_SETR0EP: Already set pointing to a different module!\n"));
3458 rc = VERR_INVALID_PARAMETER;
3459 }
3460 }
3461 return rc;
3462}
3463
3464
3465/**
3466 * Unsets the R0 entry point installed by supdrvLdrSetR0EP.
3467 *
3468 * @param pDevExt Device globals.
3469 */
3470static void supdrvLdrUnsetR0EP(PSUPDRVDEVEXT pDevExt)
3471{
3472#ifdef VBOX_WITH_IDT_PATCHING
3473 PSUPDRVPATCH pPatch;
3474#endif
3475
3476 pDevExt->pvVMMR0 = NULL;
3477 pDevExt->pfnVMMR0EntryInt = NULL;
3478 pDevExt->pfnVMMR0EntryFast = NULL;
3479 pDevExt->pfnVMMR0EntryEx = NULL;
3480
3481#ifdef VBOX_WITH_IDT_PATCHING
3482 for (pPatch = pDevExt->pIdtPatches; pPatch; pPatch = pPatch->pNext)
3483 {
3484# ifdef RT_ARCH_AMD64
3485 ASMAtomicXchgU64((volatile uint64_t *)&pPatch->auCode[pPatch->offVMMR0EntryFixup],
3486 (uint64_t)&pPatch->auCode[pPatch->offStub]);
3487# else /* RT_ARCH_X86 */
3488 ASMAtomicXchgU32((volatile uint32_t *)&pPatch->auCode[pPatch->offVMMR0EntryFixup],
3489 (uint32_t)&pPatch->auCode[pPatch->offStub] - (uint32_t)&pPatch->auCode[pPatch->offVMMR0EntryFixup + 4]);
3490# endif
3491 }
3492#endif /* VBOX_WITH_IDT_PATCHING */
3493}
3494
3495
3496/**
3497 * Adds a usage reference in the specified session of an image.
3498 *
3499 * @param pSession Session in question.
3500 * @param pImage Image which the session is using.
3501 */
3502static void supdrvLdrAddUsage(PSUPDRVSESSION pSession, PSUPDRVLDRIMAGE pImage)
3503{
3504 PSUPDRVLDRUSAGE pUsage;
3505 LogFlow(("supdrvLdrAddUsage: pImage=%p\n", pImage));
3506
3507 /*
3508 * Referenced it already?
3509 */
3510 pUsage = pSession->pLdrUsage;
3511 while (pUsage)
3512 {
3513 if (pUsage->pImage == pImage)
3514 {
3515 pUsage->cUsage++;
3516 return;
3517 }
3518 pUsage = pUsage->pNext;
3519 }
3520
3521 /*
3522 * Allocate new usage record.
3523 */
3524 pUsage = (PSUPDRVLDRUSAGE)RTMemAlloc(sizeof(*pUsage));
3525 Assert(pUsage);
3526 if (pUsage)
3527 {
3528 pUsage->cUsage = 1;
3529 pUsage->pImage = pImage;
3530 pUsage->pNext = pSession->pLdrUsage;
3531 pSession->pLdrUsage = pUsage;
3532 }
3533 /* ignore errors... */
3534}
3535
3536
3537/**
3538 * Frees a load image.
3539 *
3540 * @param pDevExt Pointer to device extension.
3541 * @param pImage Pointer to the image we're gonna free.
3542 * This image must exit!
3543 * @remark The caller MUST own SUPDRVDEVEXT::mtxLdr!
3544 */
3545static void supdrvLdrFree(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
3546{
3547 PSUPDRVLDRIMAGE pImagePrev;
3548 LogFlow(("supdrvLdrFree: pImage=%p\n", pImage));
3549
3550 /* find it - arg. should've used doubly linked list. */
3551 Assert(pDevExt->pLdrImages);
3552 pImagePrev = NULL;
3553 if (pDevExt->pLdrImages != pImage)
3554 {
3555 pImagePrev = pDevExt->pLdrImages;
3556 while (pImagePrev->pNext != pImage)
3557 pImagePrev = pImagePrev->pNext;
3558 Assert(pImagePrev->pNext == pImage);
3559 }
3560
3561 /* unlink */
3562 if (pImagePrev)
3563 pImagePrev->pNext = pImage->pNext;
3564 else
3565 pDevExt->pLdrImages = pImage->pNext;
3566
3567 /* check if this is VMMR0.r0 and fix the Idt patches if it is. */
3568 if (pDevExt->pvVMMR0 == pImage->pvImage)
3569 supdrvLdrUnsetR0EP(pDevExt);
3570
3571 /* check for objects with destructors in this image. (Shouldn't happen.) */
3572 if (pDevExt->pObjs)
3573 {
3574 unsigned cObjs = 0;
3575 PSUPDRVOBJ pObj;
3576 RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
3577 RTSpinlockAcquire(pDevExt->Spinlock, &SpinlockTmp);
3578 for (pObj = pDevExt->pObjs; pObj; pObj = pObj->pNext)
3579 if (RT_UNLIKELY((uintptr_t)pObj->pfnDestructor - (uintptr_t)pImage->pvImage < pImage->cbImage))
3580 {
3581 pObj->pfnDestructor = NULL;
3582 cObjs++;
3583 }
3584 RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
3585 if (cObjs)
3586 OSDBGPRINT(("supdrvLdrFree: Image '%s' has %d dangling objects!\n", pImage->szName, cObjs));
3587 }
3588
3589 /* call termination function if fully loaded. */
3590 if ( pImage->pfnModuleTerm
3591 && pImage->uState == SUP_IOCTL_LDR_LOAD)
3592 {
3593 LogFlow(("supdrvIOCtl_LdrLoad: calling pfnModuleTerm=%p\n", pImage->pfnModuleTerm));
3594 pImage->pfnModuleTerm();
3595 }
3596
3597 /* free the image */
3598 pImage->cUsage = 0;
3599 pImage->pNext = 0;
3600 pImage->uState = SUP_IOCTL_LDR_FREE;
3601 RTMemExecFree(pImage);
3602}
3603
3604
3605/**
3606 * Gets the current paging mode of the CPU and stores in in pOut.
3607 */
3608static SUPPAGINGMODE supdrvIOCtl_GetPagingMode(void)
3609{
3610 SUPPAGINGMODE enmMode;
3611
3612 RTUINTREG cr0 = ASMGetCR0();
3613 if ((cr0 & (X86_CR0_PG | X86_CR0_PE)) != (X86_CR0_PG | X86_CR0_PE))
3614 enmMode = SUPPAGINGMODE_INVALID;
3615 else
3616 {
3617 RTUINTREG cr4 = ASMGetCR4();
3618 uint32_t fNXEPlusLMA = 0;
3619 if (cr4 & X86_CR4_PAE)
3620 {
3621 uint32_t fAmdFeatures = ASMCpuId_EDX(0x80000001);
3622 if (fAmdFeatures & (X86_CPUID_AMD_FEATURE_EDX_NX | X86_CPUID_AMD_FEATURE_EDX_LONG_MODE))
3623 {
3624 uint64_t efer = ASMRdMsr(MSR_K6_EFER);
3625 if ((fAmdFeatures & X86_CPUID_AMD_FEATURE_EDX_NX) && (efer & MSR_K6_EFER_NXE))
3626 fNXEPlusLMA |= RT_BIT(0);
3627 if ((fAmdFeatures & X86_CPUID_AMD_FEATURE_EDX_LONG_MODE) && (efer & MSR_K6_EFER_LMA))
3628 fNXEPlusLMA |= RT_BIT(1);
3629 }
3630 }
3631
3632 switch ((cr4 & (X86_CR4_PAE | X86_CR4_PGE)) | fNXEPlusLMA)
3633 {
3634 case 0:
3635 enmMode = SUPPAGINGMODE_32_BIT;
3636 break;
3637
3638 case X86_CR4_PGE:
3639 enmMode = SUPPAGINGMODE_32_BIT_GLOBAL;
3640 break;
3641
3642 case X86_CR4_PAE:
3643 enmMode = SUPPAGINGMODE_PAE;
3644 break;
3645
3646 case X86_CR4_PAE | RT_BIT(0):
3647 enmMode = SUPPAGINGMODE_PAE_NX;
3648 break;
3649
3650 case X86_CR4_PAE | X86_CR4_PGE:
3651 enmMode = SUPPAGINGMODE_PAE_GLOBAL;
3652 break;
3653
3654 case X86_CR4_PAE | X86_CR4_PGE | RT_BIT(0):
3655 enmMode = SUPPAGINGMODE_PAE_GLOBAL;
3656 break;
3657
3658 case RT_BIT(1) | X86_CR4_PAE:
3659 enmMode = SUPPAGINGMODE_AMD64;
3660 break;
3661
3662 case RT_BIT(1) | X86_CR4_PAE | RT_BIT(0):
3663 enmMode = SUPPAGINGMODE_AMD64_NX;
3664 break;
3665
3666 case RT_BIT(1) | X86_CR4_PAE | X86_CR4_PGE:
3667 enmMode = SUPPAGINGMODE_AMD64_GLOBAL;
3668 break;
3669
3670 case RT_BIT(1) | X86_CR4_PAE | X86_CR4_PGE | RT_BIT(0):
3671 enmMode = SUPPAGINGMODE_AMD64_GLOBAL_NX;
3672 break;
3673
3674 default:
3675 AssertMsgFailed(("Cannot happen! cr4=%#x fNXEPlusLMA=%d\n", cr4, fNXEPlusLMA));
3676 enmMode = SUPPAGINGMODE_INVALID;
3677 break;
3678 }
3679 }
3680 return enmMode;
3681}
3682
3683
3684#ifdef USE_NEW_OS_INTERFACE_FOR_GIP
3685/**
3686 * Creates the GIP.
3687 *
3688 * @returns negative errno.
3689 * @param pDevExt Instance data. GIP stuff may be updated.
3690 */
3691static int supdrvGipCreate(PSUPDRVDEVEXT pDevExt)
3692{
3693 PSUPGLOBALINFOPAGE pGip;
3694 RTHCPHYS HCPhysGip;
3695 uint32_t u32SystemResolution;
3696 uint32_t u32Interval;
3697 int rc;
3698
3699 LogFlow(("supdrvGipCreate:\n"));
3700
3701 /* assert order */
3702 Assert(pDevExt->u32SystemTimerGranularityGrant == 0);
3703 Assert(pDevExt->GipMemObj == NIL_RTR0MEMOBJ);
3704 Assert(!pDevExt->pGipTimer);
3705
3706 /*
3707 * Allocate a suitable page with a default kernel mapping.
3708 */
3709 rc = RTR0MemObjAllocLow(&pDevExt->GipMemObj, PAGE_SIZE, false);
3710 if (RT_FAILURE(rc))
3711 {
3712 OSDBGPRINT(("supdrvGipCreate: failed to allocate the GIP page. rc=%d\n", rc));
3713 return rc;
3714 }
3715 pGip = (PSUPGLOBALINFOPAGE)RTR0MemObjAddress(pDevExt->GipMemObj); AssertPtr(pGip);
3716 HCPhysGip = RTR0MemObjGetPagePhysAddr(pDevExt->GipMemObj, 0); Assert(HCPhysGip != NIL_RTHCPHYS);
3717
3718 /*
3719 * Try bump up the system timer resolution.
3720 * The more interrupts the better...
3721 */
3722 if ( RT_SUCCESS(RTTimerRequestSystemGranularity( 976563 /* 1024 HZ */, &u32SystemResolution))
3723 || RT_SUCCESS(RTTimerRequestSystemGranularity( 1000000 /* 1000 HZ */, &u32SystemResolution))
3724 || RT_SUCCESS(RTTimerRequestSystemGranularity( 3906250 /* 256 HZ */, &u32SystemResolution))
3725 || RT_SUCCESS(RTTimerRequestSystemGranularity( 4000000 /* 250 HZ */, &u32SystemResolution))
3726 || RT_SUCCESS(RTTimerRequestSystemGranularity( 7812500 /* 128 HZ */, &u32SystemResolution))
3727 || RT_SUCCESS(RTTimerRequestSystemGranularity(10000000 /* 100 HZ */, &u32SystemResolution))
3728 || RT_SUCCESS(RTTimerRequestSystemGranularity(15625000 /* 64 HZ */, &u32SystemResolution))
3729 || RT_SUCCESS(RTTimerRequestSystemGranularity(31250000 /* 32 HZ */, &u32SystemResolution))
3730 )
3731 {
3732 Assert(RTTimerGetSystemGranularity() <= u32SystemResolution);
3733 pDevExt->u32SystemTimerGranularityGrant = u32SystemResolution;
3734 }
3735
3736 /*
3737 * Find a reasonable update interval, something close to 10ms would be nice,
3738 * and create a recurring timer.
3739 */
3740 u32Interval = u32SystemResolution = RTTimerGetSystemGranularity();
3741 while (u32Interval < 10000000 /* 10 ms */)
3742 u32Interval += u32SystemResolution;
3743
3744 rc = RTTimerCreateEx(&pDevExt->pGipTimer, u32Interval, 0, supdrvGipTimer, pDevExt);
3745 if (RT_FAILURE(rc))
3746 {
3747 OSDBGPRINT(("supdrvGipCreate: failed create GIP timer at %RU32 ns interval. rc=%d\n", u32Interval, rc));
3748 Assert(!pDevExt->pGipTimer);
3749 supdrvGipDestroy(pDevExt);
3750 return rc;
3751 }
3752
3753 /*
3754 * We're good.
3755 */
3756 supdrvGipInit(pDevExt, pGip, HCPhysGip, RTTimeSystemNanoTS(), 1000000000 / u32Interval /*=Hz*/);
3757 return VINF_SUCCESS;
3758}
3759
3760
3761/**
3762 * Terminates the GIP.
3763 *
3764 * @param pDevExt Instance data. GIP stuff may be updated.
3765 */
3766static void supdrvGipDestroy(PSUPDRVDEVEXT pDevExt)
3767{
3768 int rc;
3769#ifdef DEBUG_DARWIN_GIP
3770 OSDBGPRINT(("supdrvGipDestroy: pDevExt=%p pGip=%p pGipTimer=%p GipMemObj=%p\n", pDevExt,
3771 pDevExt->GipMemObj != NIL_RTR0MEMOBJ ? RTR0MemObjAddress(pDevExt->GipMemObj) : NULL,
3772 pDevExt->pGipTimer, pDevExt->GipMemObj));
3773#endif
3774
3775 /*
3776 * Invalid the GIP data.
3777 */
3778 if (pDevExt->pGip)
3779 {
3780 supdrvGipTerm(pDevExt->pGip);
3781 pDevExt->pGip = NULL;
3782 }
3783
3784 /*
3785 * Destroy the timer and free the GIP memory object.
3786 */
3787 if (pDevExt->pGipTimer)
3788 {
3789 rc = RTTimerDestroy(pDevExt->pGipTimer); AssertRC(rc);
3790 pDevExt->pGipTimer = NULL;
3791 }
3792
3793 if (pDevExt->GipMemObj != NIL_RTR0MEMOBJ)
3794 {
3795 rc = RTR0MemObjFree(pDevExt->GipMemObj, true /* free mappings */); AssertRC(rc);
3796 pDevExt->GipMemObj = NIL_RTR0MEMOBJ;
3797 }
3798
3799 /*
3800 * Finally, release the system timer resolution request if one succeeded.
3801 */
3802 if (pDevExt->u32SystemTimerGranularityGrant)
3803 {
3804 rc = RTTimerReleaseSystemGranularity(pDevExt->u32SystemTimerGranularityGrant); AssertRC(rc);
3805 pDevExt->u32SystemTimerGranularityGrant = 0;
3806 }
3807}
3808
3809
3810/**
3811 * Timer callback function.
3812 * @param pTimer The timer.
3813 * @param pvUser The device extension.
3814 */
3815static DECLCALLBACK(void) supdrvGipTimer(PRTTIMER pTimer, void *pvUser)
3816{
3817 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser;
3818 supdrvGipUpdate(pDevExt->pGip, RTTimeSystemNanoTS());
3819}
3820#endif /* USE_NEW_OS_INTERFACE_FOR_GIP */
3821
3822
3823/**
3824 * Initializes the GIP data.
3825 *
3826 * @returns IPRT status code.
3827 * @param pDevExt Pointer to the device instance data.
3828 * @param pGip Pointer to the read-write kernel mapping of the GIP.
3829 * @param HCPhys The physical address of the GIP.
3830 * @param u64NanoTS The current nanosecond timestamp.
3831 * @param uUpdateHz The update freqence.
3832 */
3833int VBOXCALL supdrvGipInit(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, RTHCPHYS HCPhys, uint64_t u64NanoTS, unsigned uUpdateHz)
3834{
3835 unsigned i;
3836#ifdef DEBUG_DARWIN_GIP
3837 OSDBGPRINT(("supdrvGipInit: pGip=%p HCPhys=%lx u64NanoTS=%llu uUpdateHz=%d\n", pGip, (long)HCPhys, u64NanoTS, uUpdateHz));
3838#else
3839 LogFlow(("supdrvGipInit: pGip=%p HCPhys=%lx u64NanoTS=%llu uUpdateHz=%d\n", pGip, (long)HCPhys, u64NanoTS, uUpdateHz));
3840#endif
3841
3842 /*
3843 * Initialize the structure.
3844 */
3845 memset(pGip, 0, PAGE_SIZE);
3846 pGip->u32Magic = SUPGLOBALINFOPAGE_MAGIC;
3847 pGip->u32Version = SUPGLOBALINFOPAGE_VERSION;
3848 pGip->u32Mode = supdrvGipDeterminTscMode();
3849 pGip->u32UpdateHz = uUpdateHz;
3850 pGip->u32UpdateIntervalNS = 1000000000 / uUpdateHz;
3851 pGip->u64NanoTSLastUpdateHz = u64NanoTS;
3852
3853 for (i = 0; i < RT_ELEMENTS(pGip->aCPUs); i++)
3854 {
3855 pGip->aCPUs[i].u32TransactionId = 2;
3856 pGip->aCPUs[i].u64NanoTS = u64NanoTS;
3857 pGip->aCPUs[i].u64TSC = ASMReadTSC();
3858
3859 /*
3860 * We don't know the following values until we've executed updates.
3861 * So, we'll just insert very high values.
3862 */
3863 pGip->aCPUs[i].u64CpuHz = _4G + 1;
3864 pGip->aCPUs[i].u32UpdateIntervalTSC = _2G / 4;
3865 pGip->aCPUs[i].au32TSCHistory[0] = _2G / 4;
3866 pGip->aCPUs[i].au32TSCHistory[1] = _2G / 4;
3867 pGip->aCPUs[i].au32TSCHistory[2] = _2G / 4;
3868 pGip->aCPUs[i].au32TSCHistory[3] = _2G / 4;
3869 pGip->aCPUs[i].au32TSCHistory[4] = _2G / 4;
3870 pGip->aCPUs[i].au32TSCHistory[5] = _2G / 4;
3871 pGip->aCPUs[i].au32TSCHistory[6] = _2G / 4;
3872 pGip->aCPUs[i].au32TSCHistory[7] = _2G / 4;
3873 }
3874
3875 /*
3876 * Link it to the device extension.
3877 */
3878 pDevExt->pGip = pGip;
3879 pDevExt->HCPhysGip = HCPhys;
3880 pDevExt->cGipUsers = 0;
3881
3882 return VINF_SUCCESS;
3883}
3884
3885
3886/**
3887 * Determin the GIP TSC mode.
3888 *
3889 * @returns The most suitable TSC mode.
3890 */
3891static SUPGIPMODE supdrvGipDeterminTscMode(void)
3892{
3893#ifndef USE_NEW_OS_INTERFACE_FOR_GIP
3894 /*
3895 * The problem here is that AMD processors with power management features
3896 * may easily end up with different TSCs because the CPUs or even cores
3897 * on the same physical chip run at different frequencies to save power.
3898 *
3899 * It is rumoured that this will be corrected with Barcelona and it's
3900 * expected that this will be indicated by the TscInvariant bit in
3901 * cpuid(0x80000007). So, the "difficult" bit here is to correctly
3902 * identify the older CPUs which don't do different frequency and
3903 * can be relied upon to have somewhat uniform TSC between the cpus.
3904 */
3905 if (supdrvOSGetCPUCount() > 1)
3906 {
3907 uint32_t uEAX, uEBX, uECX, uEDX;
3908
3909 /* Permit user users override. */
3910 if (supdrvOSGetForcedAsyncTscMode())
3911 return SUPGIPMODE_ASYNC_TSC;
3912
3913 /* Check for "AuthenticAMD" */
3914 ASMCpuId(0, &uEAX, &uEBX, &uECX, &uEDX);
3915 if (uEAX >= 1 && uEBX == 0x68747541 && uECX == 0x444d4163 && uEDX == 0x69746e65)
3916 {
3917 /* Check for APM support and that TscInvariant is cleared. */
3918 ASMCpuId(0x80000000, &uEAX, &uEBX, &uECX, &uEDX);
3919 if (uEAX >= 0x80000007)
3920 {
3921 ASMCpuId(0x80000007, &uEAX, &uEBX, &uECX, &uEDX);
3922 if ( !(uEDX & RT_BIT(8))/* TscInvariant */
3923 && (uEDX & 0x3e)) /* STC|TM|THERMTRIP|VID|FID. Ignore TS. */
3924 return SUPGIPMODE_ASYNC_TSC;
3925 }
3926 }
3927 }
3928#endif
3929 return SUPGIPMODE_SYNC_TSC;
3930}
3931
3932
3933/**
3934 * Invalidates the GIP data upon termination.
3935 *
3936 * @param pGip Pointer to the read-write kernel mapping of the GIP.
3937 */
3938void VBOXCALL supdrvGipTerm(PSUPGLOBALINFOPAGE pGip)
3939{
3940 unsigned i;
3941 pGip->u32Magic = 0;
3942 for (i = 0; i < RT_ELEMENTS(pGip->aCPUs); i++)
3943 {
3944 pGip->aCPUs[i].u64NanoTS = 0;
3945 pGip->aCPUs[i].u64TSC = 0;
3946 pGip->aCPUs[i].iTSCHistoryHead = 0;
3947 }
3948}
3949
3950
3951/**
3952 * Worker routine for supdrvGipUpdate and supdrvGipUpdatePerCpu that
3953 * updates all the per cpu data except the transaction id.
3954 *
3955 * @param pGip The GIP.
3956 * @param pGipCpu Pointer to the per cpu data.
3957 * @param u64NanoTS The current time stamp.
3958 */
3959static void supdrvGipDoUpdateCpu(PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pGipCpu, uint64_t u64NanoTS)
3960{
3961 uint64_t u64TSC;
3962 uint64_t u64TSCDelta;
3963 uint32_t u32UpdateIntervalTSC;
3964 uint32_t u32UpdateIntervalTSCSlack;
3965 unsigned iTSCHistoryHead;
3966 uint64_t u64CpuHz;
3967
3968 /*
3969 * Update the NanoTS.
3970 */
3971 ASMAtomicXchgU64(&pGipCpu->u64NanoTS, u64NanoTS);
3972
3973 /*
3974 * Calc TSC delta.
3975 */
3976 /** @todo validate the NanoTS delta, don't trust the OS to call us when it should... */
3977 u64TSC = ASMReadTSC();
3978 u64TSCDelta = u64TSC - pGipCpu->u64TSC;
3979 ASMAtomicXchgU64(&pGipCpu->u64TSC, u64TSC);
3980
3981 if (u64TSCDelta >> 32)
3982 {
3983 u64TSCDelta = pGipCpu->u32UpdateIntervalTSC;
3984 pGipCpu->cErrors++;
3985 }
3986
3987 /*
3988 * TSC History.
3989 */
3990 Assert(ELEMENTS(pGipCpu->au32TSCHistory) == 8);
3991
3992 iTSCHistoryHead = (pGipCpu->iTSCHistoryHead + 1) & 7;
3993 ASMAtomicXchgU32(&pGipCpu->iTSCHistoryHead, iTSCHistoryHead);
3994 ASMAtomicXchgU32(&pGipCpu->au32TSCHistory[iTSCHistoryHead], (uint32_t)u64TSCDelta);
3995
3996 /*
3997 * UpdateIntervalTSC = average of last 8,2,1 intervals depending on update HZ.
3998 */
3999 if (pGip->u32UpdateHz >= 1000)
4000 {
4001 uint32_t u32;
4002 u32 = pGipCpu->au32TSCHistory[0];
4003 u32 += pGipCpu->au32TSCHistory[1];
4004 u32 += pGipCpu->au32TSCHistory[2];
4005 u32 += pGipCpu->au32TSCHistory[3];
4006 u32 >>= 2;
4007 u32UpdateIntervalTSC = pGipCpu->au32TSCHistory[4];
4008 u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[5];
4009 u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[6];
4010 u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[7];
4011 u32UpdateIntervalTSC >>= 2;
4012 u32UpdateIntervalTSC += u32;
4013 u32UpdateIntervalTSC >>= 1;
4014
4015 /* Value choosen for a 2GHz Athlon64 running linux 2.6.10/11, . */
4016 u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 14;
4017 }
4018 else if (pGip->u32UpdateHz >= 90)
4019 {
4020 u32UpdateIntervalTSC = (uint32_t)u64TSCDelta;
4021 u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[(iTSCHistoryHead - 1) & 7];
4022 u32UpdateIntervalTSC >>= 1;
4023
4024 /* value choosen on a 2GHz thinkpad running windows */
4025 u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 7;
4026 }
4027 else
4028 {
4029 u32UpdateIntervalTSC = (uint32_t)u64TSCDelta;
4030
4031 /* This value hasn't be checked yet.. waiting for OS/2 and 33Hz timers.. :-) */
4032 u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 6;
4033 }
4034 ASMAtomicXchgU32(&pGipCpu->u32UpdateIntervalTSC, u32UpdateIntervalTSC + u32UpdateIntervalTSCSlack);
4035
4036 /*
4037 * CpuHz.
4038 */
4039 u64CpuHz = ASMMult2xU32RetU64(u32UpdateIntervalTSC, pGip->u32UpdateHz);
4040 ASMAtomicXchgU64(&pGipCpu->u64CpuHz, u64CpuHz);
4041}
4042
4043
4044/**
4045 * Updates the GIP.
4046 *
4047 * @param pGip Pointer to the GIP.
4048 * @param u64NanoTS The current nanosecond timesamp.
4049 */
4050void VBOXCALL supdrvGipUpdate(PSUPGLOBALINFOPAGE pGip, uint64_t u64NanoTS)
4051{
4052 /*
4053 * Determin the relevant CPU data.
4054 */
4055 PSUPGIPCPU pGipCpu;
4056 if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
4057 pGipCpu = &pGip->aCPUs[0];
4058 else
4059 {
4060 unsigned iCpu = ASMGetApicId();
4061 if (RT_LIKELY(iCpu >= RT_ELEMENTS(pGip->aCPUs)))
4062 return;
4063 pGipCpu = &pGip->aCPUs[iCpu];
4064 }
4065
4066 /*
4067 * Start update transaction.
4068 */
4069 if (!(ASMAtomicIncU32(&pGipCpu->u32TransactionId) & 1))
4070 {
4071 /* this can happen on win32 if we're taking to long and there are more CPUs around. shouldn't happen though. */
4072 AssertMsgFailed(("Invalid transaction id, %#x, not odd!\n", pGipCpu->u32TransactionId));
4073 ASMAtomicIncU32(&pGipCpu->u32TransactionId);
4074 pGipCpu->cErrors++;
4075 return;
4076 }
4077
4078 /*
4079 * Recalc the update frequency every 0x800th time.
4080 */
4081 if (!(pGipCpu->u32TransactionId & (GIP_UPDATEHZ_RECALC_FREQ * 2 - 2)))
4082 {
4083 if (pGip->u64NanoTSLastUpdateHz)
4084 {
4085#ifdef RT_ARCH_AMD64 /** @todo fix 64-bit div here to work on x86 linux. */
4086 uint64_t u64Delta = u64NanoTS - pGip->u64NanoTSLastUpdateHz;
4087 uint32_t u32UpdateHz = (uint32_t)((UINT64_C(1000000000) * GIP_UPDATEHZ_RECALC_FREQ) / u64Delta);
4088 if (u32UpdateHz <= 2000 && u32UpdateHz >= 30)
4089 {
4090 ASMAtomicXchgU32(&pGip->u32UpdateHz, u32UpdateHz);
4091 ASMAtomicXchgU32(&pGip->u32UpdateIntervalNS, 1000000000 / u32UpdateHz);
4092 }
4093#endif
4094 }
4095 ASMAtomicXchgU64(&pGip->u64NanoTSLastUpdateHz, u64NanoTS);
4096 }
4097
4098 /*
4099 * Update the data.
4100 */
4101 supdrvGipDoUpdateCpu(pGip, pGipCpu, u64NanoTS);
4102
4103 /*
4104 * Complete transaction.
4105 */
4106 ASMAtomicIncU32(&pGipCpu->u32TransactionId);
4107}
4108
4109
4110/**
4111 * Updates the per cpu GIP data for the calling cpu.
4112 *
4113 * @param pGip Pointer to the GIP.
4114 * @param u64NanoTS The current nanosecond timesamp.
4115 * @param iCpu The CPU index.
4116 */
4117void VBOXCALL supdrvGipUpdatePerCpu(PSUPGLOBALINFOPAGE pGip, uint64_t u64NanoTS, unsigned iCpu)
4118{
4119 PSUPGIPCPU pGipCpu;
4120
4121 if (RT_LIKELY(iCpu < RT_ELEMENTS(pGip->aCPUs)))
4122 {
4123 pGipCpu = &pGip->aCPUs[iCpu];
4124
4125 /*
4126 * Start update transaction.
4127 */
4128 if (!(ASMAtomicIncU32(&pGipCpu->u32TransactionId) & 1))
4129 {
4130 AssertMsgFailed(("Invalid transaction id, %#x, not odd!\n", pGipCpu->u32TransactionId));
4131 ASMAtomicIncU32(&pGipCpu->u32TransactionId);
4132 pGipCpu->cErrors++;
4133 return;
4134 }
4135
4136 /*
4137 * Update the data.
4138 */
4139 supdrvGipDoUpdateCpu(pGip, pGipCpu, u64NanoTS);
4140
4141 /*
4142 * Complete transaction.
4143 */
4144 ASMAtomicIncU32(&pGipCpu->u32TransactionId);
4145 }
4146}
4147
4148
4149/**
4150 * Callback used by supdrvDetermineAsyncTSC to read the TSC on a CPU.
4151 *
4152 * @param idCpu Ignored.
4153 * @param pvUser1 Where to put the TSC.
4154 * @param pvUser2 Ignored.
4155 */
4156static DECLCALLBACK(void) supdrvDetermineAsyncTscWorker(RTCPUID idCpu, void *pvUser1, void *pvUser2)
4157{
4158 *(uint64_t *)pvUser1 = ASMReadTSC();
4159}
4160
4161
4162/**
4163 * Determine if Async GIP mode is required because of TSC drift.
4164 *
4165 * When using the default/normal timer code it is essential that the time stamp counter
4166 * (TSC) runs never backwards, that is, a read operation to the counter should return
4167 * a bigger value than any previous read operation. This is guaranteed by the latest
4168 * AMD CPUs and by newer Intel CPUs which never enter the C2 state (P4). In any other
4169 * case we have to choose the asynchronous timer mode.
4170 *
4171 * @param pu64Diff pointer to the determined difference between different cores.
4172 * @return false if the time stamp counters appear to be synchron, true otherwise.
4173 */
4174bool VBOXCALL supdrvDetermineAsyncTsc(uint64_t *pu64DiffCores)
4175{
4176 static uint64_t s_aTsc[8][RTCPUSET_MAX_CPUS];
4177 uint64_t u64Diff, u64DiffMin, u64DiffMax, u64TscLast;
4178 int iSlot, iCpu, cCpus;
4179 bool fBackwards;
4180 RTCPUSET OnlineCpus;
4181 int rc;
4182
4183 *pu64DiffCores = 1;
4184
4185 RTMpGetOnlineSet(&OnlineCpus);
4186 cCpus = RTCpuSetCount(&OnlineCpus);
4187 if (cCpus < 2)
4188 return false;
4189 Assert(cCpus <= RT_ELEMENTS(s_aTsc[0]));
4190
4191 /*
4192 * Collect data from the online CPUs.
4193 */
4194 for (iSlot = 0; iSlot < RT_ELEMENTS(s_aTsc); iSlot++)
4195 {
4196 RTCPUID iCpuSet = 0;
4197 for (iCpu = 0; iCpu < cCpus; iCpu++)
4198 {
4199 while (!RTCpuSetIsMember(&OnlineCpus, iCpuSet))
4200 iCpuSet++; /* skip offline CPU */
4201 rc = RTMpOnSpecific(RTMpCpuIdFromSetIndex(iCpuSet), supdrvDetermineAsyncTscWorker, &s_aTsc[iSlot][iCpu], NULL);
4202 if (rc == VERR_NOT_SUPPORTED)
4203 return false;
4204 iCpuSet++;
4205 }
4206 }
4207
4208 /*
4209 * Check that the TSC reads are strictly ascending.
4210 */
4211 fBackwards = false;
4212 u64DiffMin = (uint64_t)~0;
4213 u64TscLast = 0;
4214 for (iSlot = 0; iSlot < RT_ELEMENTS(s_aTsc); iSlot++)
4215 {
4216 uint64_t u64Tsc0 = s_aTsc[iSlot][0];
4217 u64DiffMax = 0;
4218 if (u64Tsc0 <= u64TscLast)
4219 fBackwards = true;
4220 u64TscLast = u64Tsc0;
4221 for (iCpu = 1; iCpu < cCpus; iCpu++)
4222 {
4223 uint64_t u64TscN = s_aTsc[iSlot][iCpu];
4224 if (u64TscN <= u64TscLast)
4225 fBackwards = true;
4226 u64TscLast = u64TscN;
4227
4228 u64Diff = u64TscN > u64Tsc0 ? u64TscN - u64Tsc0 : u64Tsc0 - u64TscN;
4229 if (u64DiffMax < u64Diff)
4230 u64DiffMax = u64Diff;
4231 }
4232 if (u64DiffMin > u64DiffMax)
4233 u64DiffMin = u64DiffMax;
4234 }
4235 /* informational */
4236 *pu64DiffCores = u64DiffMin;
4237
4238 return fBackwards;
4239}
4240
4241
4242#ifndef DEBUG /** @todo change #ifndef DEBUG -> #ifdef LOG_ENABLED */
4243/**
4244 * Stub function for non-debug builds.
4245 */
4246RTDECL(PRTLOGGER) RTLogDefaultInstance(void)
4247{
4248 return NULL;
4249}
4250
4251RTDECL(PRTLOGGER) RTLogRelDefaultInstance(void)
4252{
4253 return NULL;
4254}
4255
4256/**
4257 * Stub function for non-debug builds.
4258 */
4259RTDECL(int) RTLogSetDefaultInstanceThread(PRTLOGGER pLogger, uintptr_t uKey)
4260{
4261 return 0;
4262}
4263
4264/**
4265 * Stub function for non-debug builds.
4266 */
4267RTDECL(void) RTLogLogger(PRTLOGGER pLogger, void *pvCallerRet, const char *pszFormat, ...)
4268{
4269}
4270
4271/**
4272 * Stub function for non-debug builds.
4273 */
4274RTDECL(void) RTLogLoggerEx(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, ...)
4275{
4276}
4277
4278/**
4279 * Stub function for non-debug builds.
4280 */
4281RTDECL(void) RTLogLoggerExV(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, va_list args)
4282{
4283}
4284
4285/**
4286 * Stub function for non-debug builds.
4287 */
4288RTDECL(void) RTLogPrintf(const char *pszFormat, ...)
4289{
4290}
4291
4292/**
4293 * Stub function for non-debug builds.
4294 */
4295RTDECL(void) RTLogPrintfV(const char *pszFormat, va_list args)
4296{
4297}
4298#endif /* !DEBUG */
4299
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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