VirtualBox

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

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

IPRT: set Linux R0 thread priority, compilation warning

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