VirtualBox

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

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

SUPDrv.c: Corrected wrong arguments.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use