VirtualBox

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

最後變更 在這個檔案從14655是 14645,由 vboxsync 提交於 16 年 前

SUP, VMM: Moved the max alloc/map page count to VBox/param.h

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

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