VirtualBox

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

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

Check all the CPUs instead of just the first 8.

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

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