VirtualBox

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

Last change on this file since 4792 was 4792, checked in by vboxsync, 18 years ago

Disable interrupts before call the VMMR0 entrypoint.

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

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