VirtualBox

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

Last change on this file since 20106 was 19932, checked in by vboxsync, 16 years ago

SUPDrv: Expose the RTThreadPreempt API to modules.

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