VirtualBox

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

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

Calculate delta between two timer callbacks.

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