VirtualBox

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

Last change on this file since 8796 was 8796, checked in by vboxsync, 17 years ago

fixed compilation of Linux host kernel module

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

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