VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/SUPDrv.c@ 25275

Last change on this file since 25275 was 25275, checked in by vboxsync, 15 years ago

SUPDrv: Added SUPGetGIP and added a fNativeLoader indicator to SUPLDROPEN (VBOX_WITH_NATIVE_R0_LOADER).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 195.8 KB
Line 
1/* $Revision: 25275 $ */
2/** @file
3 * VBoxDrv - The VirtualBox Support Driver - Common code.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31/*******************************************************************************
32* Header Files *
33*******************************************************************************/
34#define LOG_GROUP LOG_GROUP_SUP_DRV
35#include "SUPDrvInternal.h"
36#ifndef PAGE_SHIFT
37# include <iprt/param.h>
38#endif
39#include <iprt/alloc.h>
40#include <iprt/cpuset.h>
41#include <iprt/handletable.h>
42#include <iprt/mp.h>
43#include <iprt/power.h>
44#include <iprt/process.h>
45#include <iprt/semaphore.h>
46#include <iprt/spinlock.h>
47#include <iprt/thread.h>
48#include <iprt/uuid.h>
49#include <VBox/param.h>
50#include <VBox/log.h>
51#include <VBox/err.h>
52#if defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
53# include <iprt/crc32.h>
54# include <iprt/net.h>
55# include <iprt/string.h>
56# include <iprt/rand.h>
57# include <iprt/path.h>
58#endif
59
60/*
61 * Logging assignments:
62 * Log - useful stuff, like failures.
63 * LogFlow - program flow, except the really noisy bits.
64 * Log2 - Cleanup.
65 * Log3 - Loader flow noise.
66 * Log4 - Call VMMR0 flow noise.
67 * Log5 - Native yet-to-be-defined noise.
68 * Log6 - Native ioctl flow noise.
69 *
70 * Logging requires BUILD_TYPE=debug and possibly changes to the logger
71 * instanciation in log-vbox.c(pp).
72 */
73
74
75/*******************************************************************************
76* Defined Constants And Macros *
77*******************************************************************************/
78/** The frequency by which we recalculate the u32UpdateHz and
79 * u32UpdateIntervalNS GIP members. The value must be a power of 2. */
80#define GIP_UPDATEHZ_RECALC_FREQ 0x800
81
82/** @def VBOX_SVN_REV
83 * The makefile should define this if it can. */
84#ifndef VBOX_SVN_REV
85# define VBOX_SVN_REV 0
86#endif
87
88
89/*******************************************************************************
90* Internal Functions *
91*******************************************************************************/
92static DECLCALLBACK(int) supdrvSessionObjHandleRetain(RTHANDLETABLE hHandleTable, void *pvObj, void *pvCtx, void *pvUser);
93static DECLCALLBACK(void) supdrvSessionObjHandleDelete(RTHANDLETABLE hHandleTable, uint32_t h, void *pvObj, void *pvCtx, void *pvUser);
94static int supdrvMemAdd(PSUPDRVMEMREF pMem, PSUPDRVSESSION pSession);
95static int supdrvMemRelease(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr, SUPDRVMEMREFTYPE eType);
96static int supdrvIOCtl_LdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDROPEN pReq);
97static int supdrvIOCtl_LdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDRLOAD pReq);
98static int supdrvIOCtl_LdrFree(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDRFREE pReq);
99static int supdrvIOCtl_LdrGetSymbol(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDRGETSYMBOL pReq);
100static int supdrvIDC_LdrGetSymbol(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPDRVIDCREQGETSYM pReq);
101static int supdrvLdrSetVMMR0EPs(PSUPDRVDEVEXT pDevExt, void *pvVMMR0, void *pvVMMR0EntryInt, void *pvVMMR0EntryFast, void *pvVMMR0EntryEx);
102static void supdrvLdrUnsetVMMR0EPs(PSUPDRVDEVEXT pDevExt);
103static int supdrvLdrAddUsage(PSUPDRVSESSION pSession, PSUPDRVLDRIMAGE pImage);
104static void supdrvLdrFree(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage);
105static int supdrvIOCtl_CallServiceModule(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPCALLSERVICE pReq);
106static int supdrvIOCtl_LoggerSettings(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLOGGERSETTINGS pReq);
107static int supdrvGipCreate(PSUPDRVDEVEXT pDevExt);
108static void supdrvGipDestroy(PSUPDRVDEVEXT pDevExt);
109static DECLCALLBACK(void) supdrvGipSyncTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick);
110static DECLCALLBACK(void) supdrvGipAsyncTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick);
111static DECLCALLBACK(void) supdrvGipMpEvent(RTMPEVENT enmEvent, RTCPUID idCpu, void *pvUser);
112
113#ifdef RT_WITH_W64_UNWIND_HACK
114DECLASM(int) supdrvNtWrapVMMR0EntryEx(PFNRT pfnVMMR0EntryEx, PVM pVM, VMCPUID idCpu, unsigned uOperation, PSUPVMMR0REQHDR pReq, uint64_t u64Arg, PSUPDRVSESSION pSession);
115DECLASM(int) supdrvNtWrapVMMR0EntryFast(PFNRT pfnVMMR0EntryFast, PVM pVM, VMCPUID idCpu, unsigned uOperation);
116DECLASM(void) supdrvNtWrapObjDestructor(PFNRT pfnDestruction, void *pvObj, void *pvUser1, void *pvUser2);
117DECLASM(void *) supdrvNtWrapQueryFactoryInterface(PFNRT pfnQueryFactoryInterface, struct SUPDRVFACTORY const *pSupDrvFactory, PSUPDRVSESSION pSession, const char *pszInterfaceUuid);
118DECLASM(int) supdrvNtWrapModuleInit(PFNRT pfnModuleInit);
119DECLASM(void) supdrvNtWrapModuleTerm(PFNRT pfnModuleTerm);
120DECLASM(int) supdrvNtWrapServiceReqHandler(PFNRT pfnServiceReqHandler, PSUPDRVSESSION pSession, uint32_t uOperation, uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr);
121
122DECLASM(int) UNWIND_WRAP(SUPR0ComponentRegisterFactory)(PSUPDRVSESSION pSession, PCSUPDRVFACTORY pFactory);
123DECLASM(int) UNWIND_WRAP(SUPR0ComponentDeregisterFactory)(PSUPDRVSESSION pSession, PCSUPDRVFACTORY pFactory);
124DECLASM(int) UNWIND_WRAP(SUPR0ComponentQueryFactory)(PSUPDRVSESSION pSession, const char *pszName, const char *pszInterfaceUuid, void **ppvFactoryIf);
125DECLASM(void *) UNWIND_WRAP(SUPR0ObjRegister)(PSUPDRVSESSION pSession, SUPDRVOBJTYPE enmType, PFNSUPDRVDESTRUCTOR pfnDestructor, void *pvUser1, void *pvUser2);
126DECLASM(int) UNWIND_WRAP(SUPR0ObjAddRef)(void *pvObj, PSUPDRVSESSION pSession);
127DECLASM(int) UNWIND_WRAP(SUPR0ObjAddRefEx)(void *pvObj, PSUPDRVSESSION pSession, bool fNoPreempt);
128DECLASM(int) UNWIND_WRAP(SUPR0ObjRelease)(void *pvObj, PSUPDRVSESSION pSession);
129DECLASM(int) UNWIND_WRAP(SUPR0ObjVerifyAccess)(void *pvObj, PSUPDRVSESSION pSession, const char *pszObjName);
130DECLASM(int) UNWIND_WRAP(SUPR0LockMem)(PSUPDRVSESSION pSession, RTR3PTR pvR3, uint32_t cPages, PRTHCPHYS paPages);
131DECLASM(int) UNWIND_WRAP(SUPR0UnlockMem)(PSUPDRVSESSION pSession, RTR3PTR pvR3);
132DECLASM(int) UNWIND_WRAP(SUPR0ContAlloc)(PSUPDRVSESSION pSession, uint32_t cPages, PRTR0PTR ppvR0, PRTR3PTR ppvR3, PRTHCPHYS pHCPhys);
133DECLASM(int) UNWIND_WRAP(SUPR0ContFree)(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr);
134DECLASM(int) UNWIND_WRAP(SUPR0LowAlloc)(PSUPDRVSESSION pSession, uint32_t cPages, PRTR0PTR ppvR0, PRTR3PTR ppvR3, PRTHCPHYS paPages);
135DECLASM(int) UNWIND_WRAP(SUPR0LowFree)(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr);
136DECLASM(int) UNWIND_WRAP(SUPR0MemAlloc)(PSUPDRVSESSION pSession, uint32_t cb, PRTR0PTR ppvR0, PRTR3PTR ppvR3);
137DECLASM(int) UNWIND_WRAP(SUPR0MemGetPhys)(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr, PSUPPAGE paPages);
138DECLASM(int) UNWIND_WRAP(SUPR0MemFree)(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr);
139DECLASM(int) UNWIND_WRAP(SUPR0PageAllocEx)(PSUPDRVSESSION pSession, uint32_t cPages, uint32_t fFlags, PRTR3PTR ppvR3, PRTR0PTR ppvR0, PRTHCPHYS paPages);
140DECLASM(int) UNWIND_WRAP(SUPR0PageFree)(PSUPDRVSESSION pSession, RTR3PTR pvR3);
141//DECLASM(int) UNWIND_WRAP(SUPR0Printf)(const char *pszFormat, ...);
142DECLASM(int) UNWIND_WRAP(SUPSemEventCreate)(PSUPDRVSESSION pSession, PSUPSEMEVENT phEvent);
143DECLASM(int) UNWIND_WRAP(SUPSemEventClose)(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent);
144DECLASM(int) UNWIND_WRAP(SUPSemEventSignal)(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent);
145DECLASM(int) UNWIND_WRAP(SUPSemEventWait)(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent, uint32_t cMillies);
146DECLASM(int) UNWIND_WRAP(SUPSemEventWaitNoResume)(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent, uint32_t cMillies);
147DECLASM(int) UNWIND_WRAP(SUPSemEventMultiCreate)(PSUPDRVSESSION pSession, PSUPSEMEVENTMULTI phEventMulti);
148DECLASM(int) UNWIND_WRAP(SUPSemEventMultiClose)(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti);
149DECLASM(int) UNWIND_WRAP(SUPSemEventMultiSignal)(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti);
150DECLASM(int) UNWIND_WRAP(SUPSemEventMultiReset)(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti);
151DECLASM(int) UNWIND_WRAP(SUPSemEventMultiWait)(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti, uint32_t cMillies);
152DECLASM(int) UNWIND_WRAP(SUPSemEventMultiWaitNoResume)(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti, uint32_t cMillies);
153DECLASM(SUPPAGINGMODE) UNWIND_WRAP(SUPR0GetPagingMode)(void);
154DECLASM(void *) UNWIND_WRAP(RTMemAlloc)(size_t cb) RT_NO_THROW;
155DECLASM(void *) UNWIND_WRAP(RTMemAllocZ)(size_t cb) RT_NO_THROW;
156DECLASM(void) UNWIND_WRAP(RTMemFree)(void *pv) RT_NO_THROW;
157DECLASM(void *) UNWIND_WRAP(RTMemDup)(const void *pvSrc, size_t cb) RT_NO_THROW;
158DECLASM(void *) UNWIND_WRAP(RTMemDupEx)(const void *pvSrc, size_t cbSrc, size_t cbExtra) RT_NO_THROW;
159DECLASM(void *) UNWIND_WRAP(RTMemRealloc)(void *pvOld, size_t cbNew) RT_NO_THROW;
160DECLASM(int) UNWIND_WRAP(RTR0MemObjAllocLow)(PRTR0MEMOBJ pMemObj, size_t cb, bool fExecutable);
161DECLASM(int) UNWIND_WRAP(RTR0MemObjAllocPage)(PRTR0MEMOBJ pMemObj, size_t cb, bool fExecutable);
162DECLASM(int) UNWIND_WRAP(RTR0MemObjAllocPhys)(PRTR0MEMOBJ pMemObj, size_t cb, RTHCPHYS PhysHighest);
163DECLASM(int) UNWIND_WRAP(RTR0MemObjAllocPhysNC)(PRTR0MEMOBJ pMemObj, size_t cb, RTHCPHYS PhysHighest);
164DECLASM(int) UNWIND_WRAP(RTR0MemObjAllocCont)(PRTR0MEMOBJ pMemObj, size_t cb, bool fExecutable);
165DECLASM(int) UNWIND_WRAP(RTR0MemObjEnterPhys)(PRTR0MEMOBJ pMemObj, RTHCPHYS Phys, size_t cb);
166DECLASM(int) UNWIND_WRAP(RTR0MemObjLockUser)(PRTR0MEMOBJ pMemObj, RTR3PTR R3Ptr, size_t cb, uint32_t fFlags, RTR0PROCESS R0Process);
167DECLASM(int) UNWIND_WRAP(RTR0MemObjMapKernel)(PRTR0MEMOBJ pMemObj, RTR0MEMOBJ MemObjToMap, void *pvFixed, size_t uAlignment, unsigned fProt);
168DECLASM(int) UNWIND_WRAP(RTR0MemObjMapKernelEx)(PRTR0MEMOBJ pMemObj, RTR0MEMOBJ MemObjToMap, void *pvFixed, size_t uAlignment, unsigned fProt, size_t offSub, size_t cbSub);
169DECLASM(int) UNWIND_WRAP(RTR0MemObjMapUser)(PRTR0MEMOBJ pMemObj, RTR0MEMOBJ MemObjToMap, RTR3PTR R3PtrFixed, size_t uAlignment, unsigned fProt, RTR0PROCESS R0Process);
170DECLASM(int) UNWIND_WRAP(RTR0MemObjProtect)(RTR0MEMOBJ hMemObj, size_t offsub, size_t cbSub, uint32_t fProt);
171/*DECLASM(void *) UNWIND_WRAP(RTR0MemObjAddress)(RTR0MEMOBJ MemObj); - not necessary */
172/*DECLASM(RTR3PTR) UNWIND_WRAP(RTR0MemObjAddressR3)(RTR0MEMOBJ MemObj); - not necessary */
173/*DECLASM(size_t) UNWIND_WRAP(RTR0MemObjSize)(RTR0MEMOBJ MemObj); - not necessary */
174/*DECLASM(bool) UNWIND_WRAP(RTR0MemObjIsMapping)(RTR0MEMOBJ MemObj); - not necessary */
175/*DECLASM(RTHCPHYS) UNWIND_WRAP(RTR0MemObjGetPagePhysAddr)(RTR0MEMOBJ MemObj, size_t iPage); - not necessary */
176DECLASM(int) UNWIND_WRAP(RTR0MemObjFree)(RTR0MEMOBJ MemObj, bool fFreeMappings);
177DECLASM(int) UNWIND_WRAP(RTR0MemUserCopyFrom)(void *pvDst, RTR3PTR R3PtrSrc, size_t cb);
178DECLASM(int) UNWIND_WRAP(RTR0MemUserCopyTo)(RTR3PTR R3PtrDst, void const *pvSrc, size_t cb);
179/* RTR0MemUserIsValidAddr - not necessary */
180/* RTR0MemKernelIsValidAddr - not necessary */
181/* RTR0MemAreKrnlAndUsrDifferent - not necessary */
182/* RTProcSelf - not necessary */
183/* RTR0ProcHandleSelf - not necessary */
184DECLASM(int) UNWIND_WRAP(RTSemFastMutexCreate)(PRTSEMFASTMUTEX pMutexSem);
185DECLASM(int) UNWIND_WRAP(RTSemFastMutexDestroy)(RTSEMFASTMUTEX MutexSem);
186DECLASM(int) UNWIND_WRAP(RTSemFastMutexRequest)(RTSEMFASTMUTEX MutexSem);
187DECLASM(int) UNWIND_WRAP(RTSemFastMutexRelease)(RTSEMFASTMUTEX MutexSem);
188DECLASM(int) UNWIND_WRAP(RTSemEventCreate)(PRTSEMEVENT pEventSem);
189DECLASM(int) UNWIND_WRAP(RTSemEventSignal)(RTSEMEVENT EventSem);
190DECLASM(int) UNWIND_WRAP(RTSemEventWait)(RTSEMEVENT EventSem, unsigned cMillies);
191DECLASM(int) UNWIND_WRAP(RTSemEventWaitNoResume)(RTSEMEVENT EventSem, unsigned cMillies);
192DECLASM(int) UNWIND_WRAP(RTSemEventDestroy)(RTSEMEVENT EventSem);
193DECLASM(int) UNWIND_WRAP(RTSemEventMultiCreate)(PRTSEMEVENTMULTI pEventMultiSem);
194DECLASM(int) UNWIND_WRAP(RTSemEventMultiSignal)(RTSEMEVENTMULTI EventMultiSem);
195DECLASM(int) UNWIND_WRAP(RTSemEventMultiReset)(RTSEMEVENTMULTI EventMultiSem);
196DECLASM(int) UNWIND_WRAP(RTSemEventMultiWait)(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies);
197DECLASM(int) UNWIND_WRAP(RTSemEventMultiWaitNoResume)(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies);
198DECLASM(int) UNWIND_WRAP(RTSemEventMultiDestroy)(RTSEMEVENTMULTI EventMultiSem);
199DECLASM(int) UNWIND_WRAP(RTSpinlockCreate)(PRTSPINLOCK pSpinlock);
200DECLASM(int) UNWIND_WRAP(RTSpinlockDestroy)(RTSPINLOCK Spinlock);
201DECLASM(void) UNWIND_WRAP(RTSpinlockAcquire)(RTSPINLOCK Spinlock, PRTSPINLOCKTMP pTmp);
202DECLASM(void) UNWIND_WRAP(RTSpinlockRelease)(RTSPINLOCK Spinlock, PRTSPINLOCKTMP pTmp);
203DECLASM(void) UNWIND_WRAP(RTSpinlockAcquireNoInts)(RTSPINLOCK Spinlock, PRTSPINLOCKTMP pTmp);
204DECLASM(void) UNWIND_WRAP(RTSpinlockReleaseNoInts)(RTSPINLOCK Spinlock, PRTSPINLOCKTMP pTmp);
205/* RTTimeNanoTS - not necessary */
206/* RTTimeMilliTS - not necessary */
207/* RTTimeSystemNanoTS - not necessary */
208/* RTTimeSystemMilliTS - not necessary */
209/* RTThreadNativeSelf - not necessary */
210DECLASM(int) UNWIND_WRAP(RTThreadSleep)(unsigned cMillies);
211DECLASM(bool) UNWIND_WRAP(RTThreadYield)(void);
212#if 0
213/* RTThreadSelf - not necessary */
214DECLASM(int) UNWIND_WRAP(RTThreadCreate)(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack,
215 RTTHREADTYPE enmType, unsigned fFlags, const char *pszName);
216DECLASM(RTNATIVETHREAD) UNWIND_WRAP(RTThreadGetNative)(RTTHREAD Thread);
217DECLASM(int) UNWIND_WRAP(RTThreadWait)(RTTHREAD Thread, unsigned cMillies, int *prc);
218DECLASM(int) UNWIND_WRAP(RTThreadWaitNoResume)(RTTHREAD Thread, unsigned cMillies, int *prc);
219DECLASM(const char *) UNWIND_WRAP(RTThreadGetName)(RTTHREAD Thread);
220DECLASM(const char *) UNWIND_WRAP(RTThreadSelfName)(void);
221DECLASM(RTTHREADTYPE) UNWIND_WRAP(RTThreadGetType)(RTTHREAD Thread);
222DECLASM(int) UNWIND_WRAP(RTThreadUserSignal)(RTTHREAD Thread);
223DECLASM(int) UNWIND_WRAP(RTThreadUserReset)(RTTHREAD Thread);
224DECLASM(int) UNWIND_WRAP(RTThreadUserWait)(RTTHREAD Thread, unsigned cMillies);
225DECLASM(int) UNWIND_WRAP(RTThreadUserWaitNoResume)(RTTHREAD Thread, unsigned cMillies);
226#endif
227/* RTThreadPreemptIsEnabled - not necessary */
228/* RTThreadPreemptIsPending - not necessary */
229/* RTThreadPreemptIsPendingTrusty - not necessary */
230DECLASM(void) UNWIND_WRAP(RTThreadPreemptDisable)(PRTTHREADPREEMPTSTATE pState);
231DECLASM(void) UNWIND_WRAP(RTThreadPreemptRestore)(RTTHREADPREEMPTSTATE pState);
232/* RTLogDefaultInstance - a bit of a gamble, but we do not want the overhead! */
233/* RTMpCpuId - not necessary */
234/* RTMpCpuIdFromSetIndex - not necessary */
235/* RTMpCpuIdToSetIndex - not necessary */
236/* RTMpIsCpuPossible - not necessary */
237/* RTMpGetCount - not necessary */
238/* RTMpGetMaxCpuId - not necessary */
239/* RTMpGetOnlineCount - not necessary */
240/* RTMpGetOnlineSet - not necessary */
241/* RTMpGetSet - not necessary */
242/* RTMpIsCpuOnline - not necessary */
243DECLASM(int) UNWIND_WRAP(RTMpIsCpuWorkPending)(void);
244DECLASM(int) UNWIND_WRAP(RTMpOnAll)(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2);
245DECLASM(int) UNWIND_WRAP(RTMpOnOthers)(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2);
246DECLASM(int) UNWIND_WRAP(RTMpOnSpecific)(RTCPUID idCpu, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2);
247DECLASM(int) UNWIND_WRAP(RTMpPokeCpu)(RTCPUID idCpu);
248/* RTLogRelDefaultInstance - not necessary. */
249DECLASM(int) UNWIND_WRAP(RTLogSetDefaultInstanceThread)(PRTLOGGER pLogger, uintptr_t uKey);
250/* RTLogLogger - can't wrap this buster. */
251/* RTLogLoggerEx - can't wrap this buster. */
252DECLASM(void) UNWIND_WRAP(RTLogLoggerExV)(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, va_list args);
253/* RTLogPrintf - can't wrap this buster. */ /** @todo provide va_list log wrappers in RuntimeR0. */
254DECLASM(void) UNWIND_WRAP(RTLogPrintfV)(const char *pszFormat, va_list args);
255DECLASM(void) UNWIND_WRAP(AssertMsg1)(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction);
256/* AssertMsg2 - can't wrap this buster. */
257#endif /* RT_WITH_W64_UNWIND_HACK */
258
259
260/*******************************************************************************
261* Global Variables *
262*******************************************************************************/
263/** Pointer to the global info page for implementing SUPGetGIP(). */
264static PSUPGLOBALINFOPAGE g_pSUPGlobalInfoPageInternal = NULL;
265
266/**
267 * Array of the R0 SUP API.
268 */
269static SUPFUNC g_aFunctions[] =
270{
271 /* name function */
272 /* Entries with absolute addresses determined at runtime, fixup
273 code makes ugly ASSUMPTIONS about the order here: */
274 { "SUPR0AbsIs64bit", (void *)0 },
275 { "SUPR0Abs64bitKernelCS", (void *)0 },
276 { "SUPR0Abs64bitKernelSS", (void *)0 },
277 { "SUPR0Abs64bitKernelDS", (void *)0 },
278 { "SUPR0AbsKernelCS", (void *)0 },
279 { "SUPR0AbsKernelSS", (void *)0 },
280 { "SUPR0AbsKernelDS", (void *)0 },
281 { "SUPR0AbsKernelES", (void *)0 },
282 { "SUPR0AbsKernelFS", (void *)0 },
283 { "SUPR0AbsKernelGS", (void *)0 },
284 /* Normal function pointers: */
285 { "SUPR0ComponentRegisterFactory", (void *)UNWIND_WRAP(SUPR0ComponentRegisterFactory) },
286 { "SUPR0ComponentDeregisterFactory", (void *)UNWIND_WRAP(SUPR0ComponentDeregisterFactory) },
287 { "SUPR0ComponentQueryFactory", (void *)UNWIND_WRAP(SUPR0ComponentQueryFactory) },
288 { "SUPR0ObjRegister", (void *)UNWIND_WRAP(SUPR0ObjRegister) },
289 { "SUPR0ObjAddRef", (void *)UNWIND_WRAP(SUPR0ObjAddRef) },
290 { "SUPR0ObjAddRefEx", (void *)UNWIND_WRAP(SUPR0ObjAddRefEx) },
291 { "SUPR0ObjRelease", (void *)UNWIND_WRAP(SUPR0ObjRelease) },
292 { "SUPR0ObjVerifyAccess", (void *)UNWIND_WRAP(SUPR0ObjVerifyAccess) },
293 { "SUPR0LockMem", (void *)UNWIND_WRAP(SUPR0LockMem) },
294 { "SUPR0UnlockMem", (void *)UNWIND_WRAP(SUPR0UnlockMem) },
295 { "SUPR0ContAlloc", (void *)UNWIND_WRAP(SUPR0ContAlloc) },
296 { "SUPR0ContFree", (void *)UNWIND_WRAP(SUPR0ContFree) },
297 { "SUPR0LowAlloc", (void *)UNWIND_WRAP(SUPR0LowAlloc) },
298 { "SUPR0LowFree", (void *)UNWIND_WRAP(SUPR0LowFree) },
299 { "SUPR0MemAlloc", (void *)UNWIND_WRAP(SUPR0MemAlloc) },
300 { "SUPR0MemGetPhys", (void *)UNWIND_WRAP(SUPR0MemGetPhys) },
301 { "SUPR0MemFree", (void *)UNWIND_WRAP(SUPR0MemFree) },
302 { "SUPR0PageAllocEx", (void *)UNWIND_WRAP(SUPR0PageAllocEx) },
303 { "SUPR0PageFree", (void *)UNWIND_WRAP(SUPR0PageFree) },
304 { "SUPR0Printf", (void *)SUPR0Printf }, /** @todo needs wrapping? */
305 { "SUPSemEventCreate", (void *)UNWIND_WRAP(SUPSemEventCreate) },
306 { "SUPSemEventClose", (void *)UNWIND_WRAP(SUPSemEventClose) },
307 { "SUPSemEventSignal", (void *)UNWIND_WRAP(SUPSemEventSignal) },
308 { "SUPSemEventWait", (void *)UNWIND_WRAP(SUPSemEventWait) },
309 { "SUPSemEventWaitNoResume", (void *)UNWIND_WRAP(SUPSemEventWaitNoResume) },
310 { "SUPSemEventMultiCreate", (void *)UNWIND_WRAP(SUPSemEventMultiCreate) },
311 { "SUPSemEventMultiClose", (void *)UNWIND_WRAP(SUPSemEventMultiClose) },
312 { "SUPSemEventMultiSignal", (void *)UNWIND_WRAP(SUPSemEventMultiSignal) },
313 { "SUPSemEventMultiReset", (void *)UNWIND_WRAP(SUPSemEventMultiReset) },
314 { "SUPSemEventMultiWait", (void *)UNWIND_WRAP(SUPSemEventMultiWait) },
315 { "SUPSemEventMultiWaitNoResume", (void *)UNWIND_WRAP(SUPSemEventMultiWaitNoResume) },
316 { "SUPR0GetPagingMode", (void *)UNWIND_WRAP(SUPR0GetPagingMode) },
317 { "SUPR0EnableVTx", (void *)SUPR0EnableVTx },
318 { "SUPGetGIP", (void *)SUPGetGIP },
319 { "RTMemAlloc", (void *)UNWIND_WRAP(RTMemAlloc) },
320 { "RTMemAllocZ", (void *)UNWIND_WRAP(RTMemAllocZ) },
321 { "RTMemFree", (void *)UNWIND_WRAP(RTMemFree) },
322 /*{ "RTMemDup", (void *)UNWIND_WRAP(RTMemDup) },
323 { "RTMemDupEx", (void *)UNWIND_WRAP(RTMemDupEx) },*/
324 { "RTMemRealloc", (void *)UNWIND_WRAP(RTMemRealloc) },
325 { "RTR0MemObjAllocLow", (void *)UNWIND_WRAP(RTR0MemObjAllocLow) },
326 { "RTR0MemObjAllocPage", (void *)UNWIND_WRAP(RTR0MemObjAllocPage) },
327 { "RTR0MemObjAllocPhys", (void *)UNWIND_WRAP(RTR0MemObjAllocPhys) },
328 { "RTR0MemObjAllocPhysNC", (void *)UNWIND_WRAP(RTR0MemObjAllocPhysNC) },
329 { "RTR0MemObjAllocCont", (void *)UNWIND_WRAP(RTR0MemObjAllocCont) },
330 { "RTR0MemObjEnterPhys", (void *)UNWIND_WRAP(RTR0MemObjEnterPhys) },
331 { "RTR0MemObjLockUser", (void *)UNWIND_WRAP(RTR0MemObjLockUser) },
332 { "RTR0MemObjMapKernel", (void *)UNWIND_WRAP(RTR0MemObjMapKernel) },
333 { "RTR0MemObjMapKernelEx", (void *)UNWIND_WRAP(RTR0MemObjMapKernelEx) },
334 { "RTR0MemObjMapUser", (void *)UNWIND_WRAP(RTR0MemObjMapUser) },
335 { "RTR0MemObjProtect", (void *)UNWIND_WRAP(RTR0MemObjProtect) },
336 { "RTR0MemObjAddress", (void *)RTR0MemObjAddress },
337 { "RTR0MemObjAddressR3", (void *)RTR0MemObjAddressR3 },
338 { "RTR0MemObjSize", (void *)RTR0MemObjSize },
339 { "RTR0MemObjIsMapping", (void *)RTR0MemObjIsMapping },
340 { "RTR0MemObjGetPagePhysAddr", (void *)RTR0MemObjGetPagePhysAddr },
341 { "RTR0MemObjFree", (void *)UNWIND_WRAP(RTR0MemObjFree) },
342 { "RTR0MemUserCopyFrom", (void *)UNWIND_WRAP(RTR0MemUserCopyFrom) },
343 { "RTR0MemUserCopyTo", (void *)UNWIND_WRAP(RTR0MemUserCopyTo) },
344 { "RTR0MemUserIsValidAddr", (void *)RTR0MemUserIsValidAddr },
345 { "RTR0MemKernelIsValidAddr", (void *)RTR0MemKernelIsValidAddr },
346 { "RTR0MemAreKrnlAndUsrDifferent", (void *)RTR0MemAreKrnlAndUsrDifferent },
347/* These don't work yet on linux - use fast mutexes!
348 { "RTSemMutexCreate", (void *)RTSemMutexCreate },
349 { "RTSemMutexRequest", (void *)RTSemMutexRequest },
350 { "RTSemMutexRelease", (void *)RTSemMutexRelease },
351 { "RTSemMutexDestroy", (void *)RTSemMutexDestroy },
352*/
353 { "RTProcSelf", (void *)RTProcSelf },
354 { "RTR0ProcHandleSelf", (void *)RTR0ProcHandleSelf },
355 { "RTSemFastMutexCreate", (void *)UNWIND_WRAP(RTSemFastMutexCreate) },
356 { "RTSemFastMutexDestroy", (void *)UNWIND_WRAP(RTSemFastMutexDestroy) },
357 { "RTSemFastMutexRequest", (void *)UNWIND_WRAP(RTSemFastMutexRequest) },
358 { "RTSemFastMutexRelease", (void *)UNWIND_WRAP(RTSemFastMutexRelease) },
359 { "RTSemEventCreate", (void *)UNWIND_WRAP(RTSemEventCreate) },
360 { "RTSemEventSignal", (void *)UNWIND_WRAP(RTSemEventSignal) },
361 { "RTSemEventWait", (void *)UNWIND_WRAP(RTSemEventWait) },
362 { "RTSemEventWaitNoResume", (void *)UNWIND_WRAP(RTSemEventWaitNoResume) },
363 { "RTSemEventDestroy", (void *)UNWIND_WRAP(RTSemEventDestroy) },
364 { "RTSemEventMultiCreate", (void *)UNWIND_WRAP(RTSemEventMultiCreate) },
365 { "RTSemEventMultiSignal", (void *)UNWIND_WRAP(RTSemEventMultiSignal) },
366 { "RTSemEventMultiReset", (void *)UNWIND_WRAP(RTSemEventMultiReset) },
367 { "RTSemEventMultiWait", (void *)UNWIND_WRAP(RTSemEventMultiWait) },
368 { "RTSemEventMultiWaitNoResume", (void *)UNWIND_WRAP(RTSemEventMultiWaitNoResume) },
369 { "RTSemEventMultiDestroy", (void *)UNWIND_WRAP(RTSemEventMultiDestroy) },
370 { "RTSpinlockCreate", (void *)UNWIND_WRAP(RTSpinlockCreate) },
371 { "RTSpinlockDestroy", (void *)UNWIND_WRAP(RTSpinlockDestroy) },
372 { "RTSpinlockAcquire", (void *)UNWIND_WRAP(RTSpinlockAcquire) },
373 { "RTSpinlockRelease", (void *)UNWIND_WRAP(RTSpinlockRelease) },
374 { "RTSpinlockAcquireNoInts", (void *)UNWIND_WRAP(RTSpinlockAcquireNoInts) },
375 { "RTSpinlockReleaseNoInts", (void *)UNWIND_WRAP(RTSpinlockReleaseNoInts) },
376 { "RTTimeNanoTS", (void *)RTTimeNanoTS },
377 { "RTTimeMilliTS", (void *)RTTimeMilliTS },
378 { "RTTimeSystemNanoTS", (void *)RTTimeSystemNanoTS },
379 { "RTTimeSystemMilliTS", (void *)RTTimeSystemMilliTS },
380 { "RTThreadNativeSelf", (void *)RTThreadNativeSelf },
381 { "RTThreadSleep", (void *)UNWIND_WRAP(RTThreadSleep) },
382 { "RTThreadYield", (void *)UNWIND_WRAP(RTThreadYield) },
383#if 0 /* Thread APIs, Part 2. */
384 { "RTThreadSelf", (void *)UNWIND_WRAP(RTThreadSelf) },
385 { "RTThreadCreate", (void *)UNWIND_WRAP(RTThreadCreate) }, /** @todo need to wrap the callback */
386 { "RTThreadGetNative", (void *)UNWIND_WRAP(RTThreadGetNative) },
387 { "RTThreadWait", (void *)UNWIND_WRAP(RTThreadWait) },
388 { "RTThreadWaitNoResume", (void *)UNWIND_WRAP(RTThreadWaitNoResume) },
389 { "RTThreadGetName", (void *)UNWIND_WRAP(RTThreadGetName) },
390 { "RTThreadSelfName", (void *)UNWIND_WRAP(RTThreadSelfName) },
391 { "RTThreadGetType", (void *)UNWIND_WRAP(RTThreadGetType) },
392 { "RTThreadUserSignal", (void *)UNWIND_WRAP(RTThreadUserSignal) },
393 { "RTThreadUserReset", (void *)UNWIND_WRAP(RTThreadUserReset) },
394 { "RTThreadUserWait", (void *)UNWIND_WRAP(RTThreadUserWait) },
395 { "RTThreadUserWaitNoResume", (void *)UNWIND_WRAP(RTThreadUserWaitNoResume) },
396#endif
397 { "RTThreadPreemptIsEnabled", (void *)RTThreadPreemptIsEnabled },
398 { "RTThreadPreemptIsPending", (void *)RTThreadPreemptIsPending },
399 { "RTThreadPreemptIsPendingTrusty", (void *)RTThreadPreemptIsPendingTrusty },
400 { "RTThreadPreemptIsPossible", (void *)RTThreadPreemptIsPossible },
401 { "RTThreadPreemptDisable", (void *)UNWIND_WRAP(RTThreadPreemptDisable) },
402 { "RTThreadPreemptRestore", (void *)UNWIND_WRAP(RTThreadPreemptRestore) },
403 { "RTThreadIsInInterrupt", (void *)RTThreadIsInInterrupt },
404
405 { "RTLogDefaultInstance", (void *)RTLogDefaultInstance },
406 { "RTMpCpuId", (void *)RTMpCpuId },
407 { "RTMpCpuIdFromSetIndex", (void *)RTMpCpuIdFromSetIndex },
408 { "RTMpCpuIdToSetIndex", (void *)RTMpCpuIdToSetIndex },
409 { "RTMpIsCpuPossible", (void *)RTMpIsCpuPossible },
410 { "RTMpGetCount", (void *)RTMpGetCount },
411 { "RTMpGetMaxCpuId", (void *)RTMpGetMaxCpuId },
412 { "RTMpGetOnlineCount", (void *)RTMpGetOnlineCount },
413 { "RTMpGetOnlineSet", (void *)RTMpGetOnlineSet },
414 { "RTMpGetSet", (void *)RTMpGetSet },
415 { "RTMpIsCpuOnline", (void *)RTMpIsCpuOnline },
416 { "RTMpIsCpuWorkPending", (void *)UNWIND_WRAP(RTMpIsCpuWorkPending) },
417 { "RTMpOnAll", (void *)UNWIND_WRAP(RTMpOnAll) },
418 { "RTMpOnOthers", (void *)UNWIND_WRAP(RTMpOnOthers) },
419 { "RTMpOnSpecific", (void *)UNWIND_WRAP(RTMpOnSpecific) },
420 { "RTMpPokeCpu", (void *)UNWIND_WRAP(RTMpPokeCpu) },
421 { "RTPowerNotificationRegister", (void *)RTPowerNotificationRegister },
422 { "RTPowerNotificationDeregister", (void *)RTPowerNotificationDeregister },
423 { "RTLogRelDefaultInstance", (void *)RTLogRelDefaultInstance },
424 { "RTLogSetDefaultInstanceThread", (void *)UNWIND_WRAP(RTLogSetDefaultInstanceThread) },
425 { "RTLogLogger", (void *)RTLogLogger }, /** @todo remove this */
426 { "RTLogLoggerEx", (void *)RTLogLoggerEx }, /** @todo remove this */
427 { "RTLogLoggerExV", (void *)UNWIND_WRAP(RTLogLoggerExV) },
428 { "RTLogPrintf", (void *)RTLogPrintf }, /** @todo remove this */
429 { "RTLogPrintfV", (void *)UNWIND_WRAP(RTLogPrintfV) },
430 { "AssertMsg1", (void *)UNWIND_WRAP(AssertMsg1) },
431 { "AssertMsg2", (void *)AssertMsg2 }, /** @todo replace this by RTAssertMsg2V */
432#if defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS)
433 { "RTR0AssertPanicSystem", (void *)RTR0AssertPanicSystem },
434#endif
435#if defined(RT_OS_DARWIN)
436 { "RTAssertMsg1", (void *)RTAssertMsg1 },
437 { "RTAssertMsg2", (void *)RTAssertMsg2 },
438 { "RTAssertMsg2V", (void *)RTAssertMsg2V },
439#endif
440};
441
442#if defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
443/**
444 * Drag in the rest of IRPT since we share it with the
445 * rest of the kernel modules on darwin.
446 */
447PFNRT g_apfnVBoxDrvIPRTDeps[] =
448{
449 /* VBoxNetFlt */
450 (PFNRT)RTCrc32,
451 (PFNRT)RTErrConvertFromErrno,
452 (PFNRT)RTNetIPv4IsHdrValid,
453 (PFNRT)RTNetIPv4TCPChecksum,
454 (PFNRT)RTNetIPv4UDPChecksum,
455 (PFNRT)RTUuidCompare,
456 (PFNRT)RTUuidCompareStr,
457 (PFNRT)RTUuidFromStr,
458 (PFNRT)RTStrDup,
459 (PFNRT)RTStrFree,
460 /* VBoxNetAdp */
461 (PFNRT)RTRandBytes,
462 /* VBoxUSB */
463 (PFNRT)RTPathStripFilename,
464 NULL
465};
466#endif /* RT_OS_DARWIN || RT_OS_SOLARIS || RT_OS_SOLARIS */
467
468
469/**
470 * Initializes the device extentsion structure.
471 *
472 * @returns IPRT status code.
473 * @param pDevExt The device extension to initialize.
474 */
475int VBOXCALL supdrvInitDevExt(PSUPDRVDEVEXT pDevExt)
476{
477 int rc;
478
479#ifdef SUPDRV_WITH_RELEASE_LOGGER
480 /*
481 * Create the release log.
482 */
483 static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
484 PRTLOGGER pRelLogger;
485 rc = RTLogCreate(&pRelLogger, 0 /* fFlags */, "all",
486 "VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups,
487 RTLOGDEST_STDOUT | RTLOGDEST_DEBUGGER, NULL);
488 if (RT_SUCCESS(rc))
489 RTLogRelSetDefaultInstance(pRelLogger);
490 /** @todo Add native hook for getting logger config parameters and setting
491 * them. On linux we should use the module parameter stuff... */
492#endif
493
494 /*
495 * Initialize it.
496 */
497 memset(pDevExt, 0, sizeof(*pDevExt));
498 rc = RTSpinlockCreate(&pDevExt->Spinlock);
499 if (!rc)
500 {
501 rc = RTSemFastMutexCreate(&pDevExt->mtxLdr);
502 if (!rc)
503 {
504 rc = RTSemFastMutexCreate(&pDevExt->mtxComponentFactory);
505 if (!rc)
506 {
507 rc = RTSemFastMutexCreate(&pDevExt->mtxGip);
508 if (!rc)
509 {
510 rc = supdrvGipCreate(pDevExt);
511 if (RT_SUCCESS(rc))
512 {
513 pDevExt->u32Cookie = BIRD; /** @todo make this random? */
514
515 /*
516 * Fixup the absolute symbols.
517 *
518 * Because of the table indexing assumptions we'll have a little #ifdef orgy
519 * here rather than distributing this to OS specific files. At least for now.
520 */
521#ifdef RT_OS_DARWIN
522# if ARCH_BITS == 32
523 if (SUPR0GetPagingMode() >= SUPPAGINGMODE_AMD64)
524 {
525 g_aFunctions[0].pfn = (void *)1; /* SUPR0AbsIs64bit */
526 g_aFunctions[1].pfn = (void *)0x80; /* SUPR0Abs64bitKernelCS - KERNEL64_CS, seg.h */
527 g_aFunctions[2].pfn = (void *)0x88; /* SUPR0Abs64bitKernelSS - KERNEL64_SS, seg.h */
528 g_aFunctions[3].pfn = (void *)0x88; /* SUPR0Abs64bitKernelDS - KERNEL64_SS, seg.h */
529 }
530 else
531 g_aFunctions[0].pfn = g_aFunctions[1].pfn = g_aFunctions[2].pfn = g_aFunctions[4].pfn = (void *)0;
532 g_aFunctions[4].pfn = (void *)0x08; /* SUPR0AbsKernelCS - KERNEL_CS, seg.h */
533 g_aFunctions[5].pfn = (void *)0x10; /* SUPR0AbsKernelSS - KERNEL_DS, seg.h */
534 g_aFunctions[6].pfn = (void *)0x10; /* SUPR0AbsKernelDS - KERNEL_DS, seg.h */
535 g_aFunctions[7].pfn = (void *)0x10; /* SUPR0AbsKernelES - KERNEL_DS, seg.h */
536 g_aFunctions[8].pfn = (void *)0x10; /* SUPR0AbsKernelFS - KERNEL_DS, seg.h */
537 g_aFunctions[9].pfn = (void *)0x48; /* SUPR0AbsKernelGS - CPU_DATA_GS, seg.h */
538# else /* 64-bit darwin: */
539 g_aFunctions[0].pfn = (void *)1; /* SUPR0AbsIs64bit */
540 g_aFunctions[1].pfn = (void *)(uintptr_t)ASMGetCS(); /* SUPR0Abs64bitKernelCS */
541 g_aFunctions[2].pfn = (void *)(uintptr_t)ASMGetSS(); /* SUPR0Abs64bitKernelSS */
542 g_aFunctions[3].pfn = (void *)0; /* SUPR0Abs64bitKernelDS */
543 g_aFunctions[4].pfn = (void *)(uintptr_t)ASMGetCS(); /* SUPR0AbsKernelCS */
544 g_aFunctions[5].pfn = (void *)(uintptr_t)ASMGetSS(); /* SUPR0AbsKernelSS */
545 g_aFunctions[6].pfn = (void *)0; /* SUPR0AbsKernelDS */
546 g_aFunctions[7].pfn = (void *)0; /* SUPR0AbsKernelES */
547 g_aFunctions[8].pfn = (void *)0; /* SUPR0AbsKernelFS */
548 g_aFunctions[9].pfn = (void *)0; /* SUPR0AbsKernelGS */
549
550# endif
551#else /* !RT_OS_DARWIN */
552# if ARCH_BITS == 64
553 g_aFunctions[0].pfn = (void *)1; /* SUPR0AbsIs64bit */
554 g_aFunctions[1].pfn = (void *)(uintptr_t)ASMGetCS(); /* SUPR0Abs64bitKernelCS */
555 g_aFunctions[2].pfn = (void *)(uintptr_t)ASMGetSS(); /* SUPR0Abs64bitKernelSS */
556 g_aFunctions[3].pfn = (void *)(uintptr_t)ASMGetDS(); /* SUPR0Abs64bitKernelDS */
557# else
558 g_aFunctions[0].pfn = g_aFunctions[1].pfn = g_aFunctions[2].pfn = g_aFunctions[4].pfn = (void *)0;
559# endif
560 g_aFunctions[4].pfn = (void *)(uintptr_t)ASMGetCS(); /* SUPR0AbsKernelCS */
561 g_aFunctions[5].pfn = (void *)(uintptr_t)ASMGetSS(); /* SUPR0AbsKernelSS */
562 g_aFunctions[6].pfn = (void *)(uintptr_t)ASMGetDS(); /* SUPR0AbsKernelDS */
563 g_aFunctions[7].pfn = (void *)(uintptr_t)ASMGetES(); /* SUPR0AbsKernelES */
564 g_aFunctions[8].pfn = (void *)(uintptr_t)ASMGetFS(); /* SUPR0AbsKernelFS */
565 g_aFunctions[9].pfn = (void *)(uintptr_t)ASMGetGS(); /* SUPR0AbsKernelGS */
566#endif /* !RT_OS_DARWIN */
567 return VINF_SUCCESS;
568 }
569
570 RTSemFastMutexDestroy(pDevExt->mtxGip);
571 pDevExt->mtxGip = NIL_RTSEMFASTMUTEX;
572 }
573 RTSemFastMutexDestroy(pDevExt->mtxComponentFactory);
574 pDevExt->mtxComponentFactory = NIL_RTSEMFASTMUTEX;
575 }
576 RTSemFastMutexDestroy(pDevExt->mtxLdr);
577 pDevExt->mtxLdr = NIL_RTSEMFASTMUTEX;
578 }
579 RTSpinlockDestroy(pDevExt->Spinlock);
580 pDevExt->Spinlock = NIL_RTSPINLOCK;
581 }
582#ifdef SUPDRV_WITH_RELEASE_LOGGER
583 RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
584 RTLogDestroy(RTLogSetDefaultInstance(NULL));
585#endif
586
587 return rc;
588}
589
590
591/**
592 * Delete the device extension (e.g. cleanup members).
593 *
594 * @param pDevExt The device extension to delete.
595 */
596void VBOXCALL supdrvDeleteDevExt(PSUPDRVDEVEXT pDevExt)
597{
598 PSUPDRVOBJ pObj;
599 PSUPDRVUSAGE pUsage;
600
601 /*
602 * Kill mutexes and spinlocks.
603 */
604 RTSemFastMutexDestroy(pDevExt->mtxGip);
605 pDevExt->mtxGip = NIL_RTSEMFASTMUTEX;
606 RTSemFastMutexDestroy(pDevExt->mtxLdr);
607 pDevExt->mtxLdr = NIL_RTSEMFASTMUTEX;
608 RTSpinlockDestroy(pDevExt->Spinlock);
609 pDevExt->Spinlock = NIL_RTSPINLOCK;
610 RTSemFastMutexDestroy(pDevExt->mtxComponentFactory);
611 pDevExt->mtxComponentFactory = NIL_RTSEMFASTMUTEX;
612
613 /*
614 * Free lists.
615 */
616 /* objects. */
617 pObj = pDevExt->pObjs;
618#if !defined(DEBUG_bird) || !defined(RT_OS_LINUX) /* breaks unloading, temporary, remove me! */
619 Assert(!pObj); /* (can trigger on forced unloads) */
620#endif
621 pDevExt->pObjs = NULL;
622 while (pObj)
623 {
624 void *pvFree = pObj;
625 pObj = pObj->pNext;
626 RTMemFree(pvFree);
627 }
628
629 /* usage records. */
630 pUsage = pDevExt->pUsageFree;
631 pDevExt->pUsageFree = NULL;
632 while (pUsage)
633 {
634 void *pvFree = pUsage;
635 pUsage = pUsage->pNext;
636 RTMemFree(pvFree);
637 }
638
639 /* kill the GIP. */
640 supdrvGipDestroy(pDevExt);
641
642#ifdef SUPDRV_WITH_RELEASE_LOGGER
643 /* destroy the loggers. */
644 RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
645 RTLogDestroy(RTLogSetDefaultInstance(NULL));
646#endif
647}
648
649
650/**
651 * Create session.
652 *
653 * @returns IPRT status code.
654 * @param pDevExt Device extension.
655 * @param fUser Flag indicating whether this is a user or kernel session.
656 * @param ppSession Where to store the pointer to the session data.
657 */
658int VBOXCALL supdrvCreateSession(PSUPDRVDEVEXT pDevExt, bool fUser, PSUPDRVSESSION *ppSession)
659{
660 /*
661 * Allocate memory for the session data.
662 */
663 int rc = VERR_NO_MEMORY;
664 PSUPDRVSESSION pSession = *ppSession = (PSUPDRVSESSION)RTMemAllocZ(sizeof(*pSession));
665 if (pSession)
666 {
667 /* Initialize session data. */
668 rc = RTSpinlockCreate(&pSession->Spinlock);
669 if (!rc)
670 {
671 rc = RTHandleTableCreateEx(&pSession->hHandleTable,
672 RTHANDLETABLE_FLAGS_LOCKED | RTHANDLETABLE_FLAGS_CONTEXT,
673 1 /*uBase*/, 32768 /*cMax*/, supdrvSessionObjHandleRetain, pSession);
674 if (RT_SUCCESS(rc))
675 {
676 Assert(pSession->Spinlock != NIL_RTSPINLOCK);
677 pSession->pDevExt = pDevExt;
678 pSession->u32Cookie = BIRD_INV;
679 /*pSession->pLdrUsage = NULL;
680 pSession->pVM = NULL;
681 pSession->pUsage = NULL;
682 pSession->pGip = NULL;
683 pSession->fGipReferenced = false;
684 pSession->Bundle.cUsed = 0; */
685 pSession->Uid = NIL_RTUID;
686 pSession->Gid = NIL_RTGID;
687 if (fUser)
688 {
689 pSession->Process = RTProcSelf();
690 pSession->R0Process = RTR0ProcHandleSelf();
691 }
692 else
693 {
694 pSession->Process = NIL_RTPROCESS;
695 pSession->R0Process = NIL_RTR0PROCESS;
696 }
697
698 LogFlow(("Created session %p initial cookie=%#x\n", pSession, pSession->u32Cookie));
699 return VINF_SUCCESS;
700 }
701
702 RTSpinlockDestroy(pSession->Spinlock);
703 }
704 RTMemFree(pSession);
705 *ppSession = NULL;
706 Log(("Failed to create spinlock, rc=%d!\n", rc));
707 }
708
709 return rc;
710}
711
712
713/**
714 * Shared code for cleaning up a session.
715 *
716 * @param pDevExt Device extension.
717 * @param pSession Session data.
718 * This data will be freed by this routine.
719 */
720void VBOXCALL supdrvCloseSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
721{
722 /*
723 * Cleanup the session first.
724 */
725 supdrvCleanupSession(pDevExt, pSession);
726
727 /*
728 * Free the rest of the session stuff.
729 */
730 RTSpinlockDestroy(pSession->Spinlock);
731 pSession->Spinlock = NIL_RTSPINLOCK;
732 pSession->pDevExt = NULL;
733 RTMemFree(pSession);
734 LogFlow(("supdrvCloseSession: returns\n"));
735}
736
737
738/**
739 * Shared code for cleaning up a session (but not quite freeing it).
740 *
741 * This is primarily intended for MAC OS X where we have to clean up the memory
742 * stuff before the file handle is closed.
743 *
744 * @param pDevExt Device extension.
745 * @param pSession Session data.
746 * This data will be freed by this routine.
747 */
748void VBOXCALL supdrvCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
749{
750 int rc;
751 PSUPDRVBUNDLE pBundle;
752 LogFlow(("supdrvCleanupSession: pSession=%p\n", pSession));
753
754 /*
755 * Remove logger instances related to this session.
756 */
757 RTLogSetDefaultInstanceThread(NULL, (uintptr_t)pSession);
758
759 /*
760 * Destroy the handle table.
761 */
762 rc = RTHandleTableDestroy(pSession->hHandleTable, supdrvSessionObjHandleDelete, pSession);
763 AssertRC(rc);
764 pSession->hHandleTable = NIL_RTHANDLETABLE;
765
766 /*
767 * Release object references made in this session.
768 * In theory there should be noone racing us in this session.
769 */
770 Log2(("release objects - start\n"));
771 if (pSession->pUsage)
772 {
773 RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
774 PSUPDRVUSAGE pUsage;
775 RTSpinlockAcquire(pDevExt->Spinlock, &SpinlockTmp);
776
777 while ((pUsage = pSession->pUsage) != NULL)
778 {
779 PSUPDRVOBJ pObj = pUsage->pObj;
780 pSession->pUsage = pUsage->pNext;
781
782 AssertMsg(pUsage->cUsage >= 1 && pObj->cUsage >= pUsage->cUsage, ("glob %d; sess %d\n", pObj->cUsage, pUsage->cUsage));
783 if (pUsage->cUsage < pObj->cUsage)
784 {
785 pObj->cUsage -= pUsage->cUsage;
786 RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
787 }
788 else
789 {
790 /* Destroy the object and free the record. */
791 if (pDevExt->pObjs == pObj)
792 pDevExt->pObjs = pObj->pNext;
793 else
794 {
795 PSUPDRVOBJ pObjPrev;
796 for (pObjPrev = pDevExt->pObjs; pObjPrev; pObjPrev = pObjPrev->pNext)
797 if (pObjPrev->pNext == pObj)
798 {
799 pObjPrev->pNext = pObj->pNext;
800 break;
801 }
802 Assert(pObjPrev);
803 }
804 RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
805
806 Log(("supdrvCleanupSession: destroying %p/%d (%p/%p) cpid=%RTproc pid=%RTproc dtor=%p\n",
807 pObj, pObj->enmType, pObj->pvUser1, pObj->pvUser2, pObj->CreatorProcess, RTProcSelf(), pObj->pfnDestructor));
808 if (pObj->pfnDestructor)
809#ifdef RT_WITH_W64_UNWIND_HACK
810 supdrvNtWrapObjDestructor((PFNRT)pObj->pfnDestructor, pObj, pObj->pvUser1, pObj->pvUser2);
811#else
812 pObj->pfnDestructor(pObj, pObj->pvUser1, pObj->pvUser2);
813#endif
814 RTMemFree(pObj);
815 }
816
817 /* free it and continue. */
818 RTMemFree(pUsage);
819
820 RTSpinlockAcquire(pDevExt->Spinlock, &SpinlockTmp);
821 }
822
823 RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
824 AssertMsg(!pSession->pUsage, ("Some buster reregistered an object during desturction!\n"));
825 }
826 Log2(("release objects - done\n"));
827
828 /*
829 * Release memory allocated in the session.
830 *
831 * We do not serialize this as we assume that the application will
832 * not allocated memory while closing the file handle object.
833 */
834 Log2(("freeing memory:\n"));
835 pBundle = &pSession->Bundle;
836 while (pBundle)
837 {
838 PSUPDRVBUNDLE pToFree;
839 unsigned i;
840
841 /*
842 * Check and unlock all entries in the bundle.
843 */
844 for (i = 0; i < RT_ELEMENTS(pBundle->aMem); i++)
845 {
846 if (pBundle->aMem[i].MemObj != NIL_RTR0MEMOBJ)
847 {
848 Log2(("eType=%d pvR0=%p pvR3=%p cb=%ld\n", pBundle->aMem[i].eType, RTR0MemObjAddress(pBundle->aMem[i].MemObj),
849 (void *)RTR0MemObjAddressR3(pBundle->aMem[i].MapObjR3), (long)RTR0MemObjSize(pBundle->aMem[i].MemObj)));
850 if (pBundle->aMem[i].MapObjR3 != NIL_RTR0MEMOBJ)
851 {
852 rc = RTR0MemObjFree(pBundle->aMem[i].MapObjR3, false);
853 AssertRC(rc); /** @todo figure out how to handle this. */
854 pBundle->aMem[i].MapObjR3 = NIL_RTR0MEMOBJ;
855 }
856 rc = RTR0MemObjFree(pBundle->aMem[i].MemObj, true /* fFreeMappings */);
857 AssertRC(rc); /** @todo figure out how to handle this. */
858 pBundle->aMem[i].MemObj = NIL_RTR0MEMOBJ;
859 pBundle->aMem[i].eType = MEMREF_TYPE_UNUSED;
860 }
861 }
862
863 /*
864 * Advance and free previous bundle.
865 */
866 pToFree = pBundle;
867 pBundle = pBundle->pNext;
868
869 pToFree->pNext = NULL;
870 pToFree->cUsed = 0;
871 if (pToFree != &pSession->Bundle)
872 RTMemFree(pToFree);
873 }
874 Log2(("freeing memory - done\n"));
875
876 /*
877 * Deregister component factories.
878 */
879 RTSemFastMutexRequest(pDevExt->mtxComponentFactory);
880 Log2(("deregistering component factories:\n"));
881 if (pDevExt->pComponentFactoryHead)
882 {
883 PSUPDRVFACTORYREG pPrev = NULL;
884 PSUPDRVFACTORYREG pCur = pDevExt->pComponentFactoryHead;
885 while (pCur)
886 {
887 if (pCur->pSession == pSession)
888 {
889 /* unlink it */
890 PSUPDRVFACTORYREG pNext = pCur->pNext;
891 if (pPrev)
892 pPrev->pNext = pNext;
893 else
894 pDevExt->pComponentFactoryHead = pNext;
895
896 /* free it */
897 pCur->pNext = NULL;
898 pCur->pSession = NULL;
899 pCur->pFactory = NULL;
900 RTMemFree(pCur);
901
902 /* next */
903 pCur = pNext;
904 }
905 else
906 {
907 /* next */
908 pPrev = pCur;
909 pCur = pCur->pNext;
910 }
911 }
912 }
913 RTSemFastMutexRelease(pDevExt->mtxComponentFactory);
914 Log2(("deregistering component factories - done\n"));
915
916 /*
917 * Loaded images needs to be dereferenced and possibly freed up.
918 */
919 RTSemFastMutexRequest(pDevExt->mtxLdr);
920 Log2(("freeing images:\n"));
921 if (pSession->pLdrUsage)
922 {
923 PSUPDRVLDRUSAGE pUsage = pSession->pLdrUsage;
924 pSession->pLdrUsage = NULL;
925 while (pUsage)
926 {
927 void *pvFree = pUsage;
928 PSUPDRVLDRIMAGE pImage = pUsage->pImage;
929 if (pImage->cUsage > pUsage->cUsage)
930 pImage->cUsage -= pUsage->cUsage;
931 else
932 supdrvLdrFree(pDevExt, pImage);
933 pUsage->pImage = NULL;
934 pUsage = pUsage->pNext;
935 RTMemFree(pvFree);
936 }
937 }
938 RTSemFastMutexRelease(pDevExt->mtxLdr);
939 Log2(("freeing images - done\n"));
940
941 /*
942 * Unmap the GIP.
943 */
944 Log2(("umapping GIP:\n"));
945 if (pSession->GipMapObjR3 != NIL_RTR0MEMOBJ)
946 {
947 SUPR0GipUnmap(pSession);
948 pSession->fGipReferenced = 0;
949 }
950 Log2(("umapping GIP - done\n"));
951}
952
953
954/**
955 * RTHandleTableDestroy callback used by supdrvCleanupSession.
956 *
957 * @returns IPRT status code, see SUPR0ObjAddRef.
958 * @param hHandleTable The handle table handle. Ignored.
959 * @param pvObj The object pointer.
960 * @param pvCtx Context, the handle type. Ignored.
961 * @param pvUser Session pointer.
962 */
963static DECLCALLBACK(int) supdrvSessionObjHandleRetain(RTHANDLETABLE hHandleTable, void *pvObj, void *pvCtx, void *pvUser)
964{
965 NOREF(pvCtx);
966 NOREF(hHandleTable);
967 return SUPR0ObjAddRefEx(pvObj, (PSUPDRVSESSION)pvUser, true /*fNoBlocking*/);
968}
969
970
971/**
972 * RTHandleTableDestroy callback used by supdrvCleanupSession.
973 *
974 * @param hHandleTable The handle table handle. Ignored.
975 * @param h The handle value. Ignored.
976 * @param pvObj The object pointer.
977 * @param pvCtx Context, the handle type. Ignored.
978 * @param pvUser Session pointer.
979 */
980static DECLCALLBACK(void) supdrvSessionObjHandleDelete(RTHANDLETABLE hHandleTable, uint32_t h, void *pvObj, void *pvCtx, void *pvUser)
981{
982 NOREF(pvCtx);
983 NOREF(h);
984 NOREF(hHandleTable);
985 SUPR0ObjRelease(pvObj, (PSUPDRVSESSION)pvUser);
986}
987
988
989/**
990 * Fast path I/O Control worker.
991 *
992 * @returns VBox status code that should be passed down to ring-3 unchanged.
993 * @param uIOCtl Function number.
994 * @param idCpu VMCPU id.
995 * @param pDevExt Device extention.
996 * @param pSession Session data.
997 */
998int VBOXCALL supdrvIOCtlFast(uintptr_t uIOCtl, VMCPUID idCpu, PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
999{
1000 /*
1001 * We check the two prereqs after doing this only to allow the compiler to optimize things better.
1002 */
1003 if (RT_LIKELY(pSession->pVM && pDevExt->pfnVMMR0EntryFast))
1004 {
1005 switch (uIOCtl)
1006 {
1007 case SUP_IOCTL_FAST_DO_RAW_RUN:
1008#ifdef RT_WITH_W64_UNWIND_HACK
1009 supdrvNtWrapVMMR0EntryFast((PFNRT)pDevExt->pfnVMMR0EntryFast, pSession->pVM, idCpu, SUP_VMMR0_DO_RAW_RUN);
1010#else
1011 pDevExt->pfnVMMR0EntryFast(pSession->pVM, idCpu, SUP_VMMR0_DO_RAW_RUN);
1012#endif
1013 break;
1014 case SUP_IOCTL_FAST_DO_HWACC_RUN:
1015#ifdef RT_WITH_W64_UNWIND_HACK
1016 supdrvNtWrapVMMR0EntryFast((PFNRT)pDevExt->pfnVMMR0EntryFast, pSession->pVM, idCpu, SUP_VMMR0_DO_HWACC_RUN);
1017#else
1018 pDevExt->pfnVMMR0EntryFast(pSession->pVM, idCpu, SUP_VMMR0_DO_HWACC_RUN);
1019#endif
1020 break;
1021 case SUP_IOCTL_FAST_DO_NOP:
1022#ifdef RT_WITH_W64_UNWIND_HACK
1023 supdrvNtWrapVMMR0EntryFast((PFNRT)pDevExt->pfnVMMR0EntryFast, pSession->pVM, idCpu, SUP_VMMR0_DO_NOP);
1024#else
1025 pDevExt->pfnVMMR0EntryFast(pSession->pVM, idCpu, SUP_VMMR0_DO_NOP);
1026#endif
1027 break;
1028 default:
1029 return VERR_INTERNAL_ERROR;
1030 }
1031 return VINF_SUCCESS;
1032 }
1033 return VERR_INTERNAL_ERROR;
1034}
1035
1036
1037/**
1038 * Helper for supdrvIOCtl. Check if pszStr contains any character of pszChars.
1039 * We would use strpbrk here if this function would be contained in the RedHat kABI white
1040 * list, see http://www.kerneldrivers.org/RHEL5.
1041 *
1042 * @return 1 if pszStr does contain any character of pszChars, 0 otherwise.
1043 * @param pszStr String to check
1044 * @param pszChars Character set
1045 */
1046static int supdrvCheckInvalidChar(const char *pszStr, const char *pszChars)
1047{
1048 int chCur;
1049 while ((chCur = *pszStr++) != '\0')
1050 {
1051 int ch;
1052 const char *psz = pszChars;
1053 while ((ch = *psz++) != '\0')
1054 if (ch == chCur)
1055 return 1;
1056
1057 }
1058 return 0;
1059}
1060
1061
1062/**
1063 * I/O Control worker.
1064 *
1065 * @returns 0 on success.
1066 * @returns VERR_INVALID_PARAMETER if the request is invalid.
1067 *
1068 * @param uIOCtl Function number.
1069 * @param pDevExt Device extention.
1070 * @param pSession Session data.
1071 * @param pReqHdr The request header.
1072 */
1073int VBOXCALL supdrvIOCtl(uintptr_t uIOCtl, PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPREQHDR pReqHdr)
1074{
1075 /*
1076 * Validate the request.
1077 */
1078 /* this first check could probably be omitted as its also done by the OS specific code... */
1079 if (RT_UNLIKELY( (pReqHdr->fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC
1080 || pReqHdr->cbIn < sizeof(*pReqHdr)
1081 || pReqHdr->cbOut < sizeof(*pReqHdr)))
1082 {
1083 OSDBGPRINT(("vboxdrv: Bad ioctl request header; cbIn=%#lx cbOut=%#lx fFlags=%#lx\n",
1084 (long)pReqHdr->cbIn, (long)pReqHdr->cbOut, (long)pReqHdr->fFlags));
1085 return VERR_INVALID_PARAMETER;
1086 }
1087 if (RT_UNLIKELY(uIOCtl == SUP_IOCTL_COOKIE))
1088 {
1089 if (pReqHdr->u32Cookie != SUPCOOKIE_INITIAL_COOKIE)
1090 {
1091 OSDBGPRINT(("SUP_IOCTL_COOKIE: bad cookie %#lx\n", (long)pReqHdr->u32Cookie));
1092 return VERR_INVALID_PARAMETER;
1093 }
1094 }
1095 else if (RT_UNLIKELY( pReqHdr->u32Cookie != pDevExt->u32Cookie
1096 || pReqHdr->u32SessionCookie != pSession->u32Cookie))
1097 {
1098 OSDBGPRINT(("vboxdrv: bad cookie %#lx / %#lx.\n", (long)pReqHdr->u32Cookie, (long)pReqHdr->u32SessionCookie));
1099 return VERR_INVALID_PARAMETER;
1100 }
1101
1102/*
1103 * Validation macros
1104 */
1105#define REQ_CHECK_SIZES_EX(Name, cbInExpect, cbOutExpect) \
1106 do { \
1107 if (RT_UNLIKELY(pReqHdr->cbIn != (cbInExpect) || pReqHdr->cbOut != (cbOutExpect))) \
1108 { \
1109 OSDBGPRINT(( #Name ": Invalid input/output sizes. cbIn=%ld expected %ld. cbOut=%ld expected %ld.\n", \
1110 (long)pReq->Hdr.cbIn, (long)(cbInExpect), (long)pReq->Hdr.cbOut, (long)(cbOutExpect))); \
1111 return pReq->Hdr.rc = VERR_INVALID_PARAMETER; \
1112 } \
1113 } while (0)
1114
1115#define REQ_CHECK_SIZES(Name) REQ_CHECK_SIZES_EX(Name, Name ## _SIZE_IN, Name ## _SIZE_OUT)
1116
1117#define REQ_CHECK_SIZE_IN(Name, cbInExpect) \
1118 do { \
1119 if (RT_UNLIKELY(pReqHdr->cbIn != (cbInExpect))) \
1120 { \
1121 OSDBGPRINT(( #Name ": Invalid input/output sizes. cbIn=%ld expected %ld.\n", \
1122 (long)pReq->Hdr.cbIn, (long)(cbInExpect))); \
1123 return pReq->Hdr.rc = VERR_INVALID_PARAMETER; \
1124 } \
1125 } while (0)
1126
1127#define REQ_CHECK_SIZE_OUT(Name, cbOutExpect) \
1128 do { \
1129 if (RT_UNLIKELY(pReqHdr->cbOut != (cbOutExpect))) \
1130 { \
1131 OSDBGPRINT(( #Name ": Invalid input/output sizes. cbOut=%ld expected %ld.\n", \
1132 (long)pReq->Hdr.cbOut, (long)(cbOutExpect))); \
1133 return pReq->Hdr.rc = VERR_INVALID_PARAMETER; \
1134 } \
1135 } while (0)
1136
1137#define REQ_CHECK_EXPR(Name, expr) \
1138 do { \
1139 if (RT_UNLIKELY(!(expr))) \
1140 { \
1141 OSDBGPRINT(( #Name ": %s\n", #expr)); \
1142 return pReq->Hdr.rc = VERR_INVALID_PARAMETER; \
1143 } \
1144 } while (0)
1145
1146#define REQ_CHECK_EXPR_FMT(expr, fmt) \
1147 do { \
1148 if (RT_UNLIKELY(!(expr))) \
1149 { \
1150 OSDBGPRINT( fmt ); \
1151 return pReq->Hdr.rc = VERR_INVALID_PARAMETER; \
1152 } \
1153 } while (0)
1154
1155
1156 /*
1157 * The switch.
1158 */
1159 switch (SUP_CTL_CODE_NO_SIZE(uIOCtl))
1160 {
1161 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_COOKIE):
1162 {
1163 PSUPCOOKIE pReq = (PSUPCOOKIE)pReqHdr;
1164 REQ_CHECK_SIZES(SUP_IOCTL_COOKIE);
1165 if (strncmp(pReq->u.In.szMagic, SUPCOOKIE_MAGIC, sizeof(pReq->u.In.szMagic)))
1166 {
1167 OSDBGPRINT(("SUP_IOCTL_COOKIE: invalid magic %.16s\n", pReq->u.In.szMagic));
1168 pReq->Hdr.rc = VERR_INVALID_MAGIC;
1169 return 0;
1170 }
1171
1172#if 0
1173 /*
1174 * Call out to the OS specific code and let it do permission checks on the
1175 * client process.
1176 */
1177 if (!supdrvOSValidateClientProcess(pDevExt, pSession))
1178 {
1179 pReq->u.Out.u32Cookie = 0xffffffff;
1180 pReq->u.Out.u32SessionCookie = 0xffffffff;
1181 pReq->u.Out.u32SessionVersion = 0xffffffff;
1182 pReq->u.Out.u32DriverVersion = SUPDRV_IOC_VERSION;
1183 pReq->u.Out.pSession = NULL;
1184 pReq->u.Out.cFunctions = 0;
1185 pReq->Hdr.rc = VERR_PERMISSION_DENIED;
1186 return 0;
1187 }
1188#endif
1189
1190 /*
1191 * Match the version.
1192 * The current logic is very simple, match the major interface version.
1193 */
1194 if ( pReq->u.In.u32MinVersion > SUPDRV_IOC_VERSION
1195 || (pReq->u.In.u32MinVersion & 0xffff0000) != (SUPDRV_IOC_VERSION & 0xffff0000))
1196 {
1197 OSDBGPRINT(("SUP_IOCTL_COOKIE: Version mismatch. Requested: %#x Min: %#x Current: %#x\n",
1198 pReq->u.In.u32ReqVersion, pReq->u.In.u32MinVersion, SUPDRV_IOC_VERSION));
1199 pReq->u.Out.u32Cookie = 0xffffffff;
1200 pReq->u.Out.u32SessionCookie = 0xffffffff;
1201 pReq->u.Out.u32SessionVersion = 0xffffffff;
1202 pReq->u.Out.u32DriverVersion = SUPDRV_IOC_VERSION;
1203 pReq->u.Out.pSession = NULL;
1204 pReq->u.Out.cFunctions = 0;
1205 pReq->Hdr.rc = VERR_VERSION_MISMATCH;
1206 return 0;
1207 }
1208
1209 /*
1210 * Fill in return data and be gone.
1211 * N.B. The first one to change SUPDRV_IOC_VERSION shall makes sure that
1212 * u32SessionVersion <= u32ReqVersion!
1213 */
1214 /** @todo Somehow validate the client and negotiate a secure cookie... */
1215 pReq->u.Out.u32Cookie = pDevExt->u32Cookie;
1216 pReq->u.Out.u32SessionCookie = pSession->u32Cookie;
1217 pReq->u.Out.u32SessionVersion = SUPDRV_IOC_VERSION;
1218 pReq->u.Out.u32DriverVersion = SUPDRV_IOC_VERSION;
1219 pReq->u.Out.pSession = pSession;
1220 pReq->u.Out.cFunctions = sizeof(g_aFunctions) / sizeof(g_aFunctions[0]);
1221 pReq->Hdr.rc = VINF_SUCCESS;
1222 return 0;
1223 }
1224
1225 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_QUERY_FUNCS(0)):
1226 {
1227 /* validate */
1228 PSUPQUERYFUNCS pReq = (PSUPQUERYFUNCS)pReqHdr;
1229 REQ_CHECK_SIZES_EX(SUP_IOCTL_QUERY_FUNCS, SUP_IOCTL_QUERY_FUNCS_SIZE_IN, SUP_IOCTL_QUERY_FUNCS_SIZE_OUT(RT_ELEMENTS(g_aFunctions)));
1230
1231 /* execute */
1232 pReq->u.Out.cFunctions = RT_ELEMENTS(g_aFunctions);
1233 memcpy(&pReq->u.Out.aFunctions[0], g_aFunctions, sizeof(g_aFunctions));
1234 pReq->Hdr.rc = VINF_SUCCESS;
1235 return 0;
1236 }
1237
1238 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_PAGE_LOCK):
1239 {
1240 /* validate */
1241 PSUPPAGELOCK pReq = (PSUPPAGELOCK)pReqHdr;
1242 REQ_CHECK_SIZE_IN(SUP_IOCTL_PAGE_LOCK, SUP_IOCTL_PAGE_LOCK_SIZE_IN);
1243 REQ_CHECK_SIZE_OUT(SUP_IOCTL_PAGE_LOCK, SUP_IOCTL_PAGE_LOCK_SIZE_OUT(pReq->u.In.cPages));
1244 REQ_CHECK_EXPR(SUP_IOCTL_PAGE_LOCK, pReq->u.In.cPages > 0);
1245 REQ_CHECK_EXPR(SUP_IOCTL_PAGE_LOCK, pReq->u.In.pvR3 >= PAGE_SIZE);
1246
1247 /* execute */
1248 pReq->Hdr.rc = SUPR0LockMem(pSession, pReq->u.In.pvR3, pReq->u.In.cPages, &pReq->u.Out.aPages[0]);
1249 if (RT_FAILURE(pReq->Hdr.rc))
1250 pReq->Hdr.cbOut = sizeof(pReq->Hdr);
1251 return 0;
1252 }
1253
1254 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_PAGE_UNLOCK):
1255 {
1256 /* validate */
1257 PSUPPAGEUNLOCK pReq = (PSUPPAGEUNLOCK)pReqHdr;
1258 REQ_CHECK_SIZES(SUP_IOCTL_PAGE_UNLOCK);
1259
1260 /* execute */
1261 pReq->Hdr.rc = SUPR0UnlockMem(pSession, pReq->u.In.pvR3);
1262 return 0;
1263 }
1264
1265 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_CONT_ALLOC):
1266 {
1267 /* validate */
1268 PSUPCONTALLOC pReq = (PSUPCONTALLOC)pReqHdr;
1269 REQ_CHECK_SIZES(SUP_IOCTL_CONT_ALLOC);
1270
1271 /* execute */
1272 pReq->Hdr.rc = SUPR0ContAlloc(pSession, pReq->u.In.cPages, &pReq->u.Out.pvR0, &pReq->u.Out.pvR3, &pReq->u.Out.HCPhys);
1273 if (RT_FAILURE(pReq->Hdr.rc))
1274 pReq->Hdr.cbOut = sizeof(pReq->Hdr);
1275 return 0;
1276 }
1277
1278 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_CONT_FREE):
1279 {
1280 /* validate */
1281 PSUPCONTFREE pReq = (PSUPCONTFREE)pReqHdr;
1282 REQ_CHECK_SIZES(SUP_IOCTL_CONT_FREE);
1283
1284 /* execute */
1285 pReq->Hdr.rc = SUPR0ContFree(pSession, (RTHCUINTPTR)pReq->u.In.pvR3);
1286 return 0;
1287 }
1288
1289 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_LDR_OPEN):
1290 {
1291 /* validate */
1292 PSUPLDROPEN pReq = (PSUPLDROPEN)pReqHdr;
1293 REQ_CHECK_SIZES(SUP_IOCTL_LDR_OPEN);
1294 REQ_CHECK_EXPR(SUP_IOCTL_LDR_OPEN, pReq->u.In.cbImageWithTabs > 0);
1295 REQ_CHECK_EXPR(SUP_IOCTL_LDR_OPEN, pReq->u.In.cbImageWithTabs < 16*_1M);
1296#ifdef VBOX_WITH_NATIVE_R0_LOADER
1297 REQ_CHECK_EXPR(SUP_IOCTL_LDR_OPEN, pReq->u.In.cbImageBits > 0);
1298 REQ_CHECK_EXPR(SUP_IOCTL_LDR_OPEN, pReq->u.In.cbImageBits > 0);
1299 REQ_CHECK_EXPR(SUP_IOCTL_LDR_OPEN, pReq->u.In.cbImageBits < pReq->u.In.cbImageWithTabs);
1300#endif
1301 REQ_CHECK_EXPR(SUP_IOCTL_LDR_OPEN, pReq->u.In.szName[0]);
1302 REQ_CHECK_EXPR(SUP_IOCTL_LDR_OPEN, memchr(pReq->u.In.szName, '\0', sizeof(pReq->u.In.szName)));
1303 REQ_CHECK_EXPR(SUP_IOCTL_LDR_OPEN, !supdrvCheckInvalidChar(pReq->u.In.szName, ";:()[]{}/\\|&*%#@!~`\"'"));
1304#ifdef VBOX_WITH_NATIVE_R0_LOADER
1305 REQ_CHECK_EXPR(SUP_IOCTL_LDR_OPEN, memchr(pReq->u.In.szFilename, '\0', sizeof(pReq->u.In.szFilename)));
1306#endif
1307
1308 /* execute */
1309 pReq->Hdr.rc = supdrvIOCtl_LdrOpen(pDevExt, pSession, pReq);
1310 return 0;
1311 }
1312
1313 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_LDR_LOAD):
1314 {
1315 /* validate */
1316 PSUPLDRLOAD pReq = (PSUPLDRLOAD)pReqHdr;
1317 REQ_CHECK_EXPR(Name, pReq->Hdr.cbIn >= sizeof(*pReq));
1318 REQ_CHECK_SIZES_EX(SUP_IOCTL_LDR_LOAD, SUP_IOCTL_LDR_LOAD_SIZE_IN(pReq->u.In.cbImageWithTabs), SUP_IOCTL_LDR_LOAD_SIZE_OUT);
1319 REQ_CHECK_EXPR(SUP_IOCTL_LDR_LOAD, pReq->u.In.cSymbols <= 16384);
1320 REQ_CHECK_EXPR_FMT( !pReq->u.In.cSymbols
1321 || ( pReq->u.In.offSymbols < pReq->u.In.cbImageWithTabs
1322 && pReq->u.In.offSymbols + pReq->u.In.cSymbols * sizeof(SUPLDRSYM) <= pReq->u.In.cbImageWithTabs),
1323 ("SUP_IOCTL_LDR_LOAD: offSymbols=%#lx cSymbols=%#lx cbImageWithTabs=%#lx\n", (long)pReq->u.In.offSymbols,
1324 (long)pReq->u.In.cSymbols, (long)pReq->u.In.cbImageWithTabs));
1325 REQ_CHECK_EXPR_FMT( !pReq->u.In.cbStrTab
1326 || ( pReq->u.In.offStrTab < pReq->u.In.cbImageWithTabs
1327 && pReq->u.In.offStrTab + pReq->u.In.cbStrTab <= pReq->u.In.cbImageWithTabs
1328 && pReq->u.In.cbStrTab <= pReq->u.In.cbImageWithTabs),
1329 ("SUP_IOCTL_LDR_LOAD: offStrTab=%#lx cbStrTab=%#lx cbImageWithTabs=%#lx\n", (long)pReq->u.In.offStrTab,
1330 (long)pReq->u.In.cbStrTab, (long)pReq->u.In.cbImageWithTabs));
1331
1332 if (pReq->u.In.cSymbols)
1333 {
1334 uint32_t i;
1335 PSUPLDRSYM paSyms = (PSUPLDRSYM)&pReq->u.In.achImage[pReq->u.In.offSymbols];
1336 for (i = 0; i < pReq->u.In.cSymbols; i++)
1337 {
1338 REQ_CHECK_EXPR_FMT(paSyms[i].offSymbol < pReq->u.In.cbImageWithTabs,
1339 ("SUP_IOCTL_LDR_LOAD: sym #%ld: symb off %#lx (max=%#lx)\n", (long)i, (long)paSyms[i].offSymbol, (long)pReq->u.In.cbImageWithTabs));
1340 REQ_CHECK_EXPR_FMT(paSyms[i].offName < pReq->u.In.cbStrTab,
1341 ("SUP_IOCTL_LDR_LOAD: sym #%ld: name off %#lx (max=%#lx)\n", (long)i, (long)paSyms[i].offName, (long)pReq->u.In.cbImageWithTabs));
1342 REQ_CHECK_EXPR_FMT(memchr(&pReq->u.In.achImage[pReq->u.In.offStrTab + paSyms[i].offName], '\0', pReq->u.In.cbStrTab - paSyms[i].offName),
1343 ("SUP_IOCTL_LDR_LOAD: sym #%ld: unterminated name! (%#lx / %#lx)\n", (long)i, (long)paSyms[i].offName, (long)pReq->u.In.cbImageWithTabs));
1344 }
1345 }
1346
1347 /* execute */
1348 pReq->Hdr.rc = supdrvIOCtl_LdrLoad(pDevExt, pSession, pReq);
1349 return 0;
1350 }
1351
1352 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_LDR_FREE):
1353 {
1354 /* validate */
1355 PSUPLDRFREE pReq = (PSUPLDRFREE)pReqHdr;
1356 REQ_CHECK_SIZES(SUP_IOCTL_LDR_FREE);
1357
1358 /* execute */
1359 pReq->Hdr.rc = supdrvIOCtl_LdrFree(pDevExt, pSession, pReq);
1360 return 0;
1361 }
1362
1363 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_LDR_GET_SYMBOL):
1364 {
1365 /* validate */
1366 PSUPLDRGETSYMBOL pReq = (PSUPLDRGETSYMBOL)pReqHdr;
1367 REQ_CHECK_SIZES(SUP_IOCTL_LDR_GET_SYMBOL);
1368 REQ_CHECK_EXPR(SUP_IOCTL_LDR_GET_SYMBOL, memchr(pReq->u.In.szSymbol, '\0', sizeof(pReq->u.In.szSymbol)));
1369
1370 /* execute */
1371 pReq->Hdr.rc = supdrvIOCtl_LdrGetSymbol(pDevExt, pSession, pReq);
1372 return 0;
1373 }
1374
1375 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_CALL_VMMR0(0)):
1376 {
1377 /* validate */
1378 PSUPCALLVMMR0 pReq = (PSUPCALLVMMR0)pReqHdr;
1379 Log4(("SUP_IOCTL_CALL_VMMR0: op=%u in=%u arg=%RX64 p/t=%RTproc/%RTthrd\n",
1380 pReq->u.In.uOperation, pReq->Hdr.cbIn, pReq->u.In.u64Arg, RTProcSelf(), RTThreadNativeSelf()));
1381
1382 if (pReq->Hdr.cbIn == SUP_IOCTL_CALL_VMMR0_SIZE(0))
1383 {
1384 REQ_CHECK_SIZES_EX(SUP_IOCTL_CALL_VMMR0, SUP_IOCTL_CALL_VMMR0_SIZE_IN(0), SUP_IOCTL_CALL_VMMR0_SIZE_OUT(0));
1385
1386 /* execute */
1387 if (RT_LIKELY(pDevExt->pfnVMMR0EntryEx))
1388#ifdef RT_WITH_W64_UNWIND_HACK
1389 pReq->Hdr.rc = supdrvNtWrapVMMR0EntryEx((PFNRT)pDevExt->pfnVMMR0EntryEx, pReq->u.In.pVMR0, pReq->u.In.idCpu, pReq->u.In.uOperation, NULL, pReq->u.In.u64Arg, pSession);
1390#else
1391 pReq->Hdr.rc = pDevExt->pfnVMMR0EntryEx(pReq->u.In.pVMR0, pReq->u.In.idCpu, pReq->u.In.uOperation, NULL, pReq->u.In.u64Arg, pSession);
1392#endif
1393 else
1394 pReq->Hdr.rc = VERR_WRONG_ORDER;
1395 }
1396 else
1397 {
1398 PSUPVMMR0REQHDR pVMMReq = (PSUPVMMR0REQHDR)&pReq->abReqPkt[0];
1399 REQ_CHECK_EXPR_FMT(pReq->Hdr.cbIn >= SUP_IOCTL_CALL_VMMR0_SIZE(sizeof(SUPVMMR0REQHDR)),
1400 ("SUP_IOCTL_CALL_VMMR0: cbIn=%#x < %#lx\n", pReq->Hdr.cbIn, SUP_IOCTL_CALL_VMMR0_SIZE(sizeof(SUPVMMR0REQHDR))));
1401 REQ_CHECK_EXPR(SUP_IOCTL_CALL_VMMR0, pVMMReq->u32Magic == SUPVMMR0REQHDR_MAGIC);
1402 REQ_CHECK_SIZES_EX(SUP_IOCTL_CALL_VMMR0, SUP_IOCTL_CALL_VMMR0_SIZE_IN(pVMMReq->cbReq), SUP_IOCTL_CALL_VMMR0_SIZE_OUT(pVMMReq->cbReq));
1403
1404 /* execute */
1405 if (RT_LIKELY(pDevExt->pfnVMMR0EntryEx))
1406#ifdef RT_WITH_W64_UNWIND_HACK
1407 pReq->Hdr.rc = supdrvNtWrapVMMR0EntryEx((PFNRT)pDevExt->pfnVMMR0EntryEx, pReq->u.In.pVMR0, pReq->u.In.idCpu, pReq->u.In.uOperation, pVMMReq, pReq->u.In.u64Arg, pSession);
1408#else
1409 pReq->Hdr.rc = pDevExt->pfnVMMR0EntryEx(pReq->u.In.pVMR0, pReq->u.In.idCpu, pReq->u.In.uOperation, pVMMReq, pReq->u.In.u64Arg, pSession);
1410#endif
1411 else
1412 pReq->Hdr.rc = VERR_WRONG_ORDER;
1413 }
1414
1415 if ( RT_FAILURE(pReq->Hdr.rc)
1416 && pReq->Hdr.rc != VERR_INTERRUPTED
1417 && pReq->Hdr.rc != VERR_TIMEOUT)
1418 Log(("SUP_IOCTL_CALL_VMMR0: rc=%Rrc op=%u out=%u arg=%RX64 p/t=%RTproc/%RTthrd\n",
1419 pReq->Hdr.rc, pReq->u.In.uOperation, pReq->Hdr.cbOut, pReq->u.In.u64Arg, RTProcSelf(), RTThreadNativeSelf()));
1420 else
1421 Log4(("SUP_IOCTL_CALL_VMMR0: rc=%Rrc op=%u out=%u arg=%RX64 p/t=%RTproc/%RTthrd\n",
1422 pReq->Hdr.rc, pReq->u.In.uOperation, pReq->Hdr.cbOut, pReq->u.In.u64Arg, RTProcSelf(), RTThreadNativeSelf()));
1423 return 0;
1424 }
1425
1426 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_GET_PAGING_MODE):
1427 {
1428 /* validate */
1429 PSUPGETPAGINGMODE pReq = (PSUPGETPAGINGMODE)pReqHdr;
1430 REQ_CHECK_SIZES(SUP_IOCTL_GET_PAGING_MODE);
1431
1432 /* execute */
1433 pReq->Hdr.rc = VINF_SUCCESS;
1434 pReq->u.Out.enmMode = SUPR0GetPagingMode();
1435 return 0;
1436 }
1437
1438 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_LOW_ALLOC):
1439 {
1440 /* validate */
1441 PSUPLOWALLOC pReq = (PSUPLOWALLOC)pReqHdr;
1442 REQ_CHECK_EXPR(SUP_IOCTL_LOW_ALLOC, pReq->Hdr.cbIn <= SUP_IOCTL_LOW_ALLOC_SIZE_IN);
1443 REQ_CHECK_SIZES_EX(SUP_IOCTL_LOW_ALLOC, SUP_IOCTL_LOW_ALLOC_SIZE_IN, SUP_IOCTL_LOW_ALLOC_SIZE_OUT(pReq->u.In.cPages));
1444
1445 /* execute */
1446 pReq->Hdr.rc = SUPR0LowAlloc(pSession, pReq->u.In.cPages, &pReq->u.Out.pvR0, &pReq->u.Out.pvR3, &pReq->u.Out.aPages[0]);
1447 if (RT_FAILURE(pReq->Hdr.rc))
1448 pReq->Hdr.cbOut = sizeof(pReq->Hdr);
1449 return 0;
1450 }
1451
1452 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_LOW_FREE):
1453 {
1454 /* validate */
1455 PSUPLOWFREE pReq = (PSUPLOWFREE)pReqHdr;
1456 REQ_CHECK_SIZES(SUP_IOCTL_LOW_FREE);
1457
1458 /* execute */
1459 pReq->Hdr.rc = SUPR0LowFree(pSession, (RTHCUINTPTR)pReq->u.In.pvR3);
1460 return 0;
1461 }
1462
1463 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_GIP_MAP):
1464 {
1465 /* validate */
1466 PSUPGIPMAP pReq = (PSUPGIPMAP)pReqHdr;
1467 REQ_CHECK_SIZES(SUP_IOCTL_GIP_MAP);
1468
1469 /* execute */
1470 pReq->Hdr.rc = SUPR0GipMap(pSession, &pReq->u.Out.pGipR3, &pReq->u.Out.HCPhysGip);
1471 if (RT_SUCCESS(pReq->Hdr.rc))
1472 pReq->u.Out.pGipR0 = pDevExt->pGip;
1473 return 0;
1474 }
1475
1476 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_GIP_UNMAP):
1477 {
1478 /* validate */
1479 PSUPGIPUNMAP pReq = (PSUPGIPUNMAP)pReqHdr;
1480 REQ_CHECK_SIZES(SUP_IOCTL_GIP_UNMAP);
1481
1482 /* execute */
1483 pReq->Hdr.rc = SUPR0GipUnmap(pSession);
1484 return 0;
1485 }
1486
1487 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_SET_VM_FOR_FAST):
1488 {
1489 /* validate */
1490 PSUPSETVMFORFAST pReq = (PSUPSETVMFORFAST)pReqHdr;
1491 REQ_CHECK_SIZES(SUP_IOCTL_SET_VM_FOR_FAST);
1492 REQ_CHECK_EXPR_FMT( !pReq->u.In.pVMR0
1493 || ( VALID_PTR(pReq->u.In.pVMR0)
1494 && !((uintptr_t)pReq->u.In.pVMR0 & (PAGE_SIZE - 1))),
1495 ("SUP_IOCTL_SET_VM_FOR_FAST: pVMR0=%p!\n", pReq->u.In.pVMR0));
1496 /* execute */
1497 pSession->pVM = pReq->u.In.pVMR0;
1498 pReq->Hdr.rc = VINF_SUCCESS;
1499 return 0;
1500 }
1501
1502 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_PAGE_ALLOC_EX):
1503 {
1504 /* validate */
1505 PSUPPAGEALLOCEX pReq = (PSUPPAGEALLOCEX)pReqHdr;
1506 REQ_CHECK_EXPR(SUP_IOCTL_PAGE_ALLOC_EX, pReq->Hdr.cbIn <= SUP_IOCTL_PAGE_ALLOC_EX_SIZE_IN);
1507 REQ_CHECK_SIZES_EX(SUP_IOCTL_PAGE_ALLOC_EX, SUP_IOCTL_PAGE_ALLOC_EX_SIZE_IN, SUP_IOCTL_PAGE_ALLOC_EX_SIZE_OUT(pReq->u.In.cPages));
1508 REQ_CHECK_EXPR_FMT(pReq->u.In.fKernelMapping || pReq->u.In.fUserMapping,
1509 ("SUP_IOCTL_PAGE_ALLOC_EX: No mapping requested!\n"));
1510 REQ_CHECK_EXPR_FMT(pReq->u.In.fUserMapping,
1511 ("SUP_IOCTL_PAGE_ALLOC_EX: Must have user mapping!\n"));
1512 REQ_CHECK_EXPR_FMT(!pReq->u.In.fReserved0 && !pReq->u.In.fReserved1,
1513 ("SUP_IOCTL_PAGE_ALLOC_EX: fReserved0=%d fReserved1=%d\n", pReq->u.In.fReserved0, pReq->u.In.fReserved1));
1514
1515 /* execute */
1516 pReq->Hdr.rc = SUPR0PageAllocEx(pSession, pReq->u.In.cPages, 0 /* fFlags */,
1517 pReq->u.In.fUserMapping ? &pReq->u.Out.pvR3 : NULL,
1518 pReq->u.In.fKernelMapping ? &pReq->u.Out.pvR0 : NULL,
1519 &pReq->u.Out.aPages[0]);
1520 if (RT_FAILURE(pReq->Hdr.rc))
1521 pReq->Hdr.cbOut = sizeof(pReq->Hdr);
1522 return 0;
1523 }
1524
1525 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_PAGE_MAP_KERNEL):
1526 {
1527 /* validate */
1528 PSUPPAGEMAPKERNEL pReq = (PSUPPAGEMAPKERNEL)pReqHdr;
1529 REQ_CHECK_SIZES(SUP_IOCTL_PAGE_MAP_KERNEL);
1530 REQ_CHECK_EXPR_FMT(!pReq->u.In.fFlags, ("SUP_IOCTL_PAGE_MAP_KERNEL: fFlags=%#x! MBZ\n", pReq->u.In.fFlags));
1531 REQ_CHECK_EXPR_FMT(!(pReq->u.In.offSub & PAGE_OFFSET_MASK), ("SUP_IOCTL_PAGE_MAP_KERNEL: offSub=%#x\n", pReq->u.In.offSub));
1532 REQ_CHECK_EXPR_FMT(pReq->u.In.cbSub && !(pReq->u.In.cbSub & PAGE_OFFSET_MASK),
1533 ("SUP_IOCTL_PAGE_MAP_KERNEL: cbSub=%#x\n", pReq->u.In.cbSub));
1534
1535 /* execute */
1536 pReq->Hdr.rc = SUPR0PageMapKernel(pSession, pReq->u.In.pvR3, pReq->u.In.offSub, pReq->u.In.cbSub,
1537 pReq->u.In.fFlags, &pReq->u.Out.pvR0);
1538 if (RT_FAILURE(pReq->Hdr.rc))
1539 pReq->Hdr.cbOut = sizeof(pReq->Hdr);
1540 return 0;
1541 }
1542
1543 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_PAGE_PROTECT):
1544 {
1545 /* validate */
1546 PSUPPAGEPROTECT pReq = (PSUPPAGEPROTECT)pReqHdr;
1547 REQ_CHECK_SIZES(SUP_IOCTL_PAGE_PROTECT);
1548 REQ_CHECK_EXPR_FMT(!(pReq->u.In.fProt & ~(RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC | RTMEM_PROT_NONE)),
1549 ("SUP_IOCTL_PAGE_PROTECT: fProt=%#x!\n", pReq->u.In.fProt));
1550 REQ_CHECK_EXPR_FMT(!(pReq->u.In.offSub & PAGE_OFFSET_MASK), ("SUP_IOCTL_PAGE_PROTECT: offSub=%#x\n", pReq->u.In.offSub));
1551 REQ_CHECK_EXPR_FMT(pReq->u.In.cbSub && !(pReq->u.In.cbSub & PAGE_OFFSET_MASK),
1552 ("SUP_IOCTL_PAGE_PROTECT: cbSub=%#x\n", pReq->u.In.cbSub));
1553
1554 /* execute */
1555 pReq->Hdr.rc = SUPR0PageProtect(pSession, pReq->u.In.pvR3, pReq->u.In.pvR0, pReq->u.In.offSub, pReq->u.In.cbSub, pReq->u.In.fProt);
1556 return 0;
1557 }
1558
1559 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_PAGE_FREE):
1560 {
1561 /* validate */
1562 PSUPPAGEFREE pReq = (PSUPPAGEFREE)pReqHdr;
1563 REQ_CHECK_SIZES(SUP_IOCTL_PAGE_FREE);
1564
1565 /* execute */
1566 pReq->Hdr.rc = SUPR0PageFree(pSession, pReq->u.In.pvR3);
1567 return 0;
1568 }
1569
1570 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_CALL_SERVICE(0)):
1571 {
1572 /* validate */
1573 PSUPCALLSERVICE pReq = (PSUPCALLSERVICE)pReqHdr;
1574 Log4(("SUP_IOCTL_CALL_SERVICE: op=%u in=%u arg=%RX64 p/t=%RTproc/%RTthrd\n",
1575 pReq->u.In.uOperation, pReq->Hdr.cbIn, pReq->u.In.u64Arg, RTProcSelf(), RTThreadNativeSelf()));
1576
1577 if (pReq->Hdr.cbIn == SUP_IOCTL_CALL_SERVICE_SIZE(0))
1578 REQ_CHECK_SIZES_EX(SUP_IOCTL_CALL_SERVICE, SUP_IOCTL_CALL_SERVICE_SIZE_IN(0), SUP_IOCTL_CALL_SERVICE_SIZE_OUT(0));
1579 else
1580 {
1581 PSUPR0SERVICEREQHDR pSrvReq = (PSUPR0SERVICEREQHDR)&pReq->abReqPkt[0];
1582 REQ_CHECK_EXPR_FMT(pReq->Hdr.cbIn >= SUP_IOCTL_CALL_SERVICE_SIZE(sizeof(SUPR0SERVICEREQHDR)),
1583 ("SUP_IOCTL_CALL_SERVICE: cbIn=%#x < %#lx\n", pReq->Hdr.cbIn, SUP_IOCTL_CALL_SERVICE_SIZE(sizeof(SUPR0SERVICEREQHDR))));
1584 REQ_CHECK_EXPR(SUP_IOCTL_CALL_SERVICE, pSrvReq->u32Magic == SUPR0SERVICEREQHDR_MAGIC);
1585 REQ_CHECK_SIZES_EX(SUP_IOCTL_CALL_SERVICE, SUP_IOCTL_CALL_SERVICE_SIZE_IN(pSrvReq->cbReq), SUP_IOCTL_CALL_SERVICE_SIZE_OUT(pSrvReq->cbReq));
1586 }
1587 REQ_CHECK_EXPR(SUP_IOCTL_CALL_SERVICE, memchr(pReq->u.In.szName, '\0', sizeof(pReq->u.In.szName)));
1588
1589 /* execute */
1590 pReq->Hdr.rc = supdrvIOCtl_CallServiceModule(pDevExt, pSession, pReq);
1591 return 0;
1592 }
1593
1594 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_LOGGER_SETTINGS(0)):
1595 {
1596 /* validate */
1597 PSUPLOGGERSETTINGS pReq = (PSUPLOGGERSETTINGS)pReqHdr;
1598 size_t cbStrTab;
1599 REQ_CHECK_SIZE_OUT(SUP_IOCTL_LOGGER_SETTINGS, SUP_IOCTL_LOGGER_SETTINGS_SIZE_OUT);
1600 REQ_CHECK_EXPR(SUP_IOCTL_LOGGER_SETTINGS, pReq->Hdr.cbIn >= SUP_IOCTL_LOGGER_SETTINGS_SIZE_IN(1));
1601 cbStrTab = pReq->Hdr.cbIn - SUP_IOCTL_LOGGER_SETTINGS_SIZE_IN(0);
1602 REQ_CHECK_EXPR(SUP_IOCTL_LOGGER_SETTINGS, pReq->u.In.offGroups < cbStrTab);
1603 REQ_CHECK_EXPR(SUP_IOCTL_LOGGER_SETTINGS, pReq->u.In.offFlags < cbStrTab);
1604 REQ_CHECK_EXPR(SUP_IOCTL_LOGGER_SETTINGS, pReq->u.In.offDestination < cbStrTab);
1605 REQ_CHECK_EXPR_FMT(pReq->u.In.szStrings[cbStrTab - 1] == '\0',
1606 ("SUP_IOCTL_LOGGER_SETTINGS: cbIn=%#x cbStrTab=%#zx LastChar=%d\n",
1607 pReq->Hdr.cbIn, cbStrTab, pReq->u.In.szStrings[cbStrTab - 1]));
1608 REQ_CHECK_EXPR(SUP_IOCTL_LOGGER_SETTINGS, pReq->u.In.fWhich <= SUPLOGGERSETTINGS_WHICH_RELEASE);
1609 REQ_CHECK_EXPR(SUP_IOCTL_LOGGER_SETTINGS, pReq->u.In.fWhat <= SUPLOGGERSETTINGS_WHAT_DESTROY);
1610
1611 /* execute */
1612 pReq->Hdr.rc = supdrvIOCtl_LoggerSettings(pDevExt, pSession, pReq);
1613 return 0;
1614 }
1615
1616 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_SEM_CREATE):
1617 {
1618 /* validate */
1619 PSUPSEMCREATE pReq = (PSUPSEMCREATE)pReqHdr;
1620 REQ_CHECK_SIZES_EX(SUP_IOCTL_SEM_CREATE, SUP_IOCTL_SEM_CREATE_SIZE_IN, SUP_IOCTL_SEM_CREATE_SIZE_OUT);
1621
1622 /* execute */
1623 switch (pReq->u.In.uType)
1624 {
1625 case SUP_SEM_TYPE_EVENT:
1626 {
1627 SUPSEMEVENT hEvent;
1628 pReq->Hdr.rc = SUPSemEventCreate(pSession, &hEvent);
1629 pReq->u.Out.hSem = (uint32_t)(uintptr_t)hEvent;
1630 break;
1631 }
1632
1633 case SUP_SEM_TYPE_EVENT_MULTI:
1634 {
1635 SUPSEMEVENTMULTI hEventMulti;
1636 pReq->Hdr.rc = SUPSemEventMultiCreate(pSession, &hEventMulti);
1637 pReq->u.Out.hSem = (uint32_t)(uintptr_t)hEventMulti;
1638 break;
1639 }
1640
1641 default:
1642 pReq->Hdr.rc = VERR_INVALID_PARAMETER;
1643 break;
1644 }
1645 return 0;
1646 }
1647
1648 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_SEM_OP):
1649 {
1650 /* validate */
1651 PSUPSEMOP pReq = (PSUPSEMOP)pReqHdr;
1652 REQ_CHECK_SIZES_EX(SUP_IOCTL_SEM_OP, SUP_IOCTL_SEM_OP_SIZE_IN, SUP_IOCTL_SEM_OP_SIZE_OUT);
1653
1654 /* execute */
1655 switch (pReq->u.In.uType)
1656 {
1657 case SUP_SEM_TYPE_EVENT:
1658 {
1659 SUPSEMEVENT hEvent = (SUPSEMEVENT)(uintptr_t)pReq->u.In.hSem;
1660 switch (pReq->u.In.uOp)
1661 {
1662 case SUPSEMOP_WAIT:
1663 pReq->Hdr.rc = SUPSemEventWaitNoResume(pSession, hEvent, pReq->u.In.cMillies);
1664 break;
1665 case SUPSEMOP_SIGNAL:
1666 pReq->Hdr.rc = SUPSemEventSignal(pSession, hEvent);
1667 break;
1668 case SUPSEMOP_CLOSE:
1669 pReq->Hdr.rc = SUPSemEventClose(pSession, hEvent);
1670 break;
1671 case SUPSEMOP_RESET:
1672 default:
1673 pReq->Hdr.rc = VERR_INVALID_FUNCTION;
1674 break;
1675 }
1676 break;
1677 }
1678
1679 case SUP_SEM_TYPE_EVENT_MULTI:
1680 {
1681 SUPSEMEVENTMULTI hEventMulti = (SUPSEMEVENTMULTI)(uintptr_t)pReq->u.In.hSem;
1682 switch (pReq->u.In.uOp)
1683 {
1684 case SUPSEMOP_WAIT:
1685 pReq->Hdr.rc = SUPSemEventMultiWaitNoResume(pSession, hEventMulti, pReq->u.In.cMillies);
1686 break;
1687 case SUPSEMOP_SIGNAL:
1688 pReq->Hdr.rc = SUPSemEventMultiSignal(pSession, hEventMulti);
1689 break;
1690 case SUPSEMOP_CLOSE:
1691 pReq->Hdr.rc = SUPSemEventMultiClose(pSession, hEventMulti);
1692 break;
1693 case SUPSEMOP_RESET:
1694 pReq->Hdr.rc = SUPSemEventMultiReset(pSession, hEventMulti);
1695 break;
1696 default:
1697 pReq->Hdr.rc = VERR_INVALID_FUNCTION;
1698 break;
1699 }
1700 break;
1701 }
1702
1703 default:
1704 pReq->Hdr.rc = VERR_INVALID_PARAMETER;
1705 break;
1706 }
1707 return 0;
1708 }
1709
1710 case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_VT_CAPS):
1711 {
1712 /* validate */
1713 PSUPVTCAPS pReq = (PSUPVTCAPS)pReqHdr;
1714 REQ_CHECK_SIZES(SUP_IOCTL_VT_CAPS);
1715 REQ_CHECK_EXPR(SUP_IOCTL_VT_CAPS, pReq->Hdr.cbIn <= SUP_IOCTL_VT_CAPS_SIZE_IN);
1716
1717 /* execute */
1718 pReq->Hdr.rc = SUPR0QueryVTCaps(pSession, &pReq->u.Out.Caps);
1719 if (RT_FAILURE(pReq->Hdr.rc))
1720 pReq->Hdr.cbOut = sizeof(pReq->Hdr);
1721 return 0;
1722 }
1723
1724 default:
1725 Log(("Unknown IOCTL %#lx\n", (long)uIOCtl));
1726 break;
1727 }
1728 return SUPDRV_ERR_GENERAL_FAILURE;
1729}
1730
1731
1732/**
1733 * Inter-Driver Communcation (IDC) worker.
1734 *
1735 * @returns VBox status code.
1736 * @retval VINF_SUCCESS on success.
1737 * @retval VERR_INVALID_PARAMETER if the request is invalid.
1738 * @retval VERR_NOT_SUPPORTED if the request isn't supported.
1739 *
1740 * @param uReq The request (function) code.
1741 * @param pDevExt Device extention.
1742 * @param pSession Session data.
1743 * @param pReqHdr The request header.
1744 */
1745int VBOXCALL supdrvIDC(uintptr_t uReq, PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPDRVIDCREQHDR pReqHdr)
1746{
1747 /*
1748 * The OS specific code has already validated the pSession
1749 * pointer, and the request size being greater or equal to
1750 * size of the header.
1751 *
1752 * So, just check that pSession is a kernel context session.
1753 */
1754 if (RT_UNLIKELY( pSession
1755 && pSession->R0Process != NIL_RTR0PROCESS))
1756 return VERR_INVALID_PARAMETER;
1757
1758/*
1759 * Validation macro.
1760 */
1761#define REQ_CHECK_IDC_SIZE(Name, cbExpect) \
1762 do { \
1763 if (RT_UNLIKELY(pReqHdr->cb != (cbExpect))) \
1764 { \
1765 OSDBGPRINT(( #Name ": Invalid input/output sizes. cb=%ld expected %ld.\n", \
1766 (long)pReqHdr->cb, (long)(cbExpect))); \
1767 return pReqHdr->rc = VERR_INVALID_PARAMETER; \
1768 } \
1769 } while (0)
1770
1771 switch (uReq)
1772 {
1773 case SUPDRV_IDC_REQ_CONNECT:
1774 {
1775 PSUPDRVIDCREQCONNECT pReq = (PSUPDRVIDCREQCONNECT)pReqHdr;
1776 REQ_CHECK_IDC_SIZE(SUPDRV_IDC_REQ_CONNECT, sizeof(*pReq));
1777
1778 /*
1779 * Validate the cookie and other input.
1780 */
1781 if (pReq->Hdr.pSession != NULL)
1782 {
1783 OSDBGPRINT(("SUPDRV_IDC_REQ_CONNECT: pSession=%p expected NULL!\n", pReq->Hdr.pSession));
1784 return pReqHdr->rc = VERR_INVALID_PARAMETER;
1785 }
1786 if (pReq->u.In.u32MagicCookie != SUPDRVIDCREQ_CONNECT_MAGIC_COOKIE)
1787 {
1788 OSDBGPRINT(("SUPDRV_IDC_REQ_CONNECT: u32MagicCookie=%#x expected %#x!\n",
1789 (unsigned)pReq->u.In.u32MagicCookie, (unsigned)SUPDRVIDCREQ_CONNECT_MAGIC_COOKIE));
1790 return pReqHdr->rc = VERR_INVALID_PARAMETER;
1791 }
1792 if ( pReq->u.In.uMinVersion > pReq->u.In.uReqVersion
1793 || (pReq->u.In.uMinVersion & UINT32_C(0xffff0000)) != (pReq->u.In.uReqVersion & UINT32_C(0xffff0000)))
1794 {
1795 OSDBGPRINT(("SUPDRV_IDC_REQ_CONNECT: uMinVersion=%#x uMaxVersion=%#x doesn't match!\n",
1796 pReq->u.In.uMinVersion, pReq->u.In.uReqVersion));
1797 return pReqHdr->rc = VERR_INVALID_PARAMETER;
1798 }
1799
1800 /*
1801 * Match the version.
1802 * The current logic is very simple, match the major interface version.
1803 */
1804 if ( pReq->u.In.uMinVersion > SUPDRV_IDC_VERSION
1805 || (pReq->u.In.uMinVersion & 0xffff0000) != (SUPDRV_IDC_VERSION & 0xffff0000))
1806 {
1807 OSDBGPRINT(("SUPDRV_IDC_REQ_CONNECT: Version mismatch. Requested: %#x Min: %#x Current: %#x\n",
1808 pReq->u.In.uReqVersion, pReq->u.In.uMinVersion, (unsigned)SUPDRV_IDC_VERSION));
1809 pReq->u.Out.pSession = NULL;
1810 pReq->u.Out.uSessionVersion = 0xffffffff;
1811 pReq->u.Out.uDriverVersion = SUPDRV_IDC_VERSION;
1812 pReq->u.Out.uDriverRevision = VBOX_SVN_REV;
1813 pReq->Hdr.rc = VERR_VERSION_MISMATCH;
1814 return VINF_SUCCESS;
1815 }
1816
1817 pReq->u.Out.pSession = NULL;
1818 pReq->u.Out.uSessionVersion = SUPDRV_IDC_VERSION;
1819 pReq->u.Out.uDriverVersion = SUPDRV_IDC_VERSION;
1820 pReq->u.Out.uDriverRevision = VBOX_SVN_REV;
1821
1822 /*
1823 * On NT we will already have a session associated with the
1824 * client, just like with the SUP_IOCTL_COOKIE request, while
1825 * the other doesn't.
1826 */
1827#ifdef RT_OS_WINDOWS
1828 pReq->Hdr.rc = VINF_SUCCESS;
1829#else
1830 AssertReturn(!pSession, VERR_INTERNAL_ERROR);
1831 pReq->Hdr.rc = supdrvCreateSession(pDevExt, false /* fUser */, &pSession);
1832 if (RT_FAILURE(pReq->Hdr.rc))
1833 {
1834 OSDBGPRINT(("SUPDRV_IDC_REQ_CONNECT: failed to create session, rc=%d\n", pReq->Hdr.rc));
1835 return VINF_SUCCESS;
1836 }
1837#endif
1838
1839 pReq->u.Out.pSession = pSession;
1840 pReq->Hdr.pSession = pSession;
1841
1842 return VINF_SUCCESS;
1843 }
1844
1845 case SUPDRV_IDC_REQ_DISCONNECT:
1846 {
1847 REQ_CHECK_IDC_SIZE(SUPDRV_IDC_REQ_DISCONNECT, sizeof(*pReqHdr));
1848
1849#ifdef RT_OS_WINDOWS
1850 /* Windows will destroy the session when the file object is destroyed. */
1851#else
1852 supdrvCloseSession(pDevExt, pSession);
1853#endif
1854 return pReqHdr->rc = VINF_SUCCESS;
1855 }
1856
1857 case SUPDRV_IDC_REQ_GET_SYMBOL:
1858 {
1859 PSUPDRVIDCREQGETSYM pReq = (PSUPDRVIDCREQGETSYM)pReqHdr;
1860 REQ_CHECK_IDC_SIZE(SUPDRV_IDC_REQ_GET_SYMBOL, sizeof(*pReq));
1861
1862 pReq->Hdr.rc = supdrvIDC_LdrGetSymbol(pDevExt, pSession, pReq);
1863 return VINF_SUCCESS;
1864 }
1865
1866 case SUPDRV_IDC_REQ_COMPONENT_REGISTER_FACTORY:
1867 {
1868 PSUPDRVIDCREQCOMPREGFACTORY pReq = (PSUPDRVIDCREQCOMPREGFACTORY)pReqHdr;
1869 REQ_CHECK_IDC_SIZE(SUPDRV_IDC_REQ_COMPONENT_REGISTER_FACTORY, sizeof(*pReq));
1870
1871 pReq->Hdr.rc = SUPR0ComponentRegisterFactory(pSession, pReq->u.In.pFactory);
1872 return VINF_SUCCESS;
1873 }
1874
1875 case SUPDRV_IDC_REQ_COMPONENT_DEREGISTER_FACTORY:
1876 {
1877 PSUPDRVIDCREQCOMPDEREGFACTORY pReq = (PSUPDRVIDCREQCOMPDEREGFACTORY)pReqHdr;
1878 REQ_CHECK_IDC_SIZE(SUPDRV_IDC_REQ_COMPONENT_DEREGISTER_FACTORY, sizeof(*pReq));
1879
1880 pReq->Hdr.rc = SUPR0ComponentDeregisterFactory(pSession, pReq->u.In.pFactory);
1881 return VINF_SUCCESS;
1882 }
1883
1884 default:
1885 Log(("Unknown IDC %#lx\n", (long)uReq));
1886 break;
1887 }
1888
1889#undef REQ_CHECK_IDC_SIZE
1890 return VERR_NOT_SUPPORTED;
1891}
1892
1893
1894/**
1895 * Register a object for reference counting.
1896 * The object is registered with one reference in the specified session.
1897 *
1898 * @returns Unique identifier on success (pointer).
1899 * All future reference must use this identifier.
1900 * @returns NULL on failure.
1901 * @param pfnDestructor The destructore function which will be called when the reference count reaches 0.
1902 * @param pvUser1 The first user argument.
1903 * @param pvUser2 The second user argument.
1904 */
1905SUPR0DECL(void *) SUPR0ObjRegister(PSUPDRVSESSION pSession, SUPDRVOBJTYPE enmType, PFNSUPDRVDESTRUCTOR pfnDestructor, void *pvUser1, void *pvUser2)
1906{
1907 RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
1908 PSUPDRVDEVEXT pDevExt = pSession->pDevExt;
1909 PSUPDRVOBJ pObj;
1910 PSUPDRVUSAGE pUsage;
1911
1912 /*
1913 * Validate the input.
1914 */
1915 AssertReturn(SUP_IS_SESSION_VALID(pSession), NULL);
1916 AssertReturn(enmType > SUPDRVOBJTYPE_INVALID && enmType < SUPDRVOBJTYPE_END, NULL);
1917 AssertPtrReturn(pfnDestructor, NULL);
1918
1919 /*
1920 * Allocate and initialize the object.
1921 */
1922 pObj = (PSUPDRVOBJ)RTMemAlloc(sizeof(*pObj));
1923 if (!pObj)
1924 return NULL;
1925 pObj->u32Magic = SUPDRVOBJ_MAGIC;
1926 pObj->enmType = enmType;
1927 pObj->pNext = NULL;
1928 pObj->cUsage = 1;
1929 pObj->pfnDestructor = pfnDestructor;
1930 pObj->pvUser1 = pvUser1;
1931 pObj->pvUser2 = pvUser2;
1932 pObj->CreatorUid = pSession->Uid;
1933 pObj->CreatorGid = pSession->Gid;
1934 pObj->CreatorProcess= pSession->Process;
1935 supdrvOSObjInitCreator(pObj, pSession);
1936
1937 /*
1938 * Allocate the usage record.
1939 * (We keep freed usage records around to simplify SUPR0ObjAddRefEx().)
1940 */
1941 RTSpinlockAcquire(pDevExt->Spinlock, &SpinlockTmp);
1942
1943 pUsage = pDevExt->pUsageFree;
1944 if (pUsage)
1945 pDevExt->pUsageFree = pUsage->pNext;
1946 else
1947 {
1948 RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
1949 pUsage = (PSUPDRVUSAGE)RTMemAlloc(sizeof(*pUsage));
1950 if (!pUsage)
1951 {
1952 RTMemFree(pObj);
1953 return NULL;
1954 }
1955 RTSpinlockAcquire(pDevExt->Spinlock, &SpinlockTmp);
1956 }
1957
1958 /*
1959 * Insert the object and create the session usage record.
1960 */
1961 /* The object. */
1962 pObj->pNext = pDevExt->pObjs;
1963 pDevExt->pObjs = pObj;
1964
1965 /* The session record. */
1966 pUsage->cUsage = 1;
1967 pUsage->pObj = pObj;
1968 pUsage->pNext = pSession->pUsage;
1969 /* Log2(("SUPR0ObjRegister: pUsage=%p:{.pObj=%p, .pNext=%p}\n", pUsage, pUsage->pObj, pUsage->pNext)); */
1970 pSession->pUsage = pUsage;
1971
1972 RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
1973
1974 Log(("SUPR0ObjRegister: returns %p (pvUser1=%p, pvUser=%p)\n", pObj, pvUser1, pvUser2));
1975 return pObj;
1976}
1977
1978
1979/**
1980 * Increment the reference counter for the object associating the reference
1981 * with the specified session.
1982 *
1983 * @returns IPRT status code.
1984 * @param pvObj The identifier returned by SUPR0ObjRegister().
1985 * @param pSession The session which is referencing the object.
1986 *
1987 * @remarks The caller should not own any spinlocks and must carefully protect
1988 * itself against potential race with the destructor so freed memory
1989 * isn't accessed here.
1990 */
1991SUPR0DECL(int) SUPR0ObjAddRef(void *pvObj, PSUPDRVSESSION pSession)
1992{
1993 return SUPR0ObjAddRefEx(pvObj, pSession, false /* fNoBlocking */);
1994}
1995
1996
1997/**
1998 * Increment the reference counter for the object associating the reference
1999 * with the specified session.
2000 *
2001 * @returns IPRT status code.
2002 * @retval VERR_TRY_AGAIN if fNoBlocking was set and a new usage record
2003 * couldn't be allocated. (If you see this you're not doing the right
2004 * thing and it won't ever work reliably.)
2005 *
2006 * @param pvObj The identifier returned by SUPR0ObjRegister().
2007 * @param pSession The session which is referencing the object.
2008 * @param fNoBlocking Set if it's not OK to block. Never try to make the
2009 * first reference to an object in a session with this
2010 * argument set.
2011 *
2012 * @remarks The caller should not own any spinlocks and must carefully protect
2013 * itself against potential race with the destructor so freed memory
2014 * isn't accessed here.
2015 */
2016SUPR0DECL(int) SUPR0ObjAddRefEx(void *pvObj, PSUPDRVSESSION pSession, bool fNoBlocking)
2017{
2018 RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
2019 PSUPDRVDEVEXT pDevExt = pSession->pDevExt;
2020 PSUPDRVOBJ pObj = (PSUPDRVOBJ)pvObj;
2021 int rc = VINF_SUCCESS;
2022 PSUPDRVUSAGE pUsagePre;
2023 PSUPDRVUSAGE pUsage;
2024
2025 /*
2026 * Validate the input.
2027 * Be ready for the destruction race (someone might be stuck in the
2028 * destructor waiting a lock we own).
2029 */
2030 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
2031 AssertPtrReturn(pObj, VERR_INVALID_POINTER);
2032 AssertMsgReturn(pObj->u32Magic == SUPDRVOBJ_MAGIC || pObj->u32Magic == SUPDRVOBJ_MAGIC_DEAD,
2033 ("Invalid pvObj=%p magic=%#x (expected %#x or %#x)\n", pvObj, pObj->u32Magic, SUPDRVOBJ_MAGIC, SUPDRVOBJ_MAGIC_DEAD),
2034 VERR_INVALID_PARAMETER);
2035
2036 RTSpinlockAcquire(pDevExt->Spinlock, &SpinlockTmp);
2037
2038 if (RT_UNLIKELY(pObj->u32Magic != SUPDRVOBJ_MAGIC))
2039 {
2040 RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
2041
2042 AssertMsgFailed(("pvObj=%p magic=%#x\n", pvObj, pObj->u32Magic));
2043 return VERR_WRONG_ORDER;
2044 }
2045
2046 /*
2047 * Preallocate the usage record if we can.
2048 */
2049 pUsagePre = pDevExt->pUsageFree;
2050 if (pUsagePre)
2051 pDevExt->pUsageFree = pUsagePre->pNext;
2052 else if (!fNoBlocking)
2053 {
2054 RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
2055 pUsagePre = (PSUPDRVUSAGE)RTMemAlloc(sizeof(*pUsagePre));
2056 if (!pUsagePre)
2057 return VERR_NO_MEMORY;
2058
2059 RTSpinlockAcquire(pDevExt->Spinlock, &SpinlockTmp);
2060 if (RT_UNLIKELY(pObj->u32Magic != SUPDRVOBJ_MAGIC))
2061 {
2062 RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
2063
2064 AssertMsgFailed(("pvObj=%p magic=%#x\n", pvObj, pObj->u32Magic));
2065 return VERR_WRONG_ORDER;
2066 }
2067 }
2068
2069 /*
2070 * Reference the object.
2071 */
2072 pObj->cUsage++;
2073
2074 /*
2075 * Look for the session record.
2076 */
2077 for (pUsage = pSession->pUsage; pUsage; pUsage = pUsage->pNext)
2078 {
2079 /*Log(("SUPR0AddRef: pUsage=%p:{.pObj=%p, .pNext=%p}\n", pUsage, pUsage->pObj, pUsage->pNext));*/
2080 if (pUsage->pObj == pObj)
2081 break;
2082 }
2083 if (pUsage)
2084 pUsage->cUsage++;
2085 else if (pUsagePre)
2086 {
2087 /* create a new session record. */
2088 pUsagePre->cUsage = 1;
2089 pUsagePre->pObj = pObj;
2090 pUsagePre->pNext = pSession->pUsage;
2091 pSession->pUsage = pUsagePre;
2092 /*Log(("SUPR0AddRef: pUsagePre=%p:{.pObj=%p, .pNext=%p}\n", pUsagePre, pUsagePre->pObj, pUsagePre->pNext));*/
2093
2094 pUsagePre = NULL;
2095 }
2096 else
2097 {
2098 pObj->cUsage--;
2099 rc = VERR_TRY_AGAIN;
2100 }
2101
2102 /*
2103 * Put any unused usage record into the free list..
2104 */
2105 if (pUsagePre)
2106 {
2107 pUsagePre->pNext = pDevExt->pUsageFree;
2108 pDevExt->pUsageFree = pUsagePre;
2109 }
2110
2111 RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
2112
2113 return rc;
2114}
2115
2116
2117/**
2118 * Decrement / destroy a reference counter record for an object.
2119 *
2120 * The object is uniquely identified by pfnDestructor+pvUser1+pvUser2.
2121 *
2122 * @returns IPRT status code.
2123 * @retval VINF_SUCCESS if not destroyed.
2124 * @retval VINF_OBJECT_DESTROYED if it's destroyed by this release call.
2125 * @retval VERR_INVALID_PARAMETER if the object isn't valid. Will assert in
2126 * string builds.
2127 *
2128 * @param pvObj The identifier returned by SUPR0ObjRegister().
2129 * @param pSession The session which is referencing the object.
2130 */
2131SUPR0DECL(int) SUPR0ObjRelease(void *pvObj, PSUPDRVSESSION pSession)
2132{
2133 RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
2134 PSUPDRVDEVEXT pDevExt = pSession->pDevExt;
2135 PSUPDRVOBJ pObj = (PSUPDRVOBJ)pvObj;
2136 int rc = VERR_INVALID_PARAMETER;
2137 PSUPDRVUSAGE pUsage;
2138 PSUPDRVUSAGE pUsagePrev;
2139
2140 /*
2141 * Validate the input.
2142 */
2143 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
2144 AssertMsgReturn(VALID_PTR(pObj) && pObj->u32Magic == SUPDRVOBJ_MAGIC,
2145 ("Invalid pvObj=%p magic=%#x (exepcted %#x)\n", pvObj, pObj ? pObj->u32Magic : 0, SUPDRVOBJ_MAGIC),
2146 VERR_INVALID_PARAMETER);
2147
2148 /*
2149 * Acquire the spinlock and look for the usage record.
2150 */
2151 RTSpinlockAcquire(pDevExt->Spinlock, &SpinlockTmp);
2152
2153 for (pUsagePrev = NULL, pUsage = pSession->pUsage;
2154 pUsage;
2155 pUsagePrev = pUsage, pUsage = pUsage->pNext)
2156 {
2157 /*Log2(("SUPR0ObjRelease: pUsage=%p:{.pObj=%p, .pNext=%p}\n", pUsage, pUsage->pObj, pUsage->pNext));*/
2158 if (pUsage->pObj == pObj)
2159 {
2160 rc = VINF_SUCCESS;
2161 AssertMsg(pUsage->cUsage >= 1 && pObj->cUsage >= pUsage->cUsage, ("glob %d; sess %d\n", pObj->cUsage, pUsage->cUsage));
2162 if (pUsage->cUsage > 1)
2163 {
2164 pObj->cUsage--;
2165 pUsage->cUsage--;
2166 }
2167 else
2168 {
2169 /*
2170 * Free the session record.
2171 */
2172 if (pUsagePrev)
2173 pUsagePrev->pNext = pUsage->pNext;
2174 else
2175 pSession->pUsage = pUsage->pNext;
2176 pUsage->pNext = pDevExt->pUsageFree;
2177 pDevExt->pUsageFree = pUsage;
2178
2179 /* What about the object? */
2180 if (pObj->cUsage > 1)
2181 pObj->cUsage--;
2182 else
2183 {
2184 /*
2185 * Object is to be destroyed, unlink it.
2186 */
2187 pObj->u32Magic = SUPDRVOBJ_MAGIC_DEAD;
2188 rc = VINF_OBJECT_DESTROYED;
2189 if (pDevExt->pObjs == pObj)
2190 pDevExt->pObjs = pObj->pNext;
2191 else
2192 {
2193 PSUPDRVOBJ pObjPrev;
2194 for (pObjPrev = pDevExt->pObjs; pObjPrev; pObjPrev = pObjPrev->pNext)
2195 if (pObjPrev->pNext == pObj)
2196 {
2197 pObjPrev->pNext = pObj->pNext;
2198 break;
2199 }
2200 Assert(pObjPrev);
2201 }
2202 }
2203 }
2204 break;
2205 }
2206 }
2207
2208 RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
2209
2210 /*
2211 * Call the destructor and free the object if required.
2212 */
2213 if (rc == VINF_OBJECT_DESTROYED)
2214 {
2215 Log(("SUPR0ObjRelease: destroying %p/%d (%p/%p) cpid=%RTproc pid=%RTproc dtor=%p\n",
2216 pObj, pObj->enmType, pObj->pvUser1, pObj->pvUser2, pObj->CreatorProcess, RTProcSelf(), pObj->pfnDestructor));
2217 if (pObj->pfnDestructor)
2218#ifdef RT_WITH_W64_UNWIND_HACK
2219 supdrvNtWrapObjDestructor((PFNRT)pObj->pfnDestructor, pObj, pObj->pvUser1, pObj->pvUser2);
2220#else
2221 pObj->pfnDestructor(pObj, pObj->pvUser1, pObj->pvUser2);
2222#endif
2223 RTMemFree(pObj);
2224 }
2225
2226 AssertMsg(pUsage, ("pvObj=%p\n", pvObj));
2227 return rc;
2228}
2229
2230
2231/**
2232 * Verifies that the current process can access the specified object.
2233 *
2234 * @returns The following IPRT status code:
2235 * @retval VINF_SUCCESS if access was granted.
2236 * @retval VERR_PERMISSION_DENIED if denied access.
2237 * @retval VERR_INVALID_PARAMETER if invalid parameter.
2238 *
2239 * @param pvObj The identifier returned by SUPR0ObjRegister().
2240 * @param pSession The session which wishes to access the object.
2241 * @param pszObjName Object string name. This is optional and depends on the object type.
2242 *
2243 * @remark The caller is responsible for making sure the object isn't removed while
2244 * we're inside this function. If uncertain about this, just call AddRef before calling us.
2245 */
2246SUPR0DECL(int) SUPR0ObjVerifyAccess(void *pvObj, PSUPDRVSESSION pSession, const char *pszObjName)
2247{
2248 PSUPDRVOBJ pObj = (PSUPDRVOBJ)pvObj;
2249 int rc;
2250
2251 /*
2252 * Validate the input.
2253 */
2254 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
2255 AssertMsgReturn(VALID_PTR(pObj) && pObj->u32Magic == SUPDRVOBJ_MAGIC,
2256 ("Invalid pvObj=%p magic=%#x (exepcted %#x)\n", pvObj, pObj ? pObj->u32Magic : 0, SUPDRVOBJ_MAGIC),
2257 VERR_INVALID_PARAMETER);
2258
2259 /*
2260 * Check access. (returns true if a decision has been made.)
2261 */
2262 rc = VERR_INTERNAL_ERROR;
2263 if (supdrvOSObjCanAccess(pObj, pSession, pszObjName, &rc))
2264 return rc;
2265
2266 /*
2267 * Default policy is to allow the user to access his own
2268 * stuff but nothing else.
2269 */
2270 if (pObj->CreatorUid == pSession->Uid)
2271 return VINF_SUCCESS;
2272 return VERR_PERMISSION_DENIED;
2273}
2274
2275
2276/**
2277 * Lock pages.
2278 *
2279 * @returns IPRT status code.
2280 * @param pSession Session to which the locked memory should be associated.
2281 * @param pvR3 Start of the memory range to lock.
2282 * This must be page aligned.
2283 * @param cPages Number of pages to lock.
2284 * @param paPages Where to put the physical addresses of locked memory.
2285 */
2286SUPR0DECL(int) SUPR0LockMem(PSUPDRVSESSION pSession, RTR3PTR pvR3, uint32_t cPages, PRTHCPHYS paPages)
2287{
2288 int rc;
2289 SUPDRVMEMREF Mem = { NIL_RTR0MEMOBJ, NIL_RTR0MEMOBJ, MEMREF_TYPE_UNUSED };
2290 const size_t cb = (size_t)cPages << PAGE_SHIFT;
2291 LogFlow(("SUPR0LockMem: pSession=%p pvR3=%p cPages=%d paPages=%p\n", pSession, (void *)pvR3, cPages, paPages));
2292
2293 /*
2294 * Verify input.
2295 */
2296 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
2297 AssertPtrReturn(paPages, VERR_INVALID_PARAMETER);
2298 if ( RT_ALIGN_R3PT(pvR3, PAGE_SIZE, RTR3PTR) != pvR3
2299 || !pvR3)
2300 {
2301 Log(("pvR3 (%p) must be page aligned and not NULL!\n", (void *)pvR3));
2302 return VERR_INVALID_PARAMETER;
2303 }
2304
2305 /*
2306 * Let IPRT do the job.
2307 */
2308 Mem.eType = MEMREF_TYPE_LOCKED;
2309 rc = RTR0MemObjLockUser(&Mem.MemObj, pvR3, cb, RTMEM_PROT_READ | RTMEM_PROT_WRITE, RTR0ProcHandleSelf());
2310 if (RT_SUCCESS(rc))
2311 {
2312 uint32_t iPage = cPages;
2313 AssertMsg(RTR0MemObjAddressR3(Mem.MemObj) == pvR3, ("%p == %p\n", RTR0MemObjAddressR3(Mem.MemObj), pvR3));
2314 AssertMsg(RTR0MemObjSize(Mem.MemObj) == cb, ("%x == %x\n", RTR0MemObjSize(Mem.MemObj), cb));
2315
2316 while (iPage-- > 0)
2317 {
2318 paPages[iPage] = RTR0MemObjGetPagePhysAddr(Mem.MemObj, iPage);
2319 if (RT_UNLIKELY(paPages[iPage] == NIL_RTCCPHYS))
2320 {
2321 AssertMsgFailed(("iPage=%d\n", iPage));
2322 rc = VERR_INTERNAL_ERROR;
2323 break;
2324 }
2325 }
2326 if (RT_SUCCESS(rc))
2327 rc = supdrvMemAdd(&Mem, pSession);
2328 if (RT_FAILURE(rc))
2329 {
2330 int rc2 = RTR0MemObjFree(Mem.MemObj, false);
2331 AssertRC(rc2);
2332 }
2333 }
2334
2335 return rc;
2336}
2337
2338
2339/**
2340 * Unlocks the memory pointed to by pv.
2341 *
2342 * @returns IPRT status code.
2343 * @param pSession Session to which the memory was locked.
2344 * @param pvR3 Memory to unlock.
2345 */
2346SUPR0DECL(int) SUPR0UnlockMem(PSUPDRVSESSION pSession, RTR3PTR pvR3)
2347{
2348 LogFlow(("SUPR0UnlockMem: pSession=%p pvR3=%p\n", pSession, (void *)pvR3));
2349 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
2350 return supdrvMemRelease(pSession, (RTHCUINTPTR)pvR3, MEMREF_TYPE_LOCKED);
2351}
2352
2353
2354/**
2355 * Allocates a chunk of page aligned memory with contiguous and fixed physical
2356 * backing.
2357 *
2358 * @returns IPRT status code.
2359 * @param pSession Session data.
2360 * @param cPages Number of pages to allocate.
2361 * @param ppvR0 Where to put the address of Ring-0 mapping the allocated memory.
2362 * @param ppvR3 Where to put the address of Ring-3 mapping the allocated memory.
2363 * @param pHCPhys Where to put the physical address of allocated memory.
2364 */
2365SUPR0DECL(int) SUPR0ContAlloc(PSUPDRVSESSION pSession, uint32_t cPages, PRTR0PTR ppvR0, PRTR3PTR ppvR3, PRTHCPHYS pHCPhys)
2366{
2367 int rc;
2368 SUPDRVMEMREF Mem = { NIL_RTR0MEMOBJ, NIL_RTR0MEMOBJ, MEMREF_TYPE_UNUSED };
2369 LogFlow(("SUPR0ContAlloc: pSession=%p cPages=%d ppvR0=%p ppvR3=%p pHCPhys=%p\n", pSession, cPages, ppvR0, ppvR3, pHCPhys));
2370
2371 /*
2372 * Validate input.
2373 */
2374 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
2375 if (!ppvR3 || !ppvR0 || !pHCPhys)
2376 {
2377 Log(("Null pointer. All of these should be set: pSession=%p ppvR0=%p ppvR3=%p pHCPhys=%p\n",
2378 pSession, ppvR0, ppvR3, pHCPhys));
2379 return VERR_INVALID_PARAMETER;
2380
2381 }
2382 if (cPages < 1 || cPages >= 256)
2383 {
2384 Log(("Illegal request cPages=%d, must be greater than 0 and smaller than 256.\n", cPages));
2385 return VERR_PAGE_COUNT_OUT_OF_RANGE;
2386 }
2387
2388 /*
2389 * Let IPRT do the job.
2390 */
2391 rc = RTR0MemObjAllocCont(&Mem.MemObj, cPages << PAGE_SHIFT, true /* executable R0 mapping */);
2392 if (RT_SUCCESS(rc))
2393 {
2394 int rc2;
2395 rc = RTR0MemObjMapUser(&Mem.MapObjR3, Mem.MemObj, (RTR3PTR)-1, 0,
2396 RTMEM_PROT_EXEC | RTMEM_PROT_WRITE | RTMEM_PROT_READ, RTR0ProcHandleSelf());
2397 if (RT_SUCCESS(rc))
2398 {
2399 Mem.eType = MEMREF_TYPE_CONT;
2400 rc = supdrvMemAdd(&Mem, pSession);
2401 if (!rc)
2402 {
2403 *ppvR0 = RTR0MemObjAddress(Mem.MemObj);
2404 *ppvR3 = RTR0MemObjAddressR3(Mem.MapObjR3);
2405 *pHCPhys = RTR0MemObjGetPagePhysAddr(Mem.MemObj, 0);
2406 return 0;
2407 }
2408
2409 rc2 = RTR0MemObjFree(Mem.MapObjR3, false);
2410 AssertRC(rc2);
2411 }
2412 rc2 = RTR0MemObjFree(Mem.MemObj, false);
2413 AssertRC(rc2);
2414 }
2415
2416 return rc;
2417}
2418
2419
2420/**
2421 * Frees memory allocated using SUPR0ContAlloc().
2422 *
2423 * @returns IPRT status code.
2424 * @param pSession The session to which the memory was allocated.
2425 * @param uPtr Pointer to the memory (ring-3 or ring-0).
2426 */
2427SUPR0DECL(int) SUPR0ContFree(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr)
2428{
2429 LogFlow(("SUPR0ContFree: pSession=%p uPtr=%p\n", pSession, (void *)uPtr));
2430 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
2431 return supdrvMemRelease(pSession, uPtr, MEMREF_TYPE_CONT);
2432}
2433
2434
2435/**
2436 * Allocates a chunk of page aligned memory with fixed physical backing below 4GB.
2437 *
2438 * The memory isn't zeroed.
2439 *
2440 * @returns IPRT status code.
2441 * @param pSession Session data.
2442 * @param cPages Number of pages to allocate.
2443 * @param ppvR0 Where to put the address of Ring-0 mapping of the allocated memory.
2444 * @param ppvR3 Where to put the address of Ring-3 mapping of the allocated memory.
2445 * @param paPages Where to put the physical addresses of allocated memory.
2446 */
2447SUPR0DECL(int) SUPR0LowAlloc(PSUPDRVSESSION pSession, uint32_t cPages, PRTR0PTR ppvR0, PRTR3PTR ppvR3, PRTHCPHYS paPages)
2448{
2449 unsigned iPage;
2450 int rc;
2451 SUPDRVMEMREF Mem = { NIL_RTR0MEMOBJ, NIL_RTR0MEMOBJ, MEMREF_TYPE_UNUSED };
2452 LogFlow(("SUPR0LowAlloc: pSession=%p cPages=%d ppvR3=%p ppvR0=%p paPages=%p\n", pSession, cPages, ppvR3, ppvR0, paPages));
2453
2454 /*
2455 * Validate input.
2456 */
2457 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
2458 if (!ppvR3 || !ppvR0 || !paPages)
2459 {
2460 Log(("Null pointer. All of these should be set: pSession=%p ppvR3=%p ppvR0=%p paPages=%p\n",
2461 pSession, ppvR3, ppvR0, paPages));
2462 return VERR_INVALID_PARAMETER;
2463
2464 }
2465 if (cPages < 1 || cPages >= 256)
2466 {
2467 Log(("Illegal request cPages=%d, must be greater than 0 and smaller than 256.\n", cPages));
2468 return VERR_PAGE_COUNT_OUT_OF_RANGE;
2469 }
2470
2471 /*
2472 * Let IPRT do the work.
2473 */
2474 rc = RTR0MemObjAllocLow(&Mem.MemObj, cPages << PAGE_SHIFT, true /* executable ring-0 mapping */);
2475 if (RT_SUCCESS(rc))
2476 {
2477 int rc2;
2478 rc = RTR0MemObjMapUser(&Mem.MapObjR3, Mem.MemObj, (RTR3PTR)-1, 0,
2479 RTMEM_PROT_EXEC | RTMEM_PROT_WRITE | RTMEM_PROT_READ, RTR0ProcHandleSelf());
2480 if (RT_SUCCESS(rc))
2481 {
2482 Mem.eType = MEMREF_TYPE_LOW;
2483 rc = supdrvMemAdd(&Mem, pSession);
2484 if (!rc)
2485 {
2486 for (iPage = 0; iPage < cPages; iPage++)
2487 {
2488 paPages[iPage] = RTR0MemObjGetPagePhysAddr(Mem.MemObj, iPage);
2489 AssertMsg(!(paPages[iPage] & (PAGE_SIZE - 1)), ("iPage=%d Phys=%RHp\n", paPages[iPage]));
2490 }
2491 *ppvR0 = RTR0MemObjAddress(Mem.MemObj);
2492 *ppvR3 = RTR0MemObjAddressR3(Mem.MapObjR3);
2493 return 0;
2494 }
2495
2496 rc2 = RTR0MemObjFree(Mem.MapObjR3, false);
2497 AssertRC(rc2);
2498 }
2499
2500 rc2 = RTR0MemObjFree(Mem.MemObj, false);
2501 AssertRC(rc2);
2502 }
2503
2504 return rc;
2505}
2506
2507
2508/**
2509 * Frees memory allocated using SUPR0LowAlloc().
2510 *
2511 * @returns IPRT status code.
2512 * @param pSession The session to which the memory was allocated.
2513 * @param uPtr Pointer to the memory (ring-3 or ring-0).
2514 */
2515SUPR0DECL(int) SUPR0LowFree(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr)
2516{
2517 LogFlow(("SUPR0LowFree: pSession=%p uPtr=%p\n", pSession, (void *)uPtr));
2518 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
2519 return supdrvMemRelease(pSession, uPtr, MEMREF_TYPE_LOW);
2520}
2521
2522
2523
2524/**
2525 * Allocates a chunk of memory with both R0 and R3 mappings.
2526 * The memory is fixed and it's possible to query the physical addresses using SUPR0MemGetPhys().
2527 *
2528 * @returns IPRT status code.
2529 * @param pSession The session to associated the allocation with.
2530 * @param cb Number of bytes to allocate.
2531 * @param ppvR0 Where to store the address of the Ring-0 mapping.
2532 * @param ppvR3 Where to store the address of the Ring-3 mapping.
2533 */
2534SUPR0DECL(int) SUPR0MemAlloc(PSUPDRVSESSION pSession, uint32_t cb, PRTR0PTR ppvR0, PRTR3PTR ppvR3)
2535{
2536 int rc;
2537 SUPDRVMEMREF Mem = { NIL_RTR0MEMOBJ, NIL_RTR0MEMOBJ, MEMREF_TYPE_UNUSED };
2538 LogFlow(("SUPR0MemAlloc: pSession=%p cb=%d ppvR0=%p ppvR3=%p\n", pSession, cb, ppvR0, ppvR3));
2539
2540 /*
2541 * Validate input.
2542 */
2543 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
2544 AssertPtrReturn(ppvR0, VERR_INVALID_POINTER);
2545 AssertPtrReturn(ppvR3, VERR_INVALID_POINTER);
2546 if (cb < 1 || cb >= _4M)
2547 {
2548 Log(("Illegal request cb=%u; must be greater than 0 and smaller than 4MB.\n", cb));
2549 return VERR_INVALID_PARAMETER;
2550 }
2551
2552 /*
2553 * Let IPRT do the work.
2554 */
2555 rc = RTR0MemObjAllocPage(&Mem.MemObj, cb, true /* executable ring-0 mapping */);
2556 if (RT_SUCCESS(rc))
2557 {
2558 int rc2;
2559 rc = RTR0MemObjMapUser(&Mem.MapObjR3, Mem.MemObj, (RTR3PTR)-1, 0,
2560 RTMEM_PROT_EXEC | RTMEM_PROT_WRITE | RTMEM_PROT_READ, RTR0ProcHandleSelf());
2561 if (RT_SUCCESS(rc))
2562 {
2563 Mem.eType = MEMREF_TYPE_MEM;
2564 rc = supdrvMemAdd(&Mem, pSession);
2565 if (!rc)
2566 {
2567 *ppvR0 = RTR0MemObjAddress(Mem.MemObj);
2568 *ppvR3 = RTR0MemObjAddressR3(Mem.MapObjR3);
2569 return VINF_SUCCESS;
2570 }
2571
2572 rc2 = RTR0MemObjFree(Mem.MapObjR3, false);
2573 AssertRC(rc2);
2574 }
2575
2576 rc2 = RTR0MemObjFree(Mem.MemObj, false);
2577 AssertRC(rc2);
2578 }
2579
2580 return rc;
2581}
2582
2583
2584/**
2585 * Get the physical addresses of memory allocated using SUPR0MemAlloc().
2586 *
2587 * @returns IPRT status code.
2588 * @param pSession The session to which the memory was allocated.
2589 * @param uPtr The Ring-0 or Ring-3 address returned by SUPR0MemAlloc().
2590 * @param paPages Where to store the physical addresses.
2591 */
2592SUPR0DECL(int) SUPR0MemGetPhys(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr, PSUPPAGE paPages) /** @todo switch this bugger to RTHCPHYS */
2593{
2594 PSUPDRVBUNDLE pBundle;
2595 RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
2596 LogFlow(("SUPR0MemGetPhys: pSession=%p uPtr=%p paPages=%p\n", pSession, (void *)uPtr, paPages));
2597
2598 /*
2599 * Validate input.
2600 */
2601 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
2602 AssertPtrReturn(paPages, VERR_INVALID_POINTER);
2603 AssertReturn(uPtr, VERR_INVALID_PARAMETER);
2604
2605 /*
2606 * Search for the address.
2607 */
2608 RTSpinlockAcquire(pSession->Spinlock, &SpinlockTmp);
2609 for (pBundle = &pSession->Bundle; pBundle; pBundle = pBundle->pNext)
2610 {
2611 if (pBundle->cUsed > 0)
2612 {
2613 unsigned i;
2614 for (i = 0; i < RT_ELEMENTS(pBundle->aMem); i++)
2615 {
2616 if ( pBundle->aMem[i].eType == MEMREF_TYPE_MEM
2617 && pBundle->aMem[i].MemObj != NIL_RTR0MEMOBJ
2618 && ( (RTHCUINTPTR)RTR0MemObjAddress(pBundle->aMem[i].MemObj) == uPtr
2619 || ( pBundle->aMem[i].MapObjR3 != NIL_RTR0MEMOBJ
2620 && RTR0MemObjAddressR3(pBundle->aMem[i].MapObjR3) == uPtr)
2621 )
2622 )
2623 {
2624 const size_t cPages = RTR0MemObjSize(pBundle->aMem[i].MemObj) >> PAGE_SHIFT;
2625 size_t iPage;
2626 for (iPage = 0; iPage < cPages; iPage++)
2627 {
2628 paPages[iPage].Phys = RTR0MemObjGetPagePhysAddr(pBundle->aMem[i].MemObj, iPage);
2629 paPages[iPage].uReserved = 0;
2630 }
2631 RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
2632 return VINF_SUCCESS;
2633 }
2634 }
2635 }
2636 }
2637 RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
2638 Log(("Failed to find %p!!!\n", (void *)uPtr));
2639 return VERR_INVALID_PARAMETER;
2640}
2641
2642
2643/**
2644 * Free memory allocated by SUPR0MemAlloc().
2645 *
2646 * @returns IPRT status code.
2647 * @param pSession The session owning the allocation.
2648 * @param uPtr The Ring-0 or Ring-3 address returned by SUPR0MemAlloc().
2649 */
2650SUPR0DECL(int) SUPR0MemFree(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr)
2651{
2652 LogFlow(("SUPR0MemFree: pSession=%p uPtr=%p\n", pSession, (void *)uPtr));
2653 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
2654 return supdrvMemRelease(pSession, uPtr, MEMREF_TYPE_MEM);
2655}
2656
2657
2658/**
2659 * Allocates a chunk of memory with a kernel or/and a user mode mapping.
2660 *
2661 * The memory is fixed and it's possible to query the physical addresses using
2662 * SUPR0MemGetPhys().
2663 *
2664 * @returns IPRT status code.
2665 * @param pSession The session to associated the allocation with.
2666 * @param cPages The number of pages to allocate.
2667 * @param fFlags Flags, reserved for the future. Must be zero.
2668 * @param ppvR3 Where to store the address of the Ring-3 mapping.
2669 * NULL if no ring-3 mapping.
2670 * @param ppvR3 Where to store the address of the Ring-0 mapping.
2671 * NULL if no ring-0 mapping.
2672 * @param paPages Where to store the addresses of the pages. Optional.
2673 */
2674SUPR0DECL(int) SUPR0PageAllocEx(PSUPDRVSESSION pSession, uint32_t cPages, uint32_t fFlags, PRTR3PTR ppvR3, PRTR0PTR ppvR0, PRTHCPHYS paPages)
2675{
2676 int rc;
2677 SUPDRVMEMREF Mem = { NIL_RTR0MEMOBJ, NIL_RTR0MEMOBJ, MEMREF_TYPE_UNUSED };
2678 LogFlow(("SUPR0PageAlloc: pSession=%p cb=%d ppvR3=%p\n", pSession, cPages, ppvR3));
2679
2680 /*
2681 * Validate input. The allowed allocation size must be at least equal to the maximum guest VRAM size.
2682 */
2683 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
2684 AssertPtrNullReturn(ppvR3, VERR_INVALID_POINTER);
2685 AssertPtrNullReturn(ppvR0, VERR_INVALID_POINTER);
2686 AssertReturn(ppvR3 || ppvR0, VERR_INVALID_PARAMETER);
2687 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
2688 if (cPages < 1 || cPages > VBOX_MAX_ALLOC_PAGE_COUNT)
2689 {
2690 Log(("SUPR0PageAlloc: Illegal request cb=%u; must be greater than 0 and smaller than 128MB.\n", cPages));
2691 return VERR_PAGE_COUNT_OUT_OF_RANGE;
2692 }
2693
2694 /*
2695 * Let IPRT do the work.
2696 */
2697 if (ppvR0)
2698 rc = RTR0MemObjAllocPage(&Mem.MemObj, (size_t)cPages * PAGE_SIZE, true /* fExecutable */);
2699 else
2700 rc = RTR0MemObjAllocPhysNC(&Mem.MemObj, (size_t)cPages * PAGE_SIZE, NIL_RTHCPHYS);
2701 if (RT_SUCCESS(rc))
2702 {
2703 int rc2;
2704 if (ppvR3)
2705 rc = RTR0MemObjMapUser(&Mem.MapObjR3, Mem.MemObj, (RTR3PTR)-1, 0,
2706 RTMEM_PROT_EXEC | RTMEM_PROT_WRITE | RTMEM_PROT_READ, RTR0ProcHandleSelf());
2707 else
2708 Mem.MapObjR3 = NIL_RTR0MEMOBJ;
2709 if (RT_SUCCESS(rc))
2710 {
2711 Mem.eType = MEMREF_TYPE_PAGE;
2712 rc = supdrvMemAdd(&Mem, pSession);
2713 if (!rc)
2714 {
2715 if (ppvR3)
2716 *ppvR3 = RTR0MemObjAddressR3(Mem.MapObjR3);
2717 if (ppvR0)
2718 *ppvR0 = RTR0MemObjAddress(Mem.MemObj);
2719 if (paPages)
2720 {
2721 uint32_t iPage = cPages;
2722 while (iPage-- > 0)
2723 {
2724 paPages[iPage] = RTR0MemObjGetPagePhysAddr(Mem.MapObjR3, iPage);
2725 Assert(paPages[iPage] != NIL_RTHCPHYS);
2726 }
2727 }
2728 return VINF_SUCCESS;
2729 }
2730
2731 rc2 = RTR0MemObjFree(Mem.MapObjR3, false);
2732 AssertRC(rc2);
2733 }
2734
2735 rc2 = RTR0MemObjFree(Mem.MemObj, false);
2736 AssertRC(rc2);
2737 }
2738 return rc;
2739}
2740
2741
2742/**
2743 * Maps a chunk of memory previously allocated by SUPR0PageAllocEx into kernel
2744 * space.
2745 *
2746 * @returns IPRT status code.
2747 * @param pSession The session to associated the allocation with.
2748 * @param pvR3 The ring-3 address returned by SUPR0PageAllocEx.
2749 * @param offSub Where to start mapping. Must be page aligned.
2750 * @param cbSub How much to map. Must be page aligned.
2751 * @param fFlags Flags, MBZ.
2752 * @param ppvR0 Where to reutrn the address of the ring-0 mapping on
2753 * success.
2754 */
2755SUPR0DECL(int) SUPR0PageMapKernel(PSUPDRVSESSION pSession, RTR3PTR pvR3, uint32_t offSub, uint32_t cbSub,
2756 uint32_t fFlags, PRTR0PTR ppvR0)
2757{
2758 int rc;
2759 PSUPDRVBUNDLE pBundle;
2760 RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
2761 RTR0MEMOBJ hMemObj = NIL_RTR0MEMOBJ;
2762 LogFlow(("SUPR0PageMapKernel: pSession=%p pvR3=%p offSub=%#x cbSub=%#x\n", pSession, pvR3, offSub, cbSub));
2763
2764 /*
2765 * Validate input. The allowed allocation size must be at least equal to the maximum guest VRAM size.
2766 */
2767 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
2768 AssertPtrNullReturn(ppvR0, VERR_INVALID_POINTER);
2769 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
2770 AssertReturn(!(offSub & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
2771 AssertReturn(!(cbSub & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
2772 AssertReturn(cbSub, VERR_INVALID_PARAMETER);
2773
2774 /*
2775 * Find the memory object.
2776 */
2777 RTSpinlockAcquire(pSession->Spinlock, &SpinlockTmp);
2778 for (pBundle = &pSession->Bundle; pBundle; pBundle = pBundle->pNext)
2779 {
2780 if (pBundle->cUsed > 0)
2781 {
2782 unsigned i;
2783 for (i = 0; i < RT_ELEMENTS(pBundle->aMem); i++)
2784 {
2785 if ( ( pBundle->aMem[i].eType == MEMREF_TYPE_PAGE
2786 && pBundle->aMem[i].MemObj != NIL_RTR0MEMOBJ
2787 && pBundle->aMem[i].MapObjR3 != NIL_RTR0MEMOBJ
2788 && RTR0MemObjAddressR3(pBundle->aMem[i].MapObjR3) == pvR3)
2789 || ( pBundle->aMem[i].eType == MEMREF_TYPE_LOCKED
2790 && pBundle->aMem[i].MemObj != NIL_RTR0MEMOBJ
2791 && pBundle->aMem[i].MapObjR3 == NIL_RTR0MEMOBJ
2792 && RTR0MemObjAddressR3(pBundle->aMem[i].MemObj) == pvR3))
2793 {
2794 hMemObj = pBundle->aMem[i].MemObj;
2795 break;
2796 }
2797 }
2798 }
2799 }
2800 RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
2801
2802 rc = VERR_INVALID_PARAMETER;
2803 if (hMemObj != NIL_RTR0MEMOBJ)
2804 {
2805 /*
2806 * Do some furter input validations before calling IPRT.
2807 * (Cleanup is done indirectly by telling RTR0MemObjFree to include mappings.)
2808 */
2809 size_t cbMemObj = RTR0MemObjSize(hMemObj);
2810 if ( offSub < cbMemObj
2811 && cbSub <= cbMemObj
2812 && offSub + cbSub <= cbMemObj)
2813 {
2814 RTR0MEMOBJ hMapObj;
2815 rc = RTR0MemObjMapKernelEx(&hMapObj, hMemObj, (void *)-1, 0,
2816 RTMEM_PROT_READ | RTMEM_PROT_WRITE, offSub, cbSub);
2817 if (RT_SUCCESS(rc))
2818 *ppvR0 = RTR0MemObjAddress(hMapObj);
2819 }
2820 else
2821 SUPR0Printf("SUPR0PageMapKernel: cbMemObj=%#x offSub=%#x cbSub=%#x\n", cbMemObj, offSub, cbSub);
2822
2823 }
2824 return rc;
2825}
2826
2827
2828/**
2829 * Changes the page level protection of one or more pages previously allocated
2830 * by SUPR0PageAllocEx.
2831 *
2832 * @returns IPRT status code.
2833 * @param pSession The session to associated the allocation with.
2834 * @param pvR3 The ring-3 address returned by SUPR0PageAllocEx.
2835 * NIL_RTR3PTR if the ring-3 mapping should be unaffected.
2836 * @param pvR0 The ring-0 address returned by SUPR0PageAllocEx.
2837 * NIL_RTR0PTR if the ring-0 mapping should be unaffected.
2838 * @param offSub Where to start changing. Must be page aligned.
2839 * @param cbSub How much to change. Must be page aligned.
2840 * @param fProt The new page level protection, see RTMEM_PROT_*.
2841 */
2842SUPR0DECL(int) SUPR0PageProtect(PSUPDRVSESSION pSession, RTR3PTR pvR3, RTR0PTR pvR0, uint32_t offSub, uint32_t cbSub, uint32_t fProt)
2843{
2844 int rc;
2845 PSUPDRVBUNDLE pBundle;
2846 RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
2847 RTR0MEMOBJ hMemObjR0 = NIL_RTR0MEMOBJ;
2848 RTR0MEMOBJ hMemObjR3 = NIL_RTR0MEMOBJ;
2849 LogFlow(("SUPR0PageProtect: pSession=%p pvR3=%p pvR0=%p offSub=%#x cbSub=%#x fProt-%#x\n", pSession, pvR3, pvR0, offSub, cbSub, fProt));
2850
2851 /*
2852 * Validate input. The allowed allocation size must be at least equal to the maximum guest VRAM size.
2853 */
2854 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
2855 AssertReturn(!(fProt & ~(RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC | RTMEM_PROT_NONE)), VERR_INVALID_PARAMETER);
2856 AssertReturn(!(offSub & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
2857 AssertReturn(!(cbSub & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
2858 AssertReturn(cbSub, VERR_INVALID_PARAMETER);
2859
2860 /*
2861 * Find the memory object.
2862 */
2863 RTSpinlockAcquire(pSession->Spinlock, &SpinlockTmp);
2864 for (pBundle = &pSession->Bundle; pBundle; pBundle = pBundle->pNext)
2865 {
2866 if (pBundle->cUsed > 0)
2867 {
2868 unsigned i;
2869 for (i = 0; i < RT_ELEMENTS(pBundle->aMem); i++)
2870 {
2871 if ( pBundle->aMem[i].eType == MEMREF_TYPE_PAGE
2872 && pBundle->aMem[i].MemObj != NIL_RTR0MEMOBJ
2873 && ( pBundle->aMem[i].MapObjR3 != NIL_RTR0MEMOBJ
2874 || pvR3 == NIL_RTR3PTR)
2875 && ( pvR0 == NIL_RTR0PTR
2876 || RTR0MemObjAddress(pBundle->aMem[i].MemObj) == pvR0)
2877 && ( pvR3 == NIL_RTR3PTR
2878 || RTR0MemObjAddressR3(pBundle->aMem[i].MapObjR3) == pvR3))
2879 {
2880 if (pvR0 != NIL_RTR0PTR)
2881 hMemObjR0 = pBundle->aMem[i].MemObj;
2882 if (pvR3 != NIL_RTR3PTR)
2883 hMemObjR3 = pBundle->aMem[i].MapObjR3;
2884 break;
2885 }
2886 }
2887 }
2888 }
2889 RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
2890
2891 rc = VERR_INVALID_PARAMETER;
2892 if ( hMemObjR0 != NIL_RTR0MEMOBJ
2893 || hMemObjR3 != NIL_RTR0MEMOBJ)
2894 {
2895 /*
2896 * Do some furter input validations before calling IPRT.
2897 */
2898 size_t cbMemObj = hMemObjR0 != NIL_RTR0PTR ? RTR0MemObjSize(hMemObjR0) : RTR0MemObjSize(hMemObjR3);
2899 if ( offSub < cbMemObj
2900 && cbSub <= cbMemObj
2901 && offSub + cbSub <= cbMemObj)
2902 {
2903 rc = VINF_SUCCESS;
2904 if (hMemObjR3 != NIL_RTR0PTR)
2905 rc = RTR0MemObjProtect(hMemObjR3, offSub, cbSub, fProt);
2906 if (hMemObjR0 != NIL_RTR0PTR && RT_SUCCESS(rc))
2907 rc = RTR0MemObjProtect(hMemObjR0, offSub, cbSub, fProt);
2908 }
2909 else
2910 SUPR0Printf("SUPR0PageMapKernel: cbMemObj=%#x offSub=%#x cbSub=%#x\n", cbMemObj, offSub, cbSub);
2911
2912 }
2913 return rc;
2914
2915}
2916
2917
2918/**
2919 * Free memory allocated by SUPR0PageAlloc() and SUPR0PageAllocEx().
2920 *
2921 * @returns IPRT status code.
2922 * @param pSession The session owning the allocation.
2923 * @param pvR3 The Ring-3 address returned by SUPR0PageAlloc() or
2924 * SUPR0PageAllocEx().
2925 */
2926SUPR0DECL(int) SUPR0PageFree(PSUPDRVSESSION pSession, RTR3PTR pvR3)
2927{
2928 LogFlow(("SUPR0PageFree: pSession=%p pvR3=%p\n", pSession, (void *)pvR3));
2929 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
2930 return supdrvMemRelease(pSession, (RTHCUINTPTR)pvR3, MEMREF_TYPE_PAGE);
2931}
2932
2933
2934/**
2935 * Maps the GIP into userspace and/or get the physical address of the GIP.
2936 *
2937 * @returns IPRT status code.
2938 * @param pSession Session to which the GIP mapping should belong.
2939 * @param ppGipR3 Where to store the address of the ring-3 mapping. (optional)
2940 * @param pHCPhysGip Where to store the physical address. (optional)
2941 *
2942 * @remark There is no reference counting on the mapping, so one call to this function
2943 * count globally as one reference. One call to SUPR0GipUnmap() is will unmap GIP
2944 * and remove the session as a GIP user.
2945 */
2946SUPR0DECL(int) SUPR0GipMap(PSUPDRVSESSION pSession, PRTR3PTR ppGipR3, PRTHCPHYS pHCPhysGip)
2947{
2948 int rc;
2949 PSUPDRVDEVEXT pDevExt = pSession->pDevExt;
2950 RTR3PTR pGipR3 = NIL_RTR3PTR;
2951 RTHCPHYS HCPhys = NIL_RTHCPHYS;
2952 LogFlow(("SUPR0GipMap: pSession=%p ppGipR3=%p pHCPhysGip=%p\n", pSession, ppGipR3, pHCPhysGip));
2953
2954 /*
2955 * Validate
2956 */
2957 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
2958 AssertPtrNullReturn(ppGipR3, VERR_INVALID_POINTER);
2959 AssertPtrNullReturn(pHCPhysGip, VERR_INVALID_POINTER);
2960
2961 RTSemFastMutexRequest(pDevExt->mtxGip);
2962 if (pDevExt->pGip)
2963 {
2964 /*
2965 * Map it?
2966 */
2967 rc = VINF_SUCCESS;
2968 if (ppGipR3)
2969 {
2970 if (pSession->GipMapObjR3 == NIL_RTR0MEMOBJ)
2971 rc = RTR0MemObjMapUser(&pSession->GipMapObjR3, pDevExt->GipMemObj, (RTR3PTR)-1, 0,
2972 RTMEM_PROT_READ, RTR0ProcHandleSelf());
2973 if (RT_SUCCESS(rc))
2974 pGipR3 = RTR0MemObjAddressR3(pSession->GipMapObjR3);
2975 }
2976
2977 /*
2978 * Get physical address.
2979 */
2980 if (pHCPhysGip && RT_SUCCESS(rc))
2981 HCPhys = pDevExt->HCPhysGip;
2982
2983 /*
2984 * Reference globally.
2985 */
2986 if (!pSession->fGipReferenced && RT_SUCCESS(rc))
2987 {
2988 pSession->fGipReferenced = 1;
2989 pDevExt->cGipUsers++;
2990 if (pDevExt->cGipUsers == 1)
2991 {
2992 PSUPGLOBALINFOPAGE pGipR0 = pDevExt->pGip;
2993 unsigned i;
2994
2995 LogFlow(("SUPR0GipMap: Resumes GIP updating\n"));
2996
2997 for (i = 0; i < RT_ELEMENTS(pGipR0->aCPUs); i++)
2998 ASMAtomicXchgU32(&pGipR0->aCPUs[i].u32TransactionId, pGipR0->aCPUs[i].u32TransactionId & ~(GIP_UPDATEHZ_RECALC_FREQ * 2 - 1));
2999 ASMAtomicXchgU64(&pGipR0->u64NanoTSLastUpdateHz, 0);
3000
3001 rc = RTTimerStart(pDevExt->pGipTimer, 0);
3002 AssertRC(rc); rc = VINF_SUCCESS;
3003 }
3004 }
3005 }
3006 else
3007 {
3008 rc = SUPDRV_ERR_GENERAL_FAILURE;
3009 Log(("SUPR0GipMap: GIP is not available!\n"));
3010 }
3011 RTSemFastMutexRelease(pDevExt->mtxGip);
3012
3013 /*
3014 * Write returns.
3015 */
3016 if (pHCPhysGip)
3017 *pHCPhysGip = HCPhys;
3018 if (ppGipR3)
3019 *ppGipR3 = pGipR3;
3020
3021#ifdef DEBUG_DARWIN_GIP
3022 OSDBGPRINT(("SUPR0GipMap: returns %d *pHCPhysGip=%lx pGipR3=%p\n", rc, (unsigned long)HCPhys, (void *)pGipR3));
3023#else
3024 LogFlow(( "SUPR0GipMap: returns %d *pHCPhysGip=%lx pGipR3=%p\n", rc, (unsigned long)HCPhys, (void *)pGipR3));
3025#endif
3026 return rc;
3027}
3028
3029
3030/**
3031 * Unmaps any user mapping of the GIP and terminates all GIP access
3032 * from this session.
3033 *
3034 * @returns IPRT status code.
3035 * @param pSession Session to which the GIP mapping should belong.
3036 */
3037SUPR0DECL(int) SUPR0GipUnmap(PSUPDRVSESSION pSession)
3038{
3039 int rc = VINF_SUCCESS;
3040 PSUPDRVDEVEXT pDevExt = pSession->pDevExt;
3041#ifdef DEBUG_DARWIN_GIP
3042 OSDBGPRINT(("SUPR0GipUnmap: pSession=%p pGip=%p GipMapObjR3=%p\n",
3043 pSession,
3044 pSession->GipMapObjR3 != NIL_RTR0MEMOBJ ? RTR0MemObjAddress(pSession->GipMapObjR3) : NULL,
3045 pSession->GipMapObjR3));
3046#else
3047 LogFlow(("SUPR0GipUnmap: pSession=%p\n", pSession));
3048#endif
3049 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
3050
3051 RTSemFastMutexRequest(pDevExt->mtxGip);
3052
3053 /*
3054 * Unmap anything?
3055 */
3056 if (pSession->GipMapObjR3 != NIL_RTR0MEMOBJ)
3057 {
3058 rc = RTR0MemObjFree(pSession->GipMapObjR3, false);
3059 AssertRC(rc);
3060 if (RT_SUCCESS(rc))
3061 pSession->GipMapObjR3 = NIL_RTR0MEMOBJ;
3062 }
3063
3064 /*
3065 * Dereference global GIP.
3066 */
3067 if (pSession->fGipReferenced && !rc)
3068 {
3069 pSession->fGipReferenced = 0;
3070 if ( pDevExt->cGipUsers > 0
3071 && !--pDevExt->cGipUsers)
3072 {
3073 LogFlow(("SUPR0GipUnmap: Suspends GIP updating\n"));
3074 rc = RTTimerStop(pDevExt->pGipTimer); AssertRC(rc); rc = VINF_SUCCESS;
3075 }
3076 }
3077
3078 RTSemFastMutexRelease(pDevExt->mtxGip);
3079
3080 return rc;
3081}
3082
3083
3084/**
3085 * Gets the GIP pointer.
3086 *
3087 * @returns Pointer to the GIP or NULL.
3088 */
3089SUPDECL(PSUPGLOBALINFOPAGE) SUPGetGIP(void)
3090{
3091 return g_pSUPGlobalInfoPageInternal;
3092}
3093
3094
3095/**
3096 * Register a component factory with the support driver.
3097 *
3098 * This is currently restricted to kernel sessions only.
3099 *
3100 * @returns VBox status code.
3101 * @retval VINF_SUCCESS on success.
3102 * @retval VERR_NO_MEMORY if we're out of memory.
3103 * @retval VERR_ALREADY_EXISTS if the factory has already been registered.
3104 * @retval VERR_ACCESS_DENIED if it isn't a kernel session.
3105 * @retval VERR_INVALID_PARAMETER on invalid parameter.
3106 * @retval VERR_INVALID_POINTER on invalid pointer parameter.
3107 *
3108 * @param pSession The SUPDRV session (must be a ring-0 session).
3109 * @param pFactory Pointer to the component factory registration structure.
3110 *
3111 * @remarks This interface is also available via SUPR0IdcComponentRegisterFactory.
3112 */
3113SUPR0DECL(int) SUPR0ComponentRegisterFactory(PSUPDRVSESSION pSession, PCSUPDRVFACTORY pFactory)
3114{
3115 PSUPDRVFACTORYREG pNewReg;
3116 const char *psz;
3117 int rc;
3118
3119 /*
3120 * Validate parameters.
3121 */
3122 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
3123 AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_ACCESS_DENIED);
3124 AssertPtrReturn(pFactory, VERR_INVALID_POINTER);
3125 AssertPtrReturn(pFactory->pfnQueryFactoryInterface, VERR_INVALID_POINTER);
3126 psz = (const char *)memchr(pFactory->szName, '\0', sizeof(pFactory->szName));
3127 AssertReturn(psz, VERR_INVALID_PARAMETER);
3128
3129 /*
3130 * Allocate and initialize a new registration structure.
3131 */
3132 pNewReg = (PSUPDRVFACTORYREG)RTMemAlloc(sizeof(SUPDRVFACTORYREG));
3133 if (pNewReg)
3134 {
3135 pNewReg->pNext = NULL;
3136 pNewReg->pFactory = pFactory;
3137 pNewReg->pSession = pSession;
3138 pNewReg->cchName = psz - &pFactory->szName[0];
3139
3140 /*
3141 * Add it to the tail of the list after checking for prior registration.
3142 */
3143 rc = RTSemFastMutexRequest(pSession->pDevExt->mtxComponentFactory);
3144 if (RT_SUCCESS(rc))
3145 {
3146 PSUPDRVFACTORYREG pPrev = NULL;
3147 PSUPDRVFACTORYREG pCur = pSession->pDevExt->pComponentFactoryHead;
3148 while (pCur && pCur->pFactory != pFactory)
3149 {
3150 pPrev = pCur;
3151 pCur = pCur->pNext;
3152 }
3153 if (!pCur)
3154 {
3155 if (pPrev)
3156 pPrev->pNext = pNewReg;
3157 else
3158 pSession->pDevExt->pComponentFactoryHead = pNewReg;
3159 rc = VINF_SUCCESS;
3160 }
3161 else
3162 rc = VERR_ALREADY_EXISTS;
3163
3164 RTSemFastMutexRelease(pSession->pDevExt->mtxComponentFactory);
3165 }
3166
3167 if (RT_FAILURE(rc))
3168 RTMemFree(pNewReg);
3169 }
3170 else
3171 rc = VERR_NO_MEMORY;
3172 return rc;
3173}
3174
3175
3176/**
3177 * Deregister a component factory.
3178 *
3179 * @returns VBox status code.
3180 * @retval VINF_SUCCESS on success.
3181 * @retval VERR_NOT_FOUND if the factory wasn't registered.
3182 * @retval VERR_ACCESS_DENIED if it isn't a kernel session.
3183 * @retval VERR_INVALID_PARAMETER on invalid parameter.
3184 * @retval VERR_INVALID_POINTER on invalid pointer parameter.
3185 *
3186 * @param pSession The SUPDRV session (must be a ring-0 session).
3187 * @param pFactory Pointer to the component factory registration structure
3188 * previously passed SUPR0ComponentRegisterFactory().
3189 *
3190 * @remarks This interface is also available via SUPR0IdcComponentDeregisterFactory.
3191 */
3192SUPR0DECL(int) SUPR0ComponentDeregisterFactory(PSUPDRVSESSION pSession, PCSUPDRVFACTORY pFactory)
3193{
3194 int rc;
3195
3196 /*
3197 * Validate parameters.
3198 */
3199 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
3200 AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_ACCESS_DENIED);
3201 AssertPtrReturn(pFactory, VERR_INVALID_POINTER);
3202
3203 /*
3204 * Take the lock and look for the registration record.
3205 */
3206 rc = RTSemFastMutexRequest(pSession->pDevExt->mtxComponentFactory);
3207 if (RT_SUCCESS(rc))
3208 {
3209 PSUPDRVFACTORYREG pPrev = NULL;
3210 PSUPDRVFACTORYREG pCur = pSession->pDevExt->pComponentFactoryHead;
3211 while (pCur && pCur->pFactory != pFactory)
3212 {
3213 pPrev = pCur;
3214 pCur = pCur->pNext;
3215 }
3216 if (pCur)
3217 {
3218 if (!pPrev)
3219 pSession->pDevExt->pComponentFactoryHead = pCur->pNext;
3220 else
3221 pPrev->pNext = pCur->pNext;
3222
3223 pCur->pNext = NULL;
3224 pCur->pFactory = NULL;
3225 pCur->pSession = NULL;
3226 rc = VINF_SUCCESS;
3227 }
3228 else
3229 rc = VERR_NOT_FOUND;
3230
3231 RTSemFastMutexRelease(pSession->pDevExt->mtxComponentFactory);
3232
3233 RTMemFree(pCur);
3234 }
3235 return rc;
3236}
3237
3238
3239/**
3240 * Queries a component factory.
3241 *
3242 * @returns VBox status code.
3243 * @retval VERR_INVALID_PARAMETER on invalid parameter.
3244 * @retval VERR_INVALID_POINTER on invalid pointer parameter.
3245 * @retval VERR_SUPDRV_COMPONENT_NOT_FOUND if the component factory wasn't found.
3246 * @retval VERR_SUPDRV_INTERFACE_NOT_SUPPORTED if the interface wasn't supported.
3247 *
3248 * @param pSession The SUPDRV session.
3249 * @param pszName The name of the component factory.
3250 * @param pszInterfaceUuid The UUID of the factory interface (stringified).
3251 * @param ppvFactoryIf Where to store the factory interface.
3252 */
3253SUPR0DECL(int) SUPR0ComponentQueryFactory(PSUPDRVSESSION pSession, const char *pszName, const char *pszInterfaceUuid, void **ppvFactoryIf)
3254{
3255 const char *pszEnd;
3256 size_t cchName;
3257 int rc;
3258
3259 /*
3260 * Validate parameters.
3261 */
3262 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
3263
3264 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
3265 pszEnd = memchr(pszName, '\0', RT_SIZEOFMEMB(SUPDRVFACTORY, szName));
3266 AssertReturn(pszEnd, VERR_INVALID_PARAMETER);
3267 cchName = pszEnd - pszName;
3268
3269 AssertPtrReturn(pszInterfaceUuid, VERR_INVALID_POINTER);
3270 pszEnd = memchr(pszInterfaceUuid, '\0', RTUUID_STR_LENGTH);
3271 AssertReturn(pszEnd, VERR_INVALID_PARAMETER);
3272
3273 AssertPtrReturn(ppvFactoryIf, VERR_INVALID_POINTER);
3274 *ppvFactoryIf = NULL;
3275
3276 /*
3277 * Take the lock and try all factories by this name.
3278 */
3279 rc = RTSemFastMutexRequest(pSession->pDevExt->mtxComponentFactory);
3280 if (RT_SUCCESS(rc))
3281 {
3282 PSUPDRVFACTORYREG pCur = pSession->pDevExt->pComponentFactoryHead;
3283 rc = VERR_SUPDRV_COMPONENT_NOT_FOUND;
3284 while (pCur)
3285 {
3286 if ( pCur->cchName == cchName
3287 && !memcmp(pCur->pFactory->szName, pszName, cchName))
3288 {
3289#ifdef RT_WITH_W64_UNWIND_HACK
3290 void *pvFactory = supdrvNtWrapQueryFactoryInterface((PFNRT)pCur->pFactory->pfnQueryFactoryInterface, pCur->pFactory, pSession, pszInterfaceUuid);
3291#else
3292 void *pvFactory = pCur->pFactory->pfnQueryFactoryInterface(pCur->pFactory, pSession, pszInterfaceUuid);
3293#endif
3294 if (pvFactory)
3295 {
3296 *ppvFactoryIf = pvFactory;
3297 rc = VINF_SUCCESS;
3298 break;
3299 }
3300 rc = VERR_SUPDRV_INTERFACE_NOT_SUPPORTED;
3301 }
3302
3303 /* next */
3304 pCur = pCur->pNext;
3305 }
3306
3307 RTSemFastMutexRelease(pSession->pDevExt->mtxComponentFactory);
3308 }
3309 return rc;
3310}
3311
3312
3313/**
3314 * Adds a memory object to the session.
3315 *
3316 * @returns IPRT status code.
3317 * @param pMem Memory tracking structure containing the
3318 * information to track.
3319 * @param pSession The session.
3320 */
3321static int supdrvMemAdd(PSUPDRVMEMREF pMem, PSUPDRVSESSION pSession)
3322{
3323 PSUPDRVBUNDLE pBundle;
3324 RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
3325
3326 /*
3327 * Find free entry and record the allocation.
3328 */
3329 RTSpinlockAcquire(pSession->Spinlock, &SpinlockTmp);
3330 for (pBundle = &pSession->Bundle; pBundle; pBundle = pBundle->pNext)
3331 {
3332 if (pBundle->cUsed < RT_ELEMENTS(pBundle->aMem))
3333 {
3334 unsigned i;
3335 for (i = 0; i < RT_ELEMENTS(pBundle->aMem); i++)
3336 {
3337 if (pBundle->aMem[i].MemObj == NIL_RTR0MEMOBJ)
3338 {
3339 pBundle->cUsed++;
3340 pBundle->aMem[i] = *pMem;
3341 RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
3342 return VINF_SUCCESS;
3343 }
3344 }
3345 AssertFailed(); /* !!this can't be happening!!! */
3346 }
3347 }
3348 RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
3349
3350 /*
3351 * Need to allocate a new bundle.
3352 * Insert into the last entry in the bundle.
3353 */
3354 pBundle = (PSUPDRVBUNDLE)RTMemAllocZ(sizeof(*pBundle));
3355 if (!pBundle)
3356 return VERR_NO_MEMORY;
3357
3358 /* take last entry. */
3359 pBundle->cUsed++;
3360 pBundle->aMem[RT_ELEMENTS(pBundle->aMem) - 1] = *pMem;
3361
3362 /* insert into list. */
3363 RTSpinlockAcquire(pSession->Spinlock, &SpinlockTmp);
3364 pBundle->pNext = pSession->Bundle.pNext;
3365 pSession->Bundle.pNext = pBundle;
3366 RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
3367
3368 return VINF_SUCCESS;
3369}
3370
3371
3372/**
3373 * Releases a memory object referenced by pointer and type.
3374 *
3375 * @returns IPRT status code.
3376 * @param pSession Session data.
3377 * @param uPtr Pointer to memory. This is matched against both the R0 and R3 addresses.
3378 * @param eType Memory type.
3379 */
3380static int supdrvMemRelease(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr, SUPDRVMEMREFTYPE eType)
3381{
3382 PSUPDRVBUNDLE pBundle;
3383 RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
3384
3385 /*
3386 * Validate input.
3387 */
3388 if (!uPtr)
3389 {
3390 Log(("Illegal address %p\n", (void *)uPtr));
3391 return VERR_INVALID_PARAMETER;
3392 }
3393
3394 /*
3395 * Search for the address.
3396 */
3397 RTSpinlockAcquire(pSession->Spinlock, &SpinlockTmp);
3398 for (pBundle = &pSession->Bundle; pBundle; pBundle = pBundle->pNext)
3399 {
3400 if (pBundle->cUsed > 0)
3401 {
3402 unsigned i;
3403 for (i = 0; i < RT_ELEMENTS(pBundle->aMem); i++)
3404 {
3405 if ( pBundle->aMem[i].eType == eType
3406 && pBundle->aMem[i].MemObj != NIL_RTR0MEMOBJ
3407 && ( (RTHCUINTPTR)RTR0MemObjAddress(pBundle->aMem[i].MemObj) == uPtr
3408 || ( pBundle->aMem[i].MapObjR3 != NIL_RTR0MEMOBJ
3409 && RTR0MemObjAddressR3(pBundle->aMem[i].MapObjR3) == uPtr))
3410 )
3411 {
3412 /* Make a copy of it and release it outside the spinlock. */
3413 SUPDRVMEMREF Mem = pBundle->aMem[i];
3414 pBundle->aMem[i].eType = MEMREF_TYPE_UNUSED;
3415 pBundle->aMem[i].MemObj = NIL_RTR0MEMOBJ;
3416 pBundle->aMem[i].MapObjR3 = NIL_RTR0MEMOBJ;
3417 RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
3418
3419 if (Mem.MapObjR3 != NIL_RTR0MEMOBJ)
3420 {
3421 int rc = RTR0MemObjFree(Mem.MapObjR3, false);
3422 AssertRC(rc); /** @todo figure out how to handle this. */
3423 }
3424 if (Mem.MemObj != NIL_RTR0MEMOBJ)
3425 {
3426 int rc = RTR0MemObjFree(Mem.MemObj, true /* fFreeMappings */);
3427 AssertRC(rc); /** @todo figure out how to handle this. */
3428 }
3429 return VINF_SUCCESS;
3430 }
3431 }
3432 }
3433 }
3434 RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
3435 Log(("Failed to find %p!!! (eType=%d)\n", (void *)uPtr, eType));
3436 return VERR_INVALID_PARAMETER;
3437}
3438
3439
3440/**
3441 * Opens an image. If it's the first time it's opened the call must upload
3442 * the bits using the supdrvIOCtl_LdrLoad() / SUPDRV_IOCTL_LDR_LOAD function.
3443 *
3444 * This is the 1st step of the loading.
3445 *
3446 * @returns IPRT status code.
3447 * @param pDevExt Device globals.
3448 * @param pSession Session data.
3449 * @param pReq The open request.
3450 */
3451static int supdrvIOCtl_LdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDROPEN pReq)
3452{
3453 int rc;
3454 PSUPDRVLDRIMAGE pImage;
3455 void *pv;
3456 size_t cchName = strlen(pReq->u.In.szName); /* (caller checked < 32). */
3457 LogFlow(("supdrvIOCtl_LdrOpen: szName=%s cbImageWithTabs=%d\n", pReq->u.In.szName, pReq->u.In.cbImageWithTabs));
3458
3459 /*
3460 * Check if we got an instance of the image already.
3461 */
3462 RTSemFastMutexRequest(pDevExt->mtxLdr);
3463 for (pImage = pDevExt->pLdrImages; pImage; pImage = pImage->pNext)
3464 {
3465 if ( pImage->szName[cchName] == '\0'
3466 && !memcmp(pImage->szName, pReq->u.In.szName, cchName))
3467 {
3468 /** @todo check cbImageBits and cbImageWithTabs here, if they differs that indicates that the images are different. */
3469 pImage->cUsage++;
3470 pReq->u.Out.pvImageBase = pImage->pvImage;
3471 pReq->u.Out.fNeedsLoading = pImage->uState == SUP_IOCTL_LDR_OPEN;
3472#ifdef VBOX_WITH_NATIVE_R0_LOADER
3473 pReq->u.Out.fNativeLoader = pImage->fNative;
3474#endif
3475 supdrvLdrAddUsage(pSession, pImage);
3476 RTSemFastMutexRelease(pDevExt->mtxLdr);
3477 return VINF_SUCCESS;
3478 }
3479 }
3480 /* (not found - add it!) */
3481
3482 /*
3483 * Allocate memory.
3484 */
3485 pv = RTMemAlloc(RT_OFFSETOF(SUPDRVLDRIMAGE, szName[cchName + 1]));
3486 if (!pv)
3487 {
3488 RTSemFastMutexRelease(pDevExt->mtxLdr);
3489 Log(("supdrvIOCtl_LdrOpen: RTMemAlloc() failed\n"));
3490 return VERR_NO_MEMORY;
3491 }
3492
3493 /*
3494 * Setup and link in the LDR stuff.
3495 */
3496 pImage = (PSUPDRVLDRIMAGE)pv;
3497 pImage->pvImage = NULL;
3498 pImage->pvImageAlloc = NULL;
3499 pImage->cbImageWithTabs = pReq->u.In.cbImageWithTabs;
3500#ifdef VBOX_WITH_NATIVE_R0_LOADER
3501 pImage->cbImageBits = pReq->u.In.cbImageBits;
3502#else
3503 pImage->cbImageBits = pReq->u.In.cbImageWithTabs;
3504#endif
3505 pImage->cSymbols = 0;
3506 pImage->paSymbols = NULL;
3507 pImage->pachStrTab = NULL;
3508 pImage->cbStrTab = 0;
3509 pImage->pfnModuleInit = NULL;
3510 pImage->pfnModuleTerm = NULL;
3511 pImage->pfnServiceReqHandler = NULL;
3512 pImage->uState = SUP_IOCTL_LDR_OPEN;
3513 pImage->cUsage = 1;
3514 memcpy(pImage->szName, pReq->u.In.szName, cchName + 1);
3515
3516 /*
3517 * Try load it using the native loader, if that isn't supported, fall back
3518 * on the older method.
3519 */
3520#ifdef VBOX_WITH_NATIVE_R0_LOADER
3521 pImage->fNative = true;
3522 RTSemFastMutexRelease(pDevExt->mtxLdr); /*hack*/
3523 rc = supdrvOSLdrOpen(pDevExt, pImage, pReq->u.In.szFilename);
3524 RTSemFastMutexRequest(pDevExt->mtxLdr); /*hack*/
3525#else
3526 rc = VERR_NOT_SUPPORTED;
3527#endif
3528 if (rc == VERR_NOT_SUPPORTED)
3529 {
3530 pImage->pvImageAlloc = RTMemExecAlloc(pImage->cbImageBits + 31);
3531 pImage->pvImage = RT_ALIGN_P(pImage->pvImageAlloc, 32);
3532#ifdef VBOX_WITH_NATIVE_R0_LOADER
3533 pImage->fNative = false;
3534#endif
3535 rc = pImage->pvImageAlloc ? VINF_SUCCESS : VERR_NO_MEMORY;
3536 }
3537 if (RT_FAILURE(rc))
3538 {
3539 RTSemFastMutexRelease(pDevExt->mtxLdr);
3540 RTMemFree(pImage);
3541 Log(("supdrvIOCtl_LdrOpen(%s): failed - %Rrc\n", pReq->u.In.szName, rc));
3542 return rc;
3543 }
3544 Assert(VALID_PTR(pImage->pvImage) || RT_FAILURE(rc));
3545
3546 /*
3547 * Link it.
3548 */
3549 pImage->pNext = pDevExt->pLdrImages;
3550 pDevExt->pLdrImages = pImage;
3551
3552 supdrvLdrAddUsage(pSession, pImage);
3553
3554 pReq->u.Out.pvImageBase = pImage->pvImage;
3555 pReq->u.Out.fNeedsLoading = true;
3556#ifdef VBOX_WITH_NATIVE_R0_LOADER
3557 pReq->u.Out.fNativeLoader = pImage->fNative;
3558#endif
3559 RTSemFastMutexRelease(pDevExt->mtxLdr);
3560
3561#if defined(RT_OS_WINDOWS) && defined(DEBUG)
3562 SUPR0Printf("VBoxDrv: windbg> .reload /f %s=%#p\n", pImage->szName, pImage->pvImage);
3563#endif
3564 return VINF_SUCCESS;
3565}
3566
3567
3568/**
3569 * Worker that validates a pointer to an image entrypoint.
3570 *
3571 * @returns IPRT status code.
3572 * @param pDevExt The device globals.
3573 * @param pImage The loader image.
3574 * @param pv The pointer into the image.
3575 * @param fMayBeNull Whether it may be NULL.
3576 * @param pszWhat What is this entrypoint? (for logging)
3577 * @param pbImageBits The image bits prepared by ring-3.
3578 *
3579 * @remarks Will leave the lock on failure.
3580 */
3581static int supdrvLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv,
3582 bool fMayBeNull, const uint8_t *pbImageBits, const char *pszWhat)
3583{
3584 if (!fMayBeNull || pv)
3585 {
3586 if ((uintptr_t)pv - (uintptr_t)pImage->pvImage >= pImage->cbImageBits)
3587 {
3588 RTSemFastMutexRelease(pDevExt->mtxLdr);
3589 Log(("Out of range (%p LB %#x): %s=%p\n", pImage->pvImage, pImage->cbImageBits, pszWhat, pv));
3590 return VERR_INVALID_PARAMETER;
3591 }
3592
3593#ifdef VBOX_WITH_NATIVE_R0_LOADER
3594 if (pImage->fNative)
3595 {
3596 int rc = supdrvOSLdrValidatePointer(pDevExt, pImage, pv, pbImageBits);
3597 if (RT_FAILURE(rc))
3598 {
3599 RTSemFastMutexRelease(pDevExt->mtxLdr);
3600 Log(("Bad entry point address: %s=%p (rc=%Rrc)\n", pszWhat, pv, rc));
3601 return rc;
3602 }
3603 }
3604#endif
3605 }
3606 return VINF_SUCCESS;
3607}
3608
3609
3610/**
3611 * Loads the image bits.
3612 *
3613 * This is the 2nd step of the loading.
3614 *
3615 * @returns IPRT status code.
3616 * @param pDevExt Device globals.
3617 * @param pSession Session data.
3618 * @param pReq The request.
3619 */
3620static int supdrvIOCtl_LdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDRLOAD pReq)
3621{
3622 PSUPDRVLDRUSAGE pUsage;
3623 PSUPDRVLDRIMAGE pImage;
3624 int rc;
3625 LogFlow(("supdrvIOCtl_LdrLoad: pvImageBase=%p cbImageWithBits=%d\n", pReq->u.In.pvImageBase, pReq->u.In.cbImageWithTabs));
3626
3627 /*
3628 * Find the ldr image.
3629 */
3630 RTSemFastMutexRequest(pDevExt->mtxLdr);
3631 pUsage = pSession->pLdrUsage;
3632 while (pUsage && pUsage->pImage->pvImage != pReq->u.In.pvImageBase)
3633 pUsage = pUsage->pNext;
3634 if (!pUsage)
3635 {
3636 RTSemFastMutexRelease(pDevExt->mtxLdr);
3637 Log(("SUP_IOCTL_LDR_LOAD: couldn't find image!\n"));
3638 return VERR_INVALID_HANDLE;
3639 }
3640 pImage = pUsage->pImage;
3641
3642 /*
3643 * Validate input.
3644 */
3645#ifdef VBOX_WITH_NATIVE_R0_LOADER
3646 if ( pImage->cbImageWithTabs != pReq->u.In.cbImageWithTabs
3647 || pImage->cbImageBits != pReq->u.In.cbImageBits)
3648#else
3649 if (pImage->cbImageWithTabs != pReq->u.In.cbImageWithTabs)
3650#endif
3651 {
3652 RTSemFastMutexRelease(pDevExt->mtxLdr);
3653#ifdef VBOX_WITH_NATIVE_R0_LOADER
3654 Log(("SUP_IOCTL_LDR_LOAD: image size mismatch!! %d(prep) != %d(load) or %d != %d\n",
3655 pImage->cbImageWithTabs, pReq->u.In.cbImageWithTabs, pImage->cbImageBits, pReq->u.In.cbImageBits));
3656#else
3657 Log(("SUP_IOCTL_LDR_LOAD: image size mismatch!! %d(prep) != %d(load)\n", pImage->cbImageWithTabs, pReq->u.In.cbImageWithTabs));
3658#endif
3659 return VERR_INVALID_HANDLE;
3660 }
3661
3662 if (pImage->uState != SUP_IOCTL_LDR_OPEN)
3663 {
3664 unsigned uState = pImage->uState;
3665 RTSemFastMutexRelease(pDevExt->mtxLdr);
3666 if (uState != SUP_IOCTL_LDR_LOAD)
3667 AssertMsgFailed(("SUP_IOCTL_LDR_LOAD: invalid image state %d (%#x)!\n", uState, uState));
3668 return SUPDRV_ERR_ALREADY_LOADED;
3669 }
3670
3671 switch (pReq->u.In.eEPType)
3672 {
3673 case SUPLDRLOADEP_NOTHING:
3674 break;
3675
3676 case SUPLDRLOADEP_VMMR0:
3677 rc = supdrvLdrValidatePointer( pDevExt, pImage, pReq->u.In.EP.VMMR0.pvVMMR0, false, pReq->u.In.achImage, "pvVMMR0");
3678 if (RT_SUCCESS(rc))
3679 rc = supdrvLdrValidatePointer(pDevExt, pImage, pReq->u.In.EP.VMMR0.pvVMMR0EntryInt, false, pReq->u.In.achImage, "pvVMMR0EntryInt");
3680 if (RT_SUCCESS(rc))
3681 rc = supdrvLdrValidatePointer(pDevExt, pImage, pReq->u.In.EP.VMMR0.pvVMMR0EntryFast, false, pReq->u.In.achImage, "pvVMMR0EntryFast");
3682 if (RT_SUCCESS(rc))
3683 rc = supdrvLdrValidatePointer(pDevExt, pImage, pReq->u.In.EP.VMMR0.pvVMMR0EntryEx, false, pReq->u.In.achImage, "pvVMMR0EntryEx");
3684 if (RT_FAILURE(rc))
3685 return rc;
3686 break;
3687
3688 case SUPLDRLOADEP_SERVICE:
3689 rc = supdrvLdrValidatePointer(pDevExt, pImage, pReq->u.In.EP.Service.pfnServiceReq, false, pReq->u.In.achImage, "pfnServiceReq");
3690 if (RT_FAILURE(rc))
3691 return rc;
3692 if ( pReq->u.In.EP.Service.apvReserved[0] != NIL_RTR0PTR
3693 || pReq->u.In.EP.Service.apvReserved[1] != NIL_RTR0PTR
3694 || pReq->u.In.EP.Service.apvReserved[2] != NIL_RTR0PTR)
3695 {
3696 RTSemFastMutexRelease(pDevExt->mtxLdr);
3697 Log(("Out of range (%p LB %#x): apvReserved={%p,%p,%p} MBZ!\n",
3698 pImage->pvImage, pReq->u.In.cbImageWithTabs,
3699 pReq->u.In.EP.Service.apvReserved[0],
3700 pReq->u.In.EP.Service.apvReserved[1],
3701 pReq->u.In.EP.Service.apvReserved[2]));
3702 return VERR_INVALID_PARAMETER;
3703 }
3704 break;
3705
3706 default:
3707 RTSemFastMutexRelease(pDevExt->mtxLdr);
3708 Log(("Invalid eEPType=%d\n", pReq->u.In.eEPType));
3709 return VERR_INVALID_PARAMETER;
3710 }
3711
3712 rc = supdrvLdrValidatePointer(pDevExt, pImage, pReq->u.In.pfnModuleInit, true, pReq->u.In.achImage, "pfnModuleInit");
3713 if (RT_FAILURE(rc))
3714 return rc;
3715 rc = supdrvLdrValidatePointer(pDevExt, pImage, pReq->u.In.pfnModuleTerm, true, pReq->u.In.achImage, "pfnModuleTerm");
3716 if (RT_FAILURE(rc))
3717 return rc;
3718
3719 /*
3720 * Allocate and copy the tables.
3721 * (No need to do try/except as this is a buffered request.)
3722 */
3723 pImage->cbStrTab = pReq->u.In.cbStrTab;
3724 if (pImage->cbStrTab)
3725 {
3726 pImage->pachStrTab = (char *)RTMemAlloc(pImage->cbStrTab);
3727 if (pImage->pachStrTab)
3728 memcpy(pImage->pachStrTab, &pReq->u.In.achImage[pReq->u.In.offStrTab], pImage->cbStrTab);
3729 else
3730 rc = VERR_NO_MEMORY;
3731 }
3732
3733 pImage->cSymbols = pReq->u.In.cSymbols;
3734 if (RT_SUCCESS(rc) && pImage->cSymbols)
3735 {
3736 size_t cbSymbols = pImage->cSymbols * sizeof(SUPLDRSYM);
3737 pImage->paSymbols = (PSUPLDRSYM)RTMemAlloc(cbSymbols);
3738 if (pImage->paSymbols)
3739 memcpy(pImage->paSymbols, &pReq->u.In.achImage[pReq->u.In.offSymbols], cbSymbols);
3740 else
3741 rc = VERR_NO_MEMORY;
3742 }
3743
3744 /*
3745 * Copy the bits / complete native loading.
3746 */
3747 if (RT_SUCCESS(rc))
3748 {
3749 pImage->uState = SUP_IOCTL_LDR_LOAD;
3750 pImage->pfnModuleInit = pReq->u.In.pfnModuleInit;
3751 pImage->pfnModuleTerm = pReq->u.In.pfnModuleTerm;
3752
3753#ifdef VBOX_WITH_NATIVE_R0_LOADER
3754 if (pImage->fNative)
3755 rc = supdrvOSLdrLoad(pDevExt, pImage, pReq->u.In.achImage);
3756 else
3757#endif
3758 memcpy(pImage->pvImage, &pReq->u.In.achImage[0], pImage->cbImageBits);
3759 }
3760
3761 /*
3762 * Update any entry points.
3763 */
3764 if (RT_SUCCESS(rc))
3765 {
3766 switch (pReq->u.In.eEPType)
3767 {
3768 default:
3769 case SUPLDRLOADEP_NOTHING:
3770 rc = VINF_SUCCESS;
3771 break;
3772 case SUPLDRLOADEP_VMMR0:
3773 rc = supdrvLdrSetVMMR0EPs(pDevExt, pReq->u.In.EP.VMMR0.pvVMMR0, pReq->u.In.EP.VMMR0.pvVMMR0EntryInt,
3774 pReq->u.In.EP.VMMR0.pvVMMR0EntryFast, pReq->u.In.EP.VMMR0.pvVMMR0EntryEx);
3775 break;
3776 case SUPLDRLOADEP_SERVICE:
3777 pImage->pfnServiceReqHandler = pReq->u.In.EP.Service.pfnServiceReq;
3778 rc = VINF_SUCCESS;
3779 break;
3780 }
3781 }
3782
3783 /*
3784 * On success call the module initialization.
3785 */
3786 LogFlow(("supdrvIOCtl_LdrLoad: pfnModuleInit=%p\n", pImage->pfnModuleInit));
3787 if (RT_SUCCESS(rc) && pImage->pfnModuleInit)
3788 {
3789 Log(("supdrvIOCtl_LdrLoad: calling pfnModuleInit=%p\n", pImage->pfnModuleInit));
3790#ifdef RT_WITH_W64_UNWIND_HACK
3791 rc = supdrvNtWrapModuleInit((PFNRT)pImage->pfnModuleInit);
3792#else
3793 rc = pImage->pfnModuleInit();
3794#endif
3795 if (rc && pDevExt->pvVMMR0 == pImage->pvImage)
3796 supdrvLdrUnsetVMMR0EPs(pDevExt);
3797 }
3798
3799 if (RT_FAILURE(rc))
3800 {
3801 pImage->uState = SUP_IOCTL_LDR_OPEN;
3802 pImage->pfnModuleInit = NULL;
3803 pImage->pfnModuleTerm = NULL;
3804 pImage->pfnServiceReqHandler= NULL;
3805 pImage->cbStrTab = 0;
3806 RTMemFree(pImage->pachStrTab);
3807 pImage->pachStrTab = NULL;
3808 RTMemFree(pImage->paSymbols);
3809 pImage->paSymbols = NULL;
3810 pImage->cSymbols = 0;
3811 }
3812
3813 RTSemFastMutexRelease(pDevExt->mtxLdr);
3814 return rc;
3815}
3816
3817
3818/**
3819 * Frees a previously loaded (prep'ed) image.
3820 *
3821 * @returns IPRT status code.
3822 * @param pDevExt Device globals.
3823 * @param pSession Session data.
3824 * @param pReq The request.
3825 */
3826static int supdrvIOCtl_LdrFree(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDRFREE pReq)
3827{
3828 int rc;
3829 PSUPDRVLDRUSAGE pUsagePrev;
3830 PSUPDRVLDRUSAGE pUsage;
3831 PSUPDRVLDRIMAGE pImage;
3832 LogFlow(("supdrvIOCtl_LdrFree: pvImageBase=%p\n", pReq->u.In.pvImageBase));
3833
3834 /*
3835 * Find the ldr image.
3836 */
3837 RTSemFastMutexRequest(pDevExt->mtxLdr);
3838 pUsagePrev = NULL;
3839 pUsage = pSession->pLdrUsage;
3840 while (pUsage && pUsage->pImage->pvImage != pReq->u.In.pvImageBase)
3841 {
3842 pUsagePrev = pUsage;
3843 pUsage = pUsage->pNext;
3844 }
3845 if (!pUsage)
3846 {
3847 RTSemFastMutexRelease(pDevExt->mtxLdr);
3848 Log(("SUP_IOCTL_LDR_FREE: couldn't find image!\n"));
3849 return VERR_INVALID_HANDLE;
3850 }
3851
3852 /*
3853 * Check if we can remove anything.
3854 */
3855 rc = VINF_SUCCESS;
3856 pImage = pUsage->pImage;
3857 if (pImage->cUsage <= 1 || pUsage->cUsage <= 1)
3858 {
3859 /*
3860 * Check if there are any objects with destructors in the image, if
3861 * so leave it for the session cleanup routine so we get a chance to
3862 * clean things up in the right order and not leave them all dangling.
3863 */
3864 RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
3865 RTSpinlockAcquire(pDevExt->Spinlock, &SpinlockTmp);
3866 if (pImage->cUsage <= 1)
3867 {
3868 PSUPDRVOBJ pObj;
3869 for (pObj = pDevExt->pObjs; pObj; pObj = pObj->pNext)
3870 if (RT_UNLIKELY((uintptr_t)pObj->pfnDestructor - (uintptr_t)pImage->pvImage < pImage->cbImageBits))
3871 {
3872 rc = VERR_DANGLING_OBJECTS;
3873 break;
3874 }
3875 }
3876 else
3877 {
3878 PSUPDRVUSAGE pGenUsage;
3879 for (pGenUsage = pSession->pUsage; pGenUsage; pGenUsage = pGenUsage->pNext)
3880 if (RT_UNLIKELY((uintptr_t)pGenUsage->pObj->pfnDestructor - (uintptr_t)pImage->pvImage < pImage->cbImageBits))
3881 {
3882 rc = VERR_DANGLING_OBJECTS;
3883 break;
3884 }
3885 }
3886 RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
3887 if (rc == VINF_SUCCESS)
3888 {
3889 /* unlink it */
3890 if (pUsagePrev)
3891 pUsagePrev->pNext = pUsage->pNext;
3892 else
3893 pSession->pLdrUsage = pUsage->pNext;
3894
3895 /* free it */
3896 pUsage->pImage = NULL;
3897 pUsage->pNext = NULL;
3898 RTMemFree(pUsage);
3899
3900 /*
3901 * Dereference the image.
3902 */
3903 if (pImage->cUsage <= 1)
3904 supdrvLdrFree(pDevExt, pImage);
3905 else
3906 pImage->cUsage--;
3907 }
3908 else
3909 {
3910 Log(("supdrvIOCtl_LdrFree: Dangling objects in %p/%s!\n", pImage->pvImage, pImage->szName));
3911 rc = VINF_SUCCESS; /** @todo BRANCH-2.1: remove this after branching. */
3912 }
3913 }
3914 else
3915 {
3916 /*
3917 * Dereference both image and usage.
3918 */
3919 pImage->cUsage--;
3920 pUsage->cUsage--;
3921 }
3922
3923 RTSemFastMutexRelease(pDevExt->mtxLdr);
3924 return rc;
3925}
3926
3927
3928/**
3929 * Gets the address of a symbol in an open image.
3930 *
3931 * @returns 0 on success.
3932 * @returns SUPDRV_ERR_* on failure.
3933 * @param pDevExt Device globals.
3934 * @param pSession Session data.
3935 * @param pReq The request buffer.
3936 */
3937static int supdrvIOCtl_LdrGetSymbol(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDRGETSYMBOL pReq)
3938{
3939 PSUPDRVLDRIMAGE pImage;
3940 PSUPDRVLDRUSAGE pUsage;
3941 uint32_t i;
3942 PSUPLDRSYM paSyms;
3943 const char *pchStrings;
3944 const size_t cbSymbol = strlen(pReq->u.In.szSymbol) + 1;
3945 void *pvSymbol = NULL;
3946 int rc = VERR_GENERAL_FAILURE;
3947 Log3(("supdrvIOCtl_LdrGetSymbol: pvImageBase=%p szSymbol=\"%s\"\n", pReq->u.In.pvImageBase, pReq->u.In.szSymbol));
3948
3949 /*
3950 * Find the ldr image.
3951 */
3952 RTSemFastMutexRequest(pDevExt->mtxLdr);
3953 pUsage = pSession->pLdrUsage;
3954 while (pUsage && pUsage->pImage->pvImage != pReq->u.In.pvImageBase)
3955 pUsage = pUsage->pNext;
3956 if (!pUsage)
3957 {
3958 RTSemFastMutexRelease(pDevExt->mtxLdr);
3959 Log(("SUP_IOCTL_LDR_GET_SYMBOL: couldn't find image!\n"));
3960 return VERR_INVALID_HANDLE;
3961 }
3962 pImage = pUsage->pImage;
3963 if (pImage->uState != SUP_IOCTL_LDR_LOAD)
3964 {
3965 unsigned uState = pImage->uState;
3966 RTSemFastMutexRelease(pDevExt->mtxLdr);
3967 Log(("SUP_IOCTL_LDR_GET_SYMBOL: invalid image state %d (%#x)!\n", uState, uState)); NOREF(uState);
3968 return VERR_ALREADY_LOADED;
3969 }
3970
3971 /*
3972 * Search the symbol strings.
3973 */
3974 pchStrings = pImage->pachStrTab;
3975 paSyms = pImage->paSymbols;
3976 for (i = 0; i < pImage->cSymbols; i++)
3977 {
3978 if ( paSyms[i].offSymbol < pImage->cbImageBits /* paranoia */
3979 && paSyms[i].offName + cbSymbol <= pImage->cbStrTab
3980 && !memcmp(pchStrings + paSyms[i].offName, pReq->u.In.szSymbol, cbSymbol))
3981 {
3982 pvSymbol = (uint8_t *)pImage->pvImage + paSyms[i].offSymbol;
3983 rc = VINF_SUCCESS;
3984 break;
3985 }
3986 }
3987 RTSemFastMutexRelease(pDevExt->mtxLdr);
3988 pReq->u.Out.pvSymbol = pvSymbol;
3989 return rc;
3990}
3991
3992
3993/**
3994 * Gets the address of a symbol in an open image or the support driver.
3995 *
3996 * @returns VINF_SUCCESS on success.
3997 * @returns
3998 * @param pDevExt Device globals.
3999 * @param pSession Session data.
4000 * @param pReq The request buffer.
4001 */
4002static int supdrvIDC_LdrGetSymbol(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPDRVIDCREQGETSYM pReq)
4003{
4004 int rc = VINF_SUCCESS;
4005 const char *pszSymbol = pReq->u.In.pszSymbol;
4006 const char *pszModule = pReq->u.In.pszModule;
4007 size_t cbSymbol;
4008 char const *pszEnd;
4009 uint32_t i;
4010
4011 /*
4012 * Input validation.
4013 */
4014 AssertPtrReturn(pszSymbol, VERR_INVALID_POINTER);
4015 pszEnd = (char *)memchr(pszSymbol, '\0', 512);
4016 AssertReturn(pszEnd, VERR_INVALID_PARAMETER);
4017 cbSymbol = pszEnd - pszSymbol + 1;
4018
4019 if (pszModule)
4020 {
4021 AssertPtrReturn(pszModule, VERR_INVALID_POINTER);
4022 pszEnd = (char *)memchr(pszModule, '\0', 64);
4023 AssertReturn(pszEnd, VERR_INVALID_PARAMETER);
4024 }
4025 Log3(("supdrvIDC_LdrGetSymbol: pszModule=%p:{%s} pszSymbol=%p:{%s}\n", pszModule, pszModule, pszSymbol, pszSymbol));
4026
4027
4028 if ( !pszModule
4029 || !strcmp(pszModule, "SupDrv"))
4030 {
4031 /*
4032 * Search the support driver export table.
4033 */
4034 for (i = 0; i < RT_ELEMENTS(g_aFunctions); i++)
4035 if (!strcmp(g_aFunctions[i].szName, pszSymbol))
4036 {
4037 pReq->u.Out.pfnSymbol = g_aFunctions[i].pfn;
4038 break;
4039 }
4040 }
4041 else
4042 {
4043 /*
4044 * Find the loader image.
4045 */
4046 PSUPDRVLDRIMAGE pImage;
4047
4048 RTSemFastMutexRequest(pDevExt->mtxLdr);
4049
4050 for (pImage = pDevExt->pLdrImages; pImage; pImage = pImage->pNext)
4051 if (!strcmp(pImage->szName, pszModule))
4052 break;
4053 if (pImage && pImage->uState == SUP_IOCTL_LDR_LOAD)
4054 {
4055 /*
4056 * Search the symbol strings.
4057 */
4058 const char *pchStrings = pImage->pachStrTab;
4059 PCSUPLDRSYM paSyms = pImage->paSymbols;
4060 for (i = 0; i < pImage->cSymbols; i++)
4061 {
4062 if ( paSyms[i].offSymbol < pImage->cbImageBits /* paranoia */
4063 && paSyms[i].offName + cbSymbol <= pImage->cbStrTab
4064 && !memcmp(pchStrings + paSyms[i].offName, pszSymbol, cbSymbol))
4065 {
4066 /*
4067 * Found it! Calc the symbol address and add a reference to the module.
4068 */
4069 pReq->u.Out.pfnSymbol = (PFNRT)((uint8_t *)pImage->pvImage + paSyms[i].offSymbol);
4070 rc = supdrvLdrAddUsage(pSession, pImage);
4071 break;
4072 }
4073 }
4074 }
4075 else
4076 rc = pImage ? VERR_WRONG_ORDER : VERR_MODULE_NOT_FOUND;
4077
4078 RTSemFastMutexRelease(pDevExt->mtxLdr);
4079 }
4080 return rc;
4081}
4082
4083
4084/**
4085 * Updates the VMMR0 entry point pointers.
4086 *
4087 * @returns IPRT status code.
4088 * @param pDevExt Device globals.
4089 * @param pSession Session data.
4090 * @param pVMMR0 VMMR0 image handle.
4091 * @param pvVMMR0EntryInt VMMR0EntryInt address.
4092 * @param pvVMMR0EntryFast VMMR0EntryFast address.
4093 * @param pvVMMR0EntryEx VMMR0EntryEx address.
4094 * @remark Caller must own the loader mutex.
4095 */
4096static int supdrvLdrSetVMMR0EPs(PSUPDRVDEVEXT pDevExt, void *pvVMMR0, void *pvVMMR0EntryInt, void *pvVMMR0EntryFast, void *pvVMMR0EntryEx)
4097{
4098 int rc = VINF_SUCCESS;
4099 LogFlow(("supdrvLdrSetR0EP pvVMMR0=%p pvVMMR0EntryInt=%p\n", pvVMMR0, pvVMMR0EntryInt));
4100
4101
4102 /*
4103 * Check if not yet set.
4104 */
4105 if (!pDevExt->pvVMMR0)
4106 {
4107 pDevExt->pvVMMR0 = pvVMMR0;
4108 pDevExt->pfnVMMR0EntryInt = pvVMMR0EntryInt;
4109 pDevExt->pfnVMMR0EntryFast = pvVMMR0EntryFast;
4110 pDevExt->pfnVMMR0EntryEx = pvVMMR0EntryEx;
4111 }
4112 else
4113 {
4114 /*
4115 * Return failure or success depending on whether the values match or not.
4116 */
4117 if ( pDevExt->pvVMMR0 != pvVMMR0
4118 || (void *)pDevExt->pfnVMMR0EntryInt != pvVMMR0EntryInt
4119 || (void *)pDevExt->pfnVMMR0EntryFast != pvVMMR0EntryFast
4120 || (void *)pDevExt->pfnVMMR0EntryEx != pvVMMR0EntryEx)
4121 {
4122 AssertMsgFailed(("SUP_IOCTL_LDR_SETR0EP: Already set pointing to a different module!\n"));
4123 rc = VERR_INVALID_PARAMETER;
4124 }
4125 }
4126 return rc;
4127}
4128
4129
4130/**
4131 * Unsets the VMMR0 entry point installed by supdrvLdrSetR0EP.
4132 *
4133 * @param pDevExt Device globals.
4134 */
4135static void supdrvLdrUnsetVMMR0EPs(PSUPDRVDEVEXT pDevExt)
4136{
4137 pDevExt->pvVMMR0 = NULL;
4138 pDevExt->pfnVMMR0EntryInt = NULL;
4139 pDevExt->pfnVMMR0EntryFast = NULL;
4140 pDevExt->pfnVMMR0EntryEx = NULL;
4141}
4142
4143
4144/**
4145 * Adds a usage reference in the specified session of an image.
4146 *
4147 * Called while owning the loader semaphore.
4148 *
4149 * @returns VINF_SUCCESS on success and VERR_NO_MEMORY on failure.
4150 * @param pSession Session in question.
4151 * @param pImage Image which the session is using.
4152 */
4153static int supdrvLdrAddUsage(PSUPDRVSESSION pSession, PSUPDRVLDRIMAGE pImage)
4154{
4155 PSUPDRVLDRUSAGE pUsage;
4156 LogFlow(("supdrvLdrAddUsage: pImage=%p\n", pImage));
4157
4158 /*
4159 * Referenced it already?
4160 */
4161 pUsage = pSession->pLdrUsage;
4162 while (pUsage)
4163 {
4164 if (pUsage->pImage == pImage)
4165 {
4166 pUsage->cUsage++;
4167 return VINF_SUCCESS;
4168 }
4169 pUsage = pUsage->pNext;
4170 }
4171
4172 /*
4173 * Allocate new usage record.
4174 */
4175 pUsage = (PSUPDRVLDRUSAGE)RTMemAlloc(sizeof(*pUsage));
4176 AssertReturn(pUsage, VERR_NO_MEMORY);
4177 pUsage->cUsage = 1;
4178 pUsage->pImage = pImage;
4179 pUsage->pNext = pSession->pLdrUsage;
4180 pSession->pLdrUsage = pUsage;
4181 return VINF_SUCCESS;
4182}
4183
4184
4185/**
4186 * Frees a load image.
4187 *
4188 * @param pDevExt Pointer to device extension.
4189 * @param pImage Pointer to the image we're gonna free.
4190 * This image must exit!
4191 * @remark The caller MUST own SUPDRVDEVEXT::mtxLdr!
4192 */
4193static void supdrvLdrFree(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
4194{
4195 PSUPDRVLDRIMAGE pImagePrev;
4196 LogFlow(("supdrvLdrFree: pImage=%p\n", pImage));
4197
4198 /* find it - arg. should've used doubly linked list. */
4199 Assert(pDevExt->pLdrImages);
4200 pImagePrev = NULL;
4201 if (pDevExt->pLdrImages != pImage)
4202 {
4203 pImagePrev = pDevExt->pLdrImages;
4204 while (pImagePrev->pNext != pImage)
4205 pImagePrev = pImagePrev->pNext;
4206 Assert(pImagePrev->pNext == pImage);
4207 }
4208
4209 /* unlink */
4210 if (pImagePrev)
4211 pImagePrev->pNext = pImage->pNext;
4212 else
4213 pDevExt->pLdrImages = pImage->pNext;
4214
4215 /* check if this is VMMR0.r0 unset its entry point pointers. */
4216 if (pDevExt->pvVMMR0 == pImage->pvImage)
4217 supdrvLdrUnsetVMMR0EPs(pDevExt);
4218
4219 /* check for objects with destructors in this image. (Shouldn't happen.) */
4220 if (pDevExt->pObjs)
4221 {
4222 unsigned cObjs = 0;
4223 PSUPDRVOBJ pObj;
4224 RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
4225 RTSpinlockAcquire(pDevExt->Spinlock, &SpinlockTmp);
4226 for (pObj = pDevExt->pObjs; pObj; pObj = pObj->pNext)
4227 if (RT_UNLIKELY((uintptr_t)pObj->pfnDestructor - (uintptr_t)pImage->pvImage < pImage->cbImageBits))
4228 {
4229 pObj->pfnDestructor = NULL;
4230 cObjs++;
4231 }
4232 RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
4233 if (cObjs)
4234 OSDBGPRINT(("supdrvLdrFree: Image '%s' has %d dangling objects!\n", pImage->szName, cObjs));
4235 }
4236
4237 /* call termination function if fully loaded. */
4238 if ( pImage->pfnModuleTerm
4239 && pImage->uState == SUP_IOCTL_LDR_LOAD)
4240 {
4241 LogFlow(("supdrvIOCtl_LdrLoad: calling pfnModuleTerm=%p\n", pImage->pfnModuleTerm));
4242#ifdef RT_WITH_W64_UNWIND_HACK
4243 supdrvNtWrapModuleTerm(pImage->pfnModuleTerm);
4244#else
4245 pImage->pfnModuleTerm();
4246#endif
4247 }
4248
4249#ifdef VBOX_WITH_NATIVE_R0_LOADER
4250 /* do native unload if appropriate. */
4251 if (pImage->fNative)
4252 supdrvOSLdrUnload(pDevExt, pImage);
4253#endif
4254
4255 /* free the image */
4256 pImage->cUsage = 0;
4257 pImage->pNext = 0;
4258 pImage->uState = SUP_IOCTL_LDR_FREE;
4259 RTMemExecFree(pImage->pvImageAlloc);
4260 pImage->pvImageAlloc = NULL;
4261 RTMemFree(pImage->pachStrTab);
4262 pImage->pachStrTab = NULL;
4263 RTMemFree(pImage->paSymbols);
4264 pImage->paSymbols = NULL;
4265 RTMemFree(pImage);
4266}
4267
4268
4269/**
4270 * Implements the service call request.
4271 *
4272 * @returns VBox status code.
4273 * @param pDevExt The device extension.
4274 * @param pSession The calling session.
4275 * @param pReq The request packet, valid.
4276 */
4277static int supdrvIOCtl_CallServiceModule(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPCALLSERVICE pReq)
4278{
4279#if !defined(RT_OS_WINDOWS) || defined(DEBUG)
4280 int rc;
4281
4282 /*
4283 * Find the module first in the module referenced by the calling session.
4284 */
4285 rc = RTSemFastMutexRequest(pDevExt->mtxLdr);
4286 if (RT_SUCCESS(rc))
4287 {
4288 PFNSUPR0SERVICEREQHANDLER pfnServiceReqHandler = NULL;
4289 PSUPDRVLDRUSAGE pUsage;
4290
4291 for (pUsage = pSession->pLdrUsage; pUsage; pUsage = pUsage->pNext)
4292 if ( pUsage->pImage->pfnServiceReqHandler
4293 && !strcmp(pUsage->pImage->szName, pReq->u.In.szName))
4294 {
4295 pfnServiceReqHandler = pUsage->pImage->pfnServiceReqHandler;
4296 break;
4297 }
4298 RTSemFastMutexRelease(pDevExt->mtxLdr);
4299
4300 if (pfnServiceReqHandler)
4301 {
4302 /*
4303 * Call it.
4304 */
4305 if (pReq->Hdr.cbIn == SUP_IOCTL_CALL_SERVICE_SIZE(0))
4306#ifdef RT_WITH_W64_UNWIND_HACK
4307 rc = supdrvNtWrapServiceReqHandler((PFNRT)pfnServiceReqHandler, pSession, pReq->u.In.uOperation, pReq->u.In.u64Arg, NULL);
4308#else
4309 rc = pfnServiceReqHandler(pSession, pReq->u.In.uOperation, pReq->u.In.u64Arg, NULL);
4310#endif
4311 else
4312#ifdef RT_WITH_W64_UNWIND_HACK
4313 rc = supdrvNtWrapServiceReqHandler((PFNRT)pfnServiceReqHandler, pSession, pReq->u.In.uOperation,
4314 pReq->u.In.u64Arg, (PSUPR0SERVICEREQHDR)&pReq->abReqPkt[0]);
4315#else
4316 rc = pfnServiceReqHandler(pSession, pReq->u.In.uOperation, pReq->u.In.u64Arg, (PSUPR0SERVICEREQHDR)&pReq->abReqPkt[0]);
4317#endif
4318 }
4319 else
4320 rc = VERR_SUPDRV_SERVICE_NOT_FOUND;
4321 }
4322
4323 /* log it */
4324 if ( RT_FAILURE(rc)
4325 && rc != VERR_INTERRUPTED
4326 && rc != VERR_TIMEOUT)
4327 Log(("SUP_IOCTL_CALL_SERVICE: rc=%Rrc op=%u out=%u arg=%RX64 p/t=%RTproc/%RTthrd\n",
4328 rc, pReq->u.In.uOperation, pReq->Hdr.cbOut, pReq->u.In.u64Arg, RTProcSelf(), RTThreadNativeSelf()));
4329 else
4330 Log4(("SUP_IOCTL_CALL_SERVICE: rc=%Rrc op=%u out=%u arg=%RX64 p/t=%RTproc/%RTthrd\n",
4331 rc, pReq->u.In.uOperation, pReq->Hdr.cbOut, pReq->u.In.u64Arg, RTProcSelf(), RTThreadNativeSelf()));
4332 return rc;
4333#else /* RT_OS_WINDOWS && !DEBUG */
4334 return VERR_NOT_IMPLEMENTED;
4335#endif /* RT_OS_WINDOWS && !DEBUG */
4336}
4337
4338
4339/**
4340 * Implements the logger settings request.
4341 *
4342 * @returns VBox status code.
4343 * @param pDevExt The device extension.
4344 * @param pSession The caller's session.
4345 * @param pReq The request.
4346 */
4347static int supdrvIOCtl_LoggerSettings(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLOGGERSETTINGS pReq)
4348{
4349 const char *pszGroup = &pReq->u.In.szStrings[pReq->u.In.offGroups];
4350 const char *pszFlags = &pReq->u.In.szStrings[pReq->u.In.offFlags];
4351 const char *pszDest = &pReq->u.In.szStrings[pReq->u.In.offDestination];
4352 PRTLOGGER pLogger = NULL;
4353 int rc;
4354
4355 /*
4356 * Some further validation.
4357 */
4358 switch (pReq->u.In.fWhat)
4359 {
4360 case SUPLOGGERSETTINGS_WHAT_SETTINGS:
4361 case SUPLOGGERSETTINGS_WHAT_CREATE:
4362 break;
4363
4364 case SUPLOGGERSETTINGS_WHAT_DESTROY:
4365 if (*pszGroup || *pszFlags || *pszDest)
4366 return VERR_INVALID_PARAMETER;
4367 if (pReq->u.In.fWhich == SUPLOGGERSETTINGS_WHICH_RELEASE)
4368 return VERR_ACCESS_DENIED;
4369 break;
4370
4371 default:
4372 return VERR_INTERNAL_ERROR;
4373 }
4374
4375 /*
4376 * Get the logger.
4377 */
4378 switch (pReq->u.In.fWhich)
4379 {
4380 case SUPLOGGERSETTINGS_WHICH_DEBUG:
4381 pLogger = RTLogGetDefaultInstance();
4382 break;
4383
4384 case SUPLOGGERSETTINGS_WHICH_RELEASE:
4385 pLogger = RTLogRelDefaultInstance();
4386 break;
4387
4388 default:
4389 return VERR_INTERNAL_ERROR;
4390 }
4391
4392 /*
4393 * Do the job.
4394 */
4395 switch (pReq->u.In.fWhat)
4396 {
4397 case SUPLOGGERSETTINGS_WHAT_SETTINGS:
4398 if (pLogger)
4399 {
4400 rc = RTLogFlags(pLogger, pszFlags);
4401 if (RT_SUCCESS(rc))
4402 rc = RTLogGroupSettings(pLogger, pszGroup);
4403 NOREF(pszDest);
4404 }
4405 else
4406 rc = VERR_NOT_FOUND;
4407 break;
4408
4409 case SUPLOGGERSETTINGS_WHAT_CREATE:
4410 {
4411 if (pLogger)
4412 rc = VERR_ALREADY_EXISTS;
4413 else
4414 {
4415 static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
4416
4417 rc = RTLogCreate(&pLogger,
4418 0 /* fFlags */,
4419 pszGroup,
4420 pReq->u.In.fWhich == SUPLOGGERSETTINGS_WHICH_DEBUG
4421 ? "VBOX_LOG"
4422 : "VBOX_RELEASE_LOG",
4423 RT_ELEMENTS(s_apszGroups),
4424 s_apszGroups,
4425 RTLOGDEST_STDOUT | RTLOGDEST_DEBUGGER,
4426 NULL);
4427 if (RT_SUCCESS(rc))
4428 {
4429 rc = RTLogFlags(pLogger, pszFlags);
4430 NOREF(pszDest);
4431 if (RT_SUCCESS(rc))
4432 {
4433 switch (pReq->u.In.fWhich)
4434 {
4435 case SUPLOGGERSETTINGS_WHICH_DEBUG:
4436 pLogger = RTLogSetDefaultInstance(pLogger);
4437 break;
4438 case SUPLOGGERSETTINGS_WHICH_RELEASE:
4439 pLogger = RTLogRelSetDefaultInstance(pLogger);
4440 break;
4441 }
4442 }
4443 RTLogDestroy(pLogger);
4444 }
4445 }
4446 break;
4447 }
4448
4449 case SUPLOGGERSETTINGS_WHAT_DESTROY:
4450 switch (pReq->u.In.fWhich)
4451 {
4452 case SUPLOGGERSETTINGS_WHICH_DEBUG:
4453 pLogger = RTLogSetDefaultInstance(NULL);
4454 break;
4455 case SUPLOGGERSETTINGS_WHICH_RELEASE:
4456 pLogger = RTLogRelSetDefaultInstance(NULL);
4457 break;
4458 }
4459 rc = RTLogDestroy(pLogger);
4460 break;
4461
4462 default:
4463 {
4464 rc = VERR_INTERNAL_ERROR;
4465 break;
4466 }
4467 }
4468
4469 return rc;
4470}
4471
4472
4473/**
4474 * Creates the GIP.
4475 *
4476 * @returns VBox status code.
4477 * @param pDevExt Instance data. GIP stuff may be updated.
4478 */
4479static int supdrvGipCreate(PSUPDRVDEVEXT pDevExt)
4480{
4481 PSUPGLOBALINFOPAGE pGip;
4482 RTHCPHYS HCPhysGip;
4483 uint32_t u32SystemResolution;
4484 uint32_t u32Interval;
4485 int rc;
4486
4487 LogFlow(("supdrvGipCreate:\n"));
4488
4489 /* assert order */
4490 Assert(pDevExt->u32SystemTimerGranularityGrant == 0);
4491 Assert(pDevExt->GipMemObj == NIL_RTR0MEMOBJ);
4492 Assert(!pDevExt->pGipTimer);
4493
4494 /*
4495 * Allocate a suitable page with a default kernel mapping.
4496 */
4497 rc = RTR0MemObjAllocLow(&pDevExt->GipMemObj, PAGE_SIZE, false);
4498 if (RT_FAILURE(rc))
4499 {
4500 OSDBGPRINT(("supdrvGipCreate: failed to allocate the GIP page. rc=%d\n", rc));
4501 return rc;
4502 }
4503 pGip = (PSUPGLOBALINFOPAGE)RTR0MemObjAddress(pDevExt->GipMemObj); AssertPtr(pGip);
4504 HCPhysGip = RTR0MemObjGetPagePhysAddr(pDevExt->GipMemObj, 0); Assert(HCPhysGip != NIL_RTHCPHYS);
4505
4506#if 0 /** @todo Disabled this as we didn't used to do it before and causes unnecessary stress on laptops.
4507 * It only applies to Windows and should probably revisited later, if possible made part of the
4508 * timer code (return min granularity in RTTimerGetSystemGranularity and set it in RTTimerStart). */
4509 /*
4510 * Try bump up the system timer resolution.
4511 * The more interrupts the better...
4512 */
4513 if ( RT_SUCCESS(RTTimerRequestSystemGranularity( 488281 /* 2048 HZ */, &u32SystemResolution))
4514 || RT_SUCCESS(RTTimerRequestSystemGranularity( 500000 /* 2000 HZ */, &u32SystemResolution))
4515 || RT_SUCCESS(RTTimerRequestSystemGranularity( 976563 /* 1024 HZ */, &u32SystemResolution))
4516 || RT_SUCCESS(RTTimerRequestSystemGranularity( 1000000 /* 1000 HZ */, &u32SystemResolution))
4517 || RT_SUCCESS(RTTimerRequestSystemGranularity( 1953125 /* 512 HZ */, &u32SystemResolution))
4518 || RT_SUCCESS(RTTimerRequestSystemGranularity( 2000000 /* 500 HZ */, &u32SystemResolution))
4519 || RT_SUCCESS(RTTimerRequestSystemGranularity( 3906250 /* 256 HZ */, &u32SystemResolution))
4520 || RT_SUCCESS(RTTimerRequestSystemGranularity( 4000000 /* 250 HZ */, &u32SystemResolution))
4521 || RT_SUCCESS(RTTimerRequestSystemGranularity( 7812500 /* 128 HZ */, &u32SystemResolution))
4522 || RT_SUCCESS(RTTimerRequestSystemGranularity(10000000 /* 100 HZ */, &u32SystemResolution))
4523 || RT_SUCCESS(RTTimerRequestSystemGranularity(15625000 /* 64 HZ */, &u32SystemResolution))
4524 || RT_SUCCESS(RTTimerRequestSystemGranularity(31250000 /* 32 HZ */, &u32SystemResolution))
4525 )
4526 {
4527 Assert(RTTimerGetSystemGranularity() <= u32SystemResolution);
4528 pDevExt->u32SystemTimerGranularityGrant = u32SystemResolution;
4529 }
4530#endif
4531
4532 /*
4533 * Find a reasonable update interval and initialize the structure.
4534 */
4535 u32Interval = u32SystemResolution = RTTimerGetSystemGranularity();
4536 while (u32Interval < 10000000 /* 10 ms */)
4537 u32Interval += u32SystemResolution;
4538
4539 supdrvGipInit(pDevExt, pGip, HCPhysGip, RTTimeSystemNanoTS(), 1000000000 / u32Interval /*=Hz*/);
4540
4541 /*
4542 * Create the timer.
4543 * If CPU_ALL isn't supported we'll have to fall back to synchronous mode.
4544 */
4545 if (pGip->u32Mode == SUPGIPMODE_ASYNC_TSC)
4546 {
4547 rc = RTTimerCreateEx(&pDevExt->pGipTimer, u32Interval, RTTIMER_FLAGS_CPU_ALL, supdrvGipAsyncTimer, pDevExt);
4548 if (rc == VERR_NOT_SUPPORTED)
4549 {
4550 OSDBGPRINT(("supdrvGipCreate: omni timer not supported, falling back to synchronous mode\n"));
4551 pGip->u32Mode = SUPGIPMODE_SYNC_TSC;
4552 }
4553 }
4554 if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
4555 rc = RTTimerCreateEx(&pDevExt->pGipTimer, u32Interval, 0, supdrvGipSyncTimer, pDevExt);
4556 if (RT_SUCCESS(rc))
4557 {
4558 if (pGip->u32Mode == SUPGIPMODE_ASYNC_TSC)
4559 rc = RTMpNotificationRegister(supdrvGipMpEvent, pDevExt);
4560 if (RT_SUCCESS(rc))
4561 {
4562 /*
4563 * We're good.
4564 */
4565 dprintf(("supdrvGipCreate: %ld ns interval.\n", (long)u32Interval));
4566 g_pSUPGlobalInfoPageInternal = pGip;
4567 return VINF_SUCCESS;
4568 }
4569
4570 OSDBGPRINT(("supdrvGipCreate: failed register MP event notfication. rc=%d\n", rc));
4571 }
4572 else
4573 {
4574 OSDBGPRINT(("supdrvGipCreate: failed create GIP timer at %ld ns interval. rc=%d\n", (long)u32Interval, rc));
4575 Assert(!pDevExt->pGipTimer);
4576 }
4577 supdrvGipDestroy(pDevExt);
4578 return rc;
4579}
4580
4581
4582/**
4583 * Terminates the GIP.
4584 *
4585 * @param pDevExt Instance data. GIP stuff may be updated.
4586 */
4587static void supdrvGipDestroy(PSUPDRVDEVEXT pDevExt)
4588{
4589 int rc;
4590#ifdef DEBUG_DARWIN_GIP
4591 OSDBGPRINT(("supdrvGipDestroy: pDevExt=%p pGip=%p pGipTimer=%p GipMemObj=%p\n", pDevExt,
4592 pDevExt->GipMemObj != NIL_RTR0MEMOBJ ? RTR0MemObjAddress(pDevExt->GipMemObj) : NULL,
4593 pDevExt->pGipTimer, pDevExt->GipMemObj));
4594#endif
4595
4596 /*
4597 * Invalid the GIP data.
4598 */
4599 if (pDevExt->pGip)
4600 {
4601 supdrvGipTerm(pDevExt->pGip);
4602 pDevExt->pGip = NULL;
4603 }
4604 g_pSUPGlobalInfoPageInternal = NULL;
4605
4606 /*
4607 * Destroy the timer and free the GIP memory object.
4608 */
4609 if (pDevExt->pGipTimer)
4610 {
4611 rc = RTTimerDestroy(pDevExt->pGipTimer); AssertRC(rc);
4612 pDevExt->pGipTimer = NULL;
4613 }
4614
4615 if (pDevExt->GipMemObj != NIL_RTR0MEMOBJ)
4616 {
4617 rc = RTR0MemObjFree(pDevExt->GipMemObj, true /* free mappings */); AssertRC(rc);
4618 pDevExt->GipMemObj = NIL_RTR0MEMOBJ;
4619 }
4620
4621 /*
4622 * Finally, release the system timer resolution request if one succeeded.
4623 */
4624 if (pDevExt->u32SystemTimerGranularityGrant)
4625 {
4626 rc = RTTimerReleaseSystemGranularity(pDevExt->u32SystemTimerGranularityGrant); AssertRC(rc);
4627 pDevExt->u32SystemTimerGranularityGrant = 0;
4628 }
4629}
4630
4631
4632/**
4633 * Timer callback function sync GIP mode.
4634 * @param pTimer The timer.
4635 * @param pvUser The device extension.
4636 */
4637static DECLCALLBACK(void) supdrvGipSyncTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
4638{
4639 RTCCUINTREG fOldFlags = ASMIntDisableFlags(); /* No interruptions please (real problem on S10). */
4640 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser;
4641 uint64_t u64TSC = ASMReadTSC();
4642 uint64_t NanoTS = RTTimeSystemNanoTS();
4643
4644 supdrvGipUpdate(pDevExt->pGip, NanoTS, u64TSC);
4645
4646 ASMSetFlags(fOldFlags);
4647}
4648
4649
4650/**
4651 * Timer callback function for async GIP mode.
4652 * @param pTimer The timer.
4653 * @param pvUser The device extension.
4654 */
4655static DECLCALLBACK(void) supdrvGipAsyncTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
4656{
4657 RTCCUINTREG fOldFlags = ASMIntDisableFlags(); /* No interruptions please (real problem on S10). */
4658 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser;
4659 RTCPUID idCpu = RTMpCpuId();
4660 uint64_t u64TSC = ASMReadTSC();
4661 uint64_t NanoTS = RTTimeSystemNanoTS();
4662
4663 /** @todo reset the transaction number and whatnot when iTick == 1. */
4664 if (pDevExt->idGipMaster == idCpu)
4665 supdrvGipUpdate(pDevExt->pGip, NanoTS, u64TSC);
4666 else
4667 supdrvGipUpdatePerCpu(pDevExt->pGip, NanoTS, u64TSC, ASMGetApicId());
4668
4669 ASMSetFlags(fOldFlags);
4670}
4671
4672
4673/**
4674 * Multiprocessor event notification callback.
4675 *
4676 * This is used to make sue that the GIP master gets passed on to
4677 * another CPU.
4678 *
4679 * @param enmEvent The event.
4680 * @param idCpu The cpu it applies to.
4681 * @param pvUser Pointer to the device extension.
4682 */
4683static DECLCALLBACK(void) supdrvGipMpEvent(RTMPEVENT enmEvent, RTCPUID idCpu, void *pvUser)
4684{
4685 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser;
4686 if (enmEvent == RTMPEVENT_OFFLINE)
4687 {
4688 RTCPUID idGipMaster;
4689 ASMAtomicReadSize(&pDevExt->idGipMaster, &idGipMaster);
4690 if (idGipMaster == idCpu)
4691 {
4692 /*
4693 * Find a new GIP master.
4694 */
4695 bool fIgnored;
4696 unsigned i;
4697 RTCPUID idNewGipMaster = NIL_RTCPUID;
4698 RTCPUSET OnlineCpus;
4699 RTMpGetOnlineSet(&OnlineCpus);
4700
4701 for (i = 0; i < RTCPUSET_MAX_CPUS; i++)
4702 {
4703 RTCPUID idCurCpu = RTMpCpuIdFromSetIndex(i);
4704 if ( RTCpuSetIsMember(&OnlineCpus, idCurCpu)
4705 && idCurCpu != idGipMaster)
4706 {
4707 idNewGipMaster = idCurCpu;
4708 break;
4709 }
4710 }
4711
4712 dprintf(("supdrvGipMpEvent: Gip master %#lx -> %#lx\n", (long)idGipMaster, (long)idNewGipMaster));
4713 ASMAtomicCmpXchgSize(&pDevExt->idGipMaster, idNewGipMaster, idGipMaster, fIgnored);
4714 NOREF(fIgnored);
4715 }
4716 }
4717}
4718
4719
4720/**
4721 * Initializes the GIP data.
4722 *
4723 * @returns IPRT status code.
4724 * @param pDevExt Pointer to the device instance data.
4725 * @param pGip Pointer to the read-write kernel mapping of the GIP.
4726 * @param HCPhys The physical address of the GIP.
4727 * @param u64NanoTS The current nanosecond timestamp.
4728 * @param uUpdateHz The update freqence.
4729 */
4730int VBOXCALL supdrvGipInit(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, RTHCPHYS HCPhys, uint64_t u64NanoTS, unsigned uUpdateHz)
4731{
4732 unsigned i;
4733#ifdef DEBUG_DARWIN_GIP
4734 OSDBGPRINT(("supdrvGipInit: pGip=%p HCPhys=%lx u64NanoTS=%llu uUpdateHz=%d\n", pGip, (long)HCPhys, u64NanoTS, uUpdateHz));
4735#else
4736 LogFlow(("supdrvGipInit: pGip=%p HCPhys=%lx u64NanoTS=%llu uUpdateHz=%d\n", pGip, (long)HCPhys, u64NanoTS, uUpdateHz));
4737#endif
4738
4739 /*
4740 * Initialize the structure.
4741 */
4742 memset(pGip, 0, PAGE_SIZE);
4743 pGip->u32Magic = SUPGLOBALINFOPAGE_MAGIC;
4744 pGip->u32Version = SUPGLOBALINFOPAGE_VERSION;
4745 pGip->u32Mode = supdrvGipDeterminTscMode(pDevExt);
4746 pGip->u32UpdateHz = uUpdateHz;
4747 pGip->u32UpdateIntervalNS = 1000000000 / uUpdateHz;
4748 pGip->u64NanoTSLastUpdateHz = u64NanoTS;
4749
4750 for (i = 0; i < RT_ELEMENTS(pGip->aCPUs); i++)
4751 {
4752 pGip->aCPUs[i].u32TransactionId = 2;
4753 pGip->aCPUs[i].u64NanoTS = u64NanoTS;
4754 pGip->aCPUs[i].u64TSC = ASMReadTSC();
4755
4756 /*
4757 * We don't know the following values until we've executed updates.
4758 * So, we'll just insert very high values.
4759 */
4760 pGip->aCPUs[i].u64CpuHz = _4G + 1;
4761 pGip->aCPUs[i].u32UpdateIntervalTSC = _2G / 4;
4762 pGip->aCPUs[i].au32TSCHistory[0] = _2G / 4;
4763 pGip->aCPUs[i].au32TSCHistory[1] = _2G / 4;
4764 pGip->aCPUs[i].au32TSCHistory[2] = _2G / 4;
4765 pGip->aCPUs[i].au32TSCHistory[3] = _2G / 4;
4766 pGip->aCPUs[i].au32TSCHistory[4] = _2G / 4;
4767 pGip->aCPUs[i].au32TSCHistory[5] = _2G / 4;
4768 pGip->aCPUs[i].au32TSCHistory[6] = _2G / 4;
4769 pGip->aCPUs[i].au32TSCHistory[7] = _2G / 4;
4770 }
4771
4772 /*
4773 * Link it to the device extension.
4774 */
4775 pDevExt->pGip = pGip;
4776 pDevExt->HCPhysGip = HCPhys;
4777 pDevExt->cGipUsers = 0;
4778
4779 return VINF_SUCCESS;
4780}
4781
4782
4783/**
4784 * Callback used by supdrvDetermineAsyncTSC to read the TSC on a CPU.
4785 *
4786 * @param idCpu Ignored.
4787 * @param pvUser1 Where to put the TSC.
4788 * @param pvUser2 Ignored.
4789 */
4790static DECLCALLBACK(void) supdrvDetermineAsyncTscWorker(RTCPUID idCpu, void *pvUser1, void *pvUser2)
4791{
4792#if 1
4793 ASMAtomicWriteU64((uint64_t volatile *)pvUser1, ASMReadTSC());
4794#else
4795 *(uint64_t *)pvUser1 = ASMReadTSC();
4796#endif
4797}
4798
4799
4800/**
4801 * Determine if Async GIP mode is required because of TSC drift.
4802 *
4803 * When using the default/normal timer code it is essential that the time stamp counter
4804 * (TSC) runs never backwards, that is, a read operation to the counter should return
4805 * a bigger value than any previous read operation. This is guaranteed by the latest
4806 * AMD CPUs and by newer Intel CPUs which never enter the C2 state (P4). In any other
4807 * case we have to choose the asynchronous timer mode.
4808 *
4809 * @param poffMin Pointer to the determined difference between different cores.
4810 * @return false if the time stamp counters appear to be synchron, true otherwise.
4811 */
4812bool VBOXCALL supdrvDetermineAsyncTsc(uint64_t *poffMin)
4813{
4814 /*
4815 * Just iterate all the cpus 8 times and make sure that the TSC is
4816 * ever increasing. We don't bother taking TSC rollover into account.
4817 */
4818 RTCPUSET CpuSet;
4819 int iLastCpu = RTCpuLastIndex(RTMpGetSet(&CpuSet));
4820 int iCpu;
4821 int cLoops = 8;
4822 bool fAsync = false;
4823 int rc = VINF_SUCCESS;
4824 uint64_t offMax = 0;
4825 uint64_t offMin = ~(uint64_t)0;
4826 uint64_t PrevTsc = ASMReadTSC();
4827
4828 while (cLoops-- > 0)
4829 {
4830 for (iCpu = 0; iCpu <= iLastCpu; iCpu++)
4831 {
4832 uint64_t CurTsc;
4833 rc = RTMpOnSpecific(RTMpCpuIdFromSetIndex(iCpu), supdrvDetermineAsyncTscWorker, &CurTsc, NULL);
4834 if (RT_SUCCESS(rc))
4835 {
4836 if (CurTsc <= PrevTsc)
4837 {
4838 fAsync = true;
4839 offMin = offMax = PrevTsc - CurTsc;
4840 dprintf(("supdrvDetermineAsyncTsc: iCpu=%d cLoops=%d CurTsc=%llx PrevTsc=%llx\n",
4841 iCpu, cLoops, CurTsc, PrevTsc));
4842 break;
4843 }
4844
4845 /* Gather statistics (except the first time). */
4846 if (iCpu != 0 || cLoops != 7)
4847 {
4848 uint64_t off = CurTsc - PrevTsc;
4849 if (off < offMin)
4850 offMin = off;
4851 if (off > offMax)
4852 offMax = off;
4853 dprintf2(("%d/%d: off=%llx\n", cLoops, iCpu, off));
4854 }
4855
4856 /* Next */
4857 PrevTsc = CurTsc;
4858 }
4859 else if (rc == VERR_NOT_SUPPORTED)
4860 break;
4861 else
4862 AssertMsg(rc == VERR_CPU_NOT_FOUND || rc == VERR_CPU_OFFLINE, ("%d\n", rc));
4863 }
4864
4865 /* broke out of the loop. */
4866 if (iCpu <= iLastCpu)
4867 break;
4868 }
4869
4870 *poffMin = offMin; /* Almost RTMpOnSpecific profiling. */
4871 dprintf(("supdrvDetermineAsyncTsc: returns %d; iLastCpu=%d rc=%d offMin=%llx offMax=%llx\n",
4872 fAsync, iLastCpu, rc, offMin, offMax));
4873#if !defined(RT_OS_SOLARIS) && !defined(RT_OS_OS2) && !defined(RT_OS_WINDOWS)
4874 OSDBGPRINT(("vboxdrv: fAsync=%d offMin=%#lx offMax=%#lx\n", fAsync, (long)offMin, (long)offMax));
4875#endif
4876 return fAsync;
4877}
4878
4879
4880/**
4881 * Invalidates the GIP data upon termination.
4882 *
4883 * @param pGip Pointer to the read-write kernel mapping of the GIP.
4884 */
4885void VBOXCALL supdrvGipTerm(PSUPGLOBALINFOPAGE pGip)
4886{
4887 unsigned i;
4888 pGip->u32Magic = 0;
4889 for (i = 0; i < RT_ELEMENTS(pGip->aCPUs); i++)
4890 {
4891 pGip->aCPUs[i].u64NanoTS = 0;
4892 pGip->aCPUs[i].u64TSC = 0;
4893 pGip->aCPUs[i].iTSCHistoryHead = 0;
4894 }
4895}
4896
4897
4898/**
4899 * Worker routine for supdrvGipUpdate and supdrvGipUpdatePerCpu that
4900 * updates all the per cpu data except the transaction id.
4901 *
4902 * @param pGip The GIP.
4903 * @param pGipCpu Pointer to the per cpu data.
4904 * @param u64NanoTS The current time stamp.
4905 * @param u64TSC The current TSC.
4906 */
4907static void supdrvGipDoUpdateCpu(PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pGipCpu, uint64_t u64NanoTS, uint64_t u64TSC)
4908{
4909 uint64_t u64TSCDelta;
4910 uint32_t u32UpdateIntervalTSC;
4911 uint32_t u32UpdateIntervalTSCSlack;
4912 unsigned iTSCHistoryHead;
4913 uint64_t u64CpuHz;
4914
4915 /* Delta between this and the previous update. */
4916 pGipCpu->u32UpdateIntervalNS = (uint32_t)(u64NanoTS - pGipCpu->u64NanoTS);
4917
4918 /*
4919 * Update the NanoTS.
4920 */
4921 ASMAtomicXchgU64(&pGipCpu->u64NanoTS, u64NanoTS);
4922
4923 /*
4924 * Calc TSC delta.
4925 */
4926 /** @todo validate the NanoTS delta, don't trust the OS to call us when it should... */
4927 u64TSCDelta = u64TSC - pGipCpu->u64TSC;
4928 ASMAtomicXchgU64(&pGipCpu->u64TSC, u64TSC);
4929
4930 if (u64TSCDelta >> 32)
4931 {
4932 u64TSCDelta = pGipCpu->u32UpdateIntervalTSC;
4933 pGipCpu->cErrors++;
4934 }
4935
4936 /*
4937 * TSC History.
4938 */
4939 Assert(RT_ELEMENTS(pGipCpu->au32TSCHistory) == 8);
4940
4941 iTSCHistoryHead = (pGipCpu->iTSCHistoryHead + 1) & 7;
4942 ASMAtomicXchgU32(&pGipCpu->iTSCHistoryHead, iTSCHistoryHead);
4943 ASMAtomicXchgU32(&pGipCpu->au32TSCHistory[iTSCHistoryHead], (uint32_t)u64TSCDelta);
4944
4945 /*
4946 * UpdateIntervalTSC = average of last 8,2,1 intervals depending on update HZ.
4947 */
4948 if (pGip->u32UpdateHz >= 1000)
4949 {
4950 uint32_t u32;
4951 u32 = pGipCpu->au32TSCHistory[0];
4952 u32 += pGipCpu->au32TSCHistory[1];
4953 u32 += pGipCpu->au32TSCHistory[2];
4954 u32 += pGipCpu->au32TSCHistory[3];
4955 u32 >>= 2;
4956 u32UpdateIntervalTSC = pGipCpu->au32TSCHistory[4];
4957 u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[5];
4958 u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[6];
4959 u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[7];
4960 u32UpdateIntervalTSC >>= 2;
4961 u32UpdateIntervalTSC += u32;
4962 u32UpdateIntervalTSC >>= 1;
4963
4964 /* Value choosen for a 2GHz Athlon64 running linux 2.6.10/11, . */
4965 u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 14;
4966 }
4967 else if (pGip->u32UpdateHz >= 90)
4968 {
4969 u32UpdateIntervalTSC = (uint32_t)u64TSCDelta;
4970 u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[(iTSCHistoryHead - 1) & 7];
4971 u32UpdateIntervalTSC >>= 1;
4972
4973 /* value choosen on a 2GHz thinkpad running windows */
4974 u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 7;
4975 }
4976 else
4977 {
4978 u32UpdateIntervalTSC = (uint32_t)u64TSCDelta;
4979
4980 /* This value hasn't be checked yet.. waiting for OS/2 and 33Hz timers.. :-) */
4981 u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 6;
4982 }
4983 ASMAtomicXchgU32(&pGipCpu->u32UpdateIntervalTSC, u32UpdateIntervalTSC + u32UpdateIntervalTSCSlack);
4984
4985 /*
4986 * CpuHz.
4987 */
4988 u64CpuHz = ASMMult2xU32RetU64(u32UpdateIntervalTSC, pGip->u32UpdateHz);
4989 ASMAtomicXchgU64(&pGipCpu->u64CpuHz, u64CpuHz);
4990}
4991
4992
4993/**
4994 * Updates the GIP.
4995 *
4996 * @param pGip Pointer to the GIP.
4997 * @param u64NanoTS The current nanosecond timesamp.
4998 * @param u64TSC The current TSC timesamp.
4999 */
5000void VBOXCALL supdrvGipUpdate(PSUPGLOBALINFOPAGE pGip, uint64_t u64NanoTS, uint64_t u64TSC)
5001{
5002 /*
5003 * Determin the relevant CPU data.
5004 */
5005 PSUPGIPCPU pGipCpu;
5006 if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
5007 pGipCpu = &pGip->aCPUs[0];
5008 else
5009 {
5010 unsigned iCpu = ASMGetApicId();
5011 if (RT_LIKELY(iCpu >= RT_ELEMENTS(pGip->aCPUs)))
5012 return;
5013 pGipCpu = &pGip->aCPUs[iCpu];
5014 }
5015
5016 /*
5017 * Start update transaction.
5018 */
5019 if (!(ASMAtomicIncU32(&pGipCpu->u32TransactionId) & 1))
5020 {
5021 /* this can happen on win32 if we're taking to long and there are more CPUs around. shouldn't happen though. */
5022 AssertMsgFailed(("Invalid transaction id, %#x, not odd!\n", pGipCpu->u32TransactionId));
5023 ASMAtomicIncU32(&pGipCpu->u32TransactionId);
5024 pGipCpu->cErrors++;
5025 return;
5026 }
5027
5028 /*
5029 * Recalc the update frequency every 0x800th time.
5030 */
5031 if (!(pGipCpu->u32TransactionId & (GIP_UPDATEHZ_RECALC_FREQ * 2 - 2)))
5032 {
5033 if (pGip->u64NanoTSLastUpdateHz)
5034 {
5035#ifdef RT_ARCH_AMD64 /** @todo fix 64-bit div here to work on x86 linux. */
5036 uint64_t u64Delta = u64NanoTS - pGip->u64NanoTSLastUpdateHz;
5037 uint32_t u32UpdateHz = (uint32_t)((UINT64_C(1000000000) * GIP_UPDATEHZ_RECALC_FREQ) / u64Delta);
5038 if (u32UpdateHz <= 2000 && u32UpdateHz >= 30)
5039 {
5040 ASMAtomicXchgU32(&pGip->u32UpdateHz, u32UpdateHz);
5041 ASMAtomicXchgU32(&pGip->u32UpdateIntervalNS, 1000000000 / u32UpdateHz);
5042 }
5043#endif
5044 }
5045 ASMAtomicXchgU64(&pGip->u64NanoTSLastUpdateHz, u64NanoTS);
5046 }
5047
5048 /*
5049 * Update the data.
5050 */
5051 supdrvGipDoUpdateCpu(pGip, pGipCpu, u64NanoTS, u64TSC);
5052
5053 /*
5054 * Complete transaction.
5055 */
5056 ASMAtomicIncU32(&pGipCpu->u32TransactionId);
5057}
5058
5059
5060/**
5061 * Updates the per cpu GIP data for the calling cpu.
5062 *
5063 * @param pGip Pointer to the GIP.
5064 * @param u64NanoTS The current nanosecond timesamp.
5065 * @param u64TSC The current TSC timesamp.
5066 * @param iCpu The CPU index.
5067 */
5068void VBOXCALL supdrvGipUpdatePerCpu(PSUPGLOBALINFOPAGE pGip, uint64_t u64NanoTS, uint64_t u64TSC, unsigned iCpu)
5069{
5070 PSUPGIPCPU pGipCpu;
5071
5072 if (RT_LIKELY(iCpu < RT_ELEMENTS(pGip->aCPUs)))
5073 {
5074 pGipCpu = &pGip->aCPUs[iCpu];
5075
5076 /*
5077 * Start update transaction.
5078 */
5079 if (!(ASMAtomicIncU32(&pGipCpu->u32TransactionId) & 1))
5080 {
5081 AssertMsgFailed(("Invalid transaction id, %#x, not odd!\n", pGipCpu->u32TransactionId));
5082 ASMAtomicIncU32(&pGipCpu->u32TransactionId);
5083 pGipCpu->cErrors++;
5084 return;
5085 }
5086
5087 /*
5088 * Update the data.
5089 */
5090 supdrvGipDoUpdateCpu(pGip, pGipCpu, u64NanoTS, u64TSC);
5091
5092 /*
5093 * Complete transaction.
5094 */
5095 ASMAtomicIncU32(&pGipCpu->u32TransactionId);
5096 }
5097}
5098
Note: See TracBrowser for help on using the repository browser.

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