VirtualBox

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

Last change on this file since 20504 was 20315, checked in by vboxsync, 16 years ago

Corrected wrong exports

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

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