VirtualBox

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

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

Split VMMR0Entry into VMMR0EntryInt, VMMR0EntryFast and VMMr0EntryEx. This will prevent the SUPCallVMMR0Ex path from causing harm and messing up the paths that has to be optimized.

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