VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/SUPDrv.c@ 12000

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

supdrv: Prototyped the fix for the PspGetSetContextInternal / RtlVirtualUnwind crashes on Vista64. (disabled)

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

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