VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/SUPDrv.cpp@ 55863

Last change on this file since 55863 was 55863, checked in by vboxsync, 10 years ago

IPRT,SUPDrv,VMM: Revised the context switching hook interface. Do less work when enabling the hook (formerly 'registration'). Drop the reference counting (kept internally for solaris) as it complicates restrictions wrt destroying enabled hooks. Bumped support driver version.

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

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