VirtualBox

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

Last change on this file since 32414 was 32414, checked in by vboxsync, 14 years ago

Export more avl functions

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

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