VirtualBox

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

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

Support driver interface cleanup.

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