VirtualBox

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

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

SUP: Expose ring-0 event semaphores to ring-3, part 1.

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