VirtualBox

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

Last change on this file since 41067 was 41067, checked in by vboxsync, 13 years ago

supdrvOSLdrNotifyOpened so we can record the load address in NVRAM if we choose to.

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