VirtualBox

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

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

warnings

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

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