VirtualBox

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

最後變更 在這個檔案從12100是 12100,由 vboxsync 提交於 17 年 前

VBoxDrv: Finished the unwind fix for AMD64. (hides our code from RtlVirtualUnwind and associated stuff.)

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

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