VirtualBox

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

Last change on this file since 81028 was 81006, checked in by vboxsync, 5 years ago

SUPDrv: Build fix.

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

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