VirtualBox

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

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

SUPDrv.c: A couple of small cleanups.

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