VirtualBox

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

Last change on this file since 1 was 1, checked in by vboxsync, 55 years ago

import

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