VirtualBox

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

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

32-bit kernel doesn't mean 32-bit cpu - I really hope this doesn't break anything... Fixed SUPR0MemLock when using the new API.

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