VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/SUPLib.cpp@ 88303

Last change on this file since 88303 was 87700, checked in by vboxsync, 4 years ago

SUPDrv,++: Experimental support for wrapping .r0 modules in native kernel modules on linux, so that perf and similar tools work better. Minor IOC version increase as SUP_IOCTL_LDR_OPEN now support just opening a module w/o preparing the loading. SUPDrv must export all the symbols in g_aFunctions the linux way now, or linux won't see them, so introduced a SUPR0_EXPORT_SYMBOL macro similar to RT_EXPORT_SYMBOL. bugref:9937

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 82.6 KB
Line 
1/* $Id: SUPLib.cpp 87700 2021-02-10 20:21:04Z vboxsync $ */
2/** @file
3 * VirtualBox Support Library - Common code.
4 */
5
6/*
7 * Copyright (C) 2006-2020 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/** @page pg_sup SUP - The Support Library
28 *
29 * The support library is responsible for providing facilities to load
30 * VMM Host Ring-0 code, to call Host VMM Ring-0 code from Ring-3 Host
31 * code, to pin down physical memory, and more.
32 *
33 * The VMM Host Ring-0 code can be combined in the support driver if
34 * permitted by kernel module license policies. If it is not combined
35 * it will be externalized in a .r0 module that will be loaded using
36 * the IPRT loader.
37 *
38 * The Ring-0 calling is done thru a generic SUP interface which will
39 * transfer an argument set and call a predefined entry point in the Host
40 * VMM Ring-0 code.
41 *
42 * See @ref grp_sup "SUP - Support APIs" for API details.
43 */
44
45
46/*********************************************************************************************************************************
47* Header Files *
48*********************************************************************************************************************************/
49#define LOG_GROUP LOG_GROUP_SUP
50#include <VBox/sup.h>
51#include <VBox/err.h>
52#include <VBox/param.h>
53#include <VBox/log.h>
54#include <VBox/VBoxTpG.h>
55
56#include <iprt/assert.h>
57#include <iprt/alloc.h>
58#include <iprt/alloca.h>
59#include <iprt/ldr.h>
60#include <iprt/asm.h>
61#include <iprt/mp.h>
62#include <iprt/cpuset.h>
63#include <iprt/thread.h>
64#include <iprt/process.h>
65#include <iprt/path.h>
66#include <iprt/string.h>
67#include <iprt/env.h>
68#include <iprt/rand.h>
69#include <iprt/x86.h>
70
71#include "SUPDrvIOC.h"
72#include "SUPLibInternal.h"
73
74
75/*********************************************************************************************************************************
76* Defined Constants And Macros *
77*********************************************************************************************************************************/
78/** R0 VMM module name. */
79#define VMMR0_NAME "VMMR0"
80
81
82/*********************************************************************************************************************************
83* Structures and Typedefs *
84*********************************************************************************************************************************/
85typedef DECLCALLBACKTYPE(int, FNCALLVMMR0,(PVMR0 pVMR0, unsigned uOperation, void *pvArg));
86typedef FNCALLVMMR0 *PFNCALLVMMR0;
87
88
89/*********************************************************************************************************************************
90* Global Variables *
91*********************************************************************************************************************************/
92/** Init counter. */
93static uint32_t g_cInits = 0;
94/** Whether we've been preinitied. */
95static bool g_fPreInited = false;
96/** The SUPLib instance data.
97 * Well, at least parts of it, specifically the parts that are being handed over
98 * via the pre-init mechanism from the hardened executable stub. */
99DECL_HIDDEN_DATA(SUPLIBDATA) g_supLibData =
100{
101 /*.hDevice = */ SUP_HDEVICE_NIL,
102 /*.fUnrestricted = */ true
103#if defined(RT_OS_DARWIN)
104 ,/* .uConnection = */ 0
105#elif defined(RT_OS_LINUX)
106 ,/* .fSysMadviseWorks = */ false
107#endif
108};
109
110/** Pointer to the Global Information Page.
111 *
112 * This pointer is valid as long as SUPLib has a open session. Anyone using
113 * the page must treat this pointer as highly volatile and not trust it beyond
114 * one transaction.
115 *
116 * @todo This will probably deserve it's own session or some other good solution...
117 */
118DECLEXPORT(PSUPGLOBALINFOPAGE) g_pSUPGlobalInfoPage;
119/** Address of the ring-0 mapping of the GIP. */
120PSUPGLOBALINFOPAGE g_pSUPGlobalInfoPageR0;
121/** The physical address of the GIP. */
122static RTHCPHYS g_HCPhysSUPGlobalInfoPage = NIL_RTHCPHYS;
123
124/** The negotiated cookie. */
125DECL_HIDDEN_DATA(uint32_t) g_u32Cookie = 0;
126/** The negotiated session cookie. */
127DECL_HIDDEN_DATA(uint32_t) g_u32SessionCookie;
128/** The session version. */
129DECL_HIDDEN_DATA(uint32_t) g_uSupSessionVersion = 0;
130/** Session handle. */
131DECL_HIDDEN_DATA(PSUPDRVSESSION) g_pSession;
132/** R0 SUP Functions used for resolving referenced to the SUPR0 module. */
133DECL_HIDDEN_DATA(PSUPQUERYFUNCS) g_pSupFunctions;
134
135/** PAGE_ALLOC_EX sans kernel mapping support indicator. */
136static bool g_fSupportsPageAllocNoKernel = true;
137/** Fake mode indicator. (~0 at first, 0 or 1 after first test) */
138DECL_HIDDEN_DATA(uint32_t) g_uSupFakeMode = UINT32_MAX;
139
140
141/*********************************************************************************************************************************
142* Internal Functions *
143*********************************************************************************************************************************/
144static int supInitFake(PSUPDRVSESSION *ppSession);
145
146
147/** Touch a range of pages. */
148DECLINLINE(void) supR3TouchPages(void *pv, size_t cPages)
149{
150 uint32_t volatile *pu32 = (uint32_t volatile *)pv;
151 while (cPages-- > 0)
152 {
153 ASMAtomicCmpXchgU32(pu32, 0, 0);
154 pu32 += PAGE_SIZE / sizeof(uint32_t);
155 }
156}
157
158
159SUPR3DECL(int) SUPR3Install(void)
160{
161 return suplibOsInstall();
162}
163
164
165SUPR3DECL(int) SUPR3Uninstall(void)
166{
167 return suplibOsUninstall();
168}
169
170
171DECL_NOTHROW(DECLEXPORT(int)) supR3PreInit(PSUPPREINITDATA pPreInitData, uint32_t fFlags)
172{
173 /*
174 * The caller is kind of trustworthy, just perform some basic checks.
175 *
176 * Note! Do not do any fancy stuff here because IPRT has NOT been
177 * initialized at this point.
178 */
179 if (!VALID_PTR(pPreInitData))
180 return VERR_INVALID_POINTER;
181 if (g_fPreInited || g_cInits > 0)
182 return VERR_WRONG_ORDER;
183
184 if ( pPreInitData->u32Magic != SUPPREINITDATA_MAGIC
185 || pPreInitData->u32EndMagic != SUPPREINITDATA_MAGIC)
186 return VERR_INVALID_MAGIC;
187 if ( !(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV)
188 && pPreInitData->Data.hDevice == SUP_HDEVICE_NIL)
189 return VERR_INVALID_HANDLE;
190 if ( (fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV)
191 && pPreInitData->Data.hDevice != SUP_HDEVICE_NIL)
192 return VERR_INVALID_PARAMETER;
193
194 /*
195 * Hand out the data.
196 */
197 int rc = supR3HardenedRecvPreInitData(pPreInitData);
198 if (RT_FAILURE(rc))
199 return rc;
200
201 /** @todo This may need some small restructuring later, it doesn't quite work with a root service flag... */
202 if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV))
203 {
204 g_supLibData = pPreInitData->Data;
205 g_fPreInited = true;
206 }
207
208 return VINF_SUCCESS;
209}
210
211
212SUPR3DECL(int) SUPR3InitEx(bool fUnrestricted, PSUPDRVSESSION *ppSession)
213{
214 /*
215 * Perform some sanity checks.
216 * (Got some trouble with compile time member alignment assertions.)
217 */
218 Assert(!(RT_UOFFSETOF(SUPGLOBALINFOPAGE, u64NanoTSLastUpdateHz) & 0x7));
219 Assert(!(RT_UOFFSETOF(SUPGLOBALINFOPAGE, aCPUs) & 0x1f));
220 Assert(!(RT_UOFFSETOF(SUPGLOBALINFOPAGE, aCPUs[1]) & 0x1f));
221 Assert(!(RT_UOFFSETOF(SUPGLOBALINFOPAGE, aCPUs[0].u64NanoTS) & 0x7));
222 Assert(!(RT_UOFFSETOF(SUPGLOBALINFOPAGE, aCPUs[0].u64TSC) & 0x7));
223 Assert(!(RT_UOFFSETOF(SUPGLOBALINFOPAGE, aCPUs[0].u64CpuHz) & 0x7));
224
225 /*
226 * Check if already initialized.
227 */
228 if (ppSession)
229 *ppSession = g_pSession;
230 if (g_cInits++ > 0)
231 {
232 if (fUnrestricted && !g_supLibData.fUnrestricted)
233 {
234 g_cInits--;
235 if (ppSession)
236 *ppSession = NIL_RTR0PTR;
237 return VERR_VM_DRIVER_NOT_ACCESSIBLE; /** @todo different status code? */
238 }
239 return VINF_SUCCESS;
240 }
241
242 /*
243 * Check for fake mode.
244 *
245 * Fake mode is used when we're doing smoke testing and debugging.
246 * It's also useful on platforms where we haven't root access or which
247 * we haven't ported the support driver to.
248 */
249 if (g_uSupFakeMode == ~0U)
250 {
251 const char *psz = RTEnvGet("VBOX_SUPLIB_FAKE");
252 if (psz && !strcmp(psz, "fake"))
253 ASMAtomicCmpXchgU32(&g_uSupFakeMode, 1, ~0U);
254 else
255 ASMAtomicCmpXchgU32(&g_uSupFakeMode, 0, ~0U);
256 }
257 if (RT_UNLIKELY(g_uSupFakeMode))
258 return supInitFake(ppSession);
259
260 /*
261 * Open the support driver.
262 */
263 SUPINITOP enmWhat = kSupInitOp_Driver;
264 int rc = suplibOsInit(&g_supLibData, g_fPreInited, fUnrestricted, &enmWhat, NULL);
265 if (RT_SUCCESS(rc))
266 {
267 /*
268 * Negotiate the cookie.
269 */
270 SUPCOOKIE CookieReq;
271 memset(&CookieReq, 0xff, sizeof(CookieReq));
272 CookieReq.Hdr.u32Cookie = SUPCOOKIE_INITIAL_COOKIE;
273 CookieReq.Hdr.u32SessionCookie = RTRandU32();
274 CookieReq.Hdr.cbIn = SUP_IOCTL_COOKIE_SIZE_IN;
275 CookieReq.Hdr.cbOut = SUP_IOCTL_COOKIE_SIZE_OUT;
276 CookieReq.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
277 CookieReq.Hdr.rc = VERR_INTERNAL_ERROR;
278 strcpy(CookieReq.u.In.szMagic, SUPCOOKIE_MAGIC);
279 CookieReq.u.In.u32ReqVersion = SUPDRV_IOC_VERSION;
280 const uint32_t uMinVersion = /*(SUPDRV_IOC_VERSION & 0xffff0000) == 0x002d0000
281 ? 0x002d0002
282 :*/ SUPDRV_IOC_VERSION & 0xffff0000;
283 CookieReq.u.In.u32MinVersion = uMinVersion;
284 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_COOKIE, &CookieReq, SUP_IOCTL_COOKIE_SIZE);
285 if ( RT_SUCCESS(rc)
286 && RT_SUCCESS(CookieReq.Hdr.rc))
287 {
288 g_uSupSessionVersion = CookieReq.u.Out.u32SessionVersion;
289 if ( (CookieReq.u.Out.u32SessionVersion & 0xffff0000) == (SUPDRV_IOC_VERSION & 0xffff0000)
290 && CookieReq.u.Out.u32SessionVersion >= uMinVersion)
291 {
292 /*
293 * Query the functions.
294 */
295 PSUPQUERYFUNCS pFuncsReq = NULL;
296 if (g_supLibData.fUnrestricted)
297 {
298 pFuncsReq = (PSUPQUERYFUNCS)RTMemAllocZ(SUP_IOCTL_QUERY_FUNCS_SIZE(CookieReq.u.Out.cFunctions));
299 if (pFuncsReq)
300 {
301 pFuncsReq->Hdr.u32Cookie = CookieReq.u.Out.u32Cookie;
302 pFuncsReq->Hdr.u32SessionCookie = CookieReq.u.Out.u32SessionCookie;
303 pFuncsReq->Hdr.cbIn = SUP_IOCTL_QUERY_FUNCS_SIZE_IN;
304 pFuncsReq->Hdr.cbOut = SUP_IOCTL_QUERY_FUNCS_SIZE_OUT(CookieReq.u.Out.cFunctions);
305 pFuncsReq->Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
306 pFuncsReq->Hdr.rc = VERR_INTERNAL_ERROR;
307 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_QUERY_FUNCS(CookieReq.u.Out.cFunctions), pFuncsReq,
308 SUP_IOCTL_QUERY_FUNCS_SIZE(CookieReq.u.Out.cFunctions));
309 if (RT_SUCCESS(rc))
310 rc = pFuncsReq->Hdr.rc;
311 if (RT_SUCCESS(rc))
312 {
313 /*
314 * Map the GIP into userspace.
315 */
316 Assert(!g_pSUPGlobalInfoPage);
317 SUPGIPMAP GipMapReq;
318 GipMapReq.Hdr.u32Cookie = CookieReq.u.Out.u32Cookie;
319 GipMapReq.Hdr.u32SessionCookie = CookieReq.u.Out.u32SessionCookie;
320 GipMapReq.Hdr.cbIn = SUP_IOCTL_GIP_MAP_SIZE_IN;
321 GipMapReq.Hdr.cbOut = SUP_IOCTL_GIP_MAP_SIZE_OUT;
322 GipMapReq.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
323 GipMapReq.Hdr.rc = VERR_INTERNAL_ERROR;
324 GipMapReq.u.Out.HCPhysGip = NIL_RTHCPHYS;
325 GipMapReq.u.Out.pGipR0 = NIL_RTR0PTR;
326 GipMapReq.u.Out.pGipR3 = NULL;
327 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_GIP_MAP, &GipMapReq, SUP_IOCTL_GIP_MAP_SIZE);
328 if (RT_SUCCESS(rc))
329 rc = GipMapReq.Hdr.rc;
330 if (RT_SUCCESS(rc))
331 {
332 /*
333 * Set the GIP globals.
334 */
335 AssertRelease(GipMapReq.u.Out.pGipR3->u32Magic == SUPGLOBALINFOPAGE_MAGIC);
336 AssertRelease(GipMapReq.u.Out.pGipR3->u32Version >= SUPGLOBALINFOPAGE_VERSION);
337
338 ASMAtomicXchgSize(&g_HCPhysSUPGlobalInfoPage, GipMapReq.u.Out.HCPhysGip);
339 ASMAtomicCmpXchgPtr((void * volatile *)&g_pSUPGlobalInfoPage, GipMapReq.u.Out.pGipR3, NULL);
340 ASMAtomicCmpXchgPtr((void * volatile *)&g_pSUPGlobalInfoPageR0, (void *)GipMapReq.u.Out.pGipR0, NULL);
341 }
342 }
343 }
344 else
345 rc = VERR_NO_MEMORY;
346 }
347
348 if (RT_SUCCESS(rc))
349 {
350 /*
351 * Set the globals and return success.
352 */
353 g_u32Cookie = CookieReq.u.Out.u32Cookie;
354 g_u32SessionCookie = CookieReq.u.Out.u32SessionCookie;
355 g_pSession = CookieReq.u.Out.pSession;
356 g_pSupFunctions = pFuncsReq;
357 if (ppSession)
358 *ppSession = CookieReq.u.Out.pSession;
359 return VINF_SUCCESS;
360 }
361
362 /* bailout */
363 RTMemFree(pFuncsReq);
364 }
365 else
366 {
367 LogRel(("Support driver version mismatch: SessionVersion=%#x DriverVersion=%#x ClientVersion=%#x MinVersion=%#x\n",
368 CookieReq.u.Out.u32SessionVersion, CookieReq.u.Out.u32DriverVersion, SUPDRV_IOC_VERSION, uMinVersion));
369 rc = VERR_VM_DRIVER_VERSION_MISMATCH;
370 }
371 }
372 else
373 {
374 if (RT_SUCCESS(rc))
375 {
376 rc = CookieReq.Hdr.rc;
377 LogRel(("Support driver version mismatch: DriverVersion=%#x ClientVersion=%#x rc=%Rrc\n",
378 CookieReq.u.Out.u32DriverVersion, SUPDRV_IOC_VERSION, rc));
379 if (rc != VERR_VM_DRIVER_VERSION_MISMATCH)
380 rc = VERR_VM_DRIVER_VERSION_MISMATCH;
381 }
382 else
383 {
384 /* for pre 0x00060000 drivers */
385 LogRel(("Support driver version mismatch: DriverVersion=too-old ClientVersion=%#x\n", SUPDRV_IOC_VERSION));
386 rc = VERR_VM_DRIVER_VERSION_MISMATCH;
387 }
388 }
389
390 suplibOsTerm(&g_supLibData);
391 }
392 g_cInits--;
393
394 return rc;
395}
396
397
398SUPR3DECL(int) SUPR3Init(PSUPDRVSESSION *ppSession)
399{
400 return SUPR3InitEx(true, ppSession);
401}
402
403/**
404 * Fake mode init.
405 */
406static int supInitFake(PSUPDRVSESSION *ppSession)
407{
408 Log(("SUP: Fake mode!\n"));
409 static const SUPFUNC s_aFakeFunctions[] =
410 {
411 /* name function */
412 { "SUPR0AbsIs64bit", 0 },
413 { "SUPR0Abs64bitKernelCS", 0 },
414 { "SUPR0Abs64bitKernelSS", 0 },
415 { "SUPR0Abs64bitKernelDS", 0 },
416 { "SUPR0AbsKernelCS", 8 },
417 { "SUPR0AbsKernelSS", 16 },
418 { "SUPR0AbsKernelDS", 16 },
419 { "SUPR0AbsKernelES", 16 },
420 { "SUPR0AbsKernelFS", 24 },
421 { "SUPR0AbsKernelGS", 32 },
422 { "SUPR0ComponentRegisterFactory", 0xefeefffd },
423 { "SUPR0ComponentDeregisterFactory", 0xefeefffe },
424 { "SUPR0ComponentQueryFactory", 0xefeeffff },
425 { "SUPR0ObjRegister", 0xefef0000 },
426 { "SUPR0ObjAddRef", 0xefef0001 },
427 { "SUPR0ObjAddRefEx", 0xefef0001 },
428 { "SUPR0ObjRelease", 0xefef0002 },
429 { "SUPR0ObjVerifyAccess", 0xefef0003 },
430 { "SUPR0LockMem", 0xefef0004 },
431 { "SUPR0UnlockMem", 0xefef0005 },
432 { "SUPR0ContAlloc", 0xefef0006 },
433 { "SUPR0ContFree", 0xefef0007 },
434 { "SUPR0MemAlloc", 0xefef0008 },
435 { "SUPR0MemGetPhys", 0xefef0009 },
436 { "SUPR0MemFree", 0xefef000a },
437 { "SUPR0Printf", 0xefef000b },
438 { "SUPR0GetPagingMode", 0xefef000c },
439 { "SUPR0EnableVTx", 0xefef000e },
440 { "RTMemAlloc", 0xefef000f },
441 { "RTMemAllocZ", 0xefef0010 },
442 { "RTMemFree", 0xefef0011 },
443 { "RTR0MemObjAddress", 0xefef0012 },
444 { "RTR0MemObjAddressR3", 0xefef0013 },
445 { "RTR0MemObjAllocPage", 0xefef0014 },
446 { "RTR0MemObjAllocPhysNC", 0xefef0015 },
447 { "RTR0MemObjAllocLow", 0xefef0016 },
448 { "RTR0MemObjEnterPhys", 0xefef0017 },
449 { "RTR0MemObjFree", 0xefef0018 },
450 { "RTR0MemObjGetPagePhysAddr", 0xefef0019 },
451 { "RTR0MemObjMapUser", 0xefef001a },
452 { "RTR0MemObjMapKernel", 0xefef001b },
453 { "RTR0MemObjMapKernelEx", 0xefef001c },
454 { "RTMpGetArraySize", 0xefef001c },
455 { "RTProcSelf", 0xefef001d },
456 { "RTR0ProcHandleSelf", 0xefef001e },
457 { "RTSemEventCreate", 0xefef001f },
458 { "RTSemEventSignal", 0xefef0020 },
459 { "RTSemEventWait", 0xefef0021 },
460 { "RTSemEventWaitNoResume", 0xefef0022 },
461 { "RTSemEventDestroy", 0xefef0023 },
462 { "RTSemEventMultiCreate", 0xefef0024 },
463 { "RTSemEventMultiSignal", 0xefef0025 },
464 { "RTSemEventMultiReset", 0xefef0026 },
465 { "RTSemEventMultiWait", 0xefef0027 },
466 { "RTSemEventMultiWaitNoResume", 0xefef0028 },
467 { "RTSemEventMultiDestroy", 0xefef0029 },
468 { "RTSemFastMutexCreate", 0xefef002a },
469 { "RTSemFastMutexDestroy", 0xefef002b },
470 { "RTSemFastMutexRequest", 0xefef002c },
471 { "RTSemFastMutexRelease", 0xefef002d },
472 { "RTSpinlockCreate", 0xefef002e },
473 { "RTSpinlockDestroy", 0xefef002f },
474 { "RTSpinlockAcquire", 0xefef0030 },
475 { "RTSpinlockRelease", 0xefef0031 },
476 { "RTSpinlockAcquireNoInts", 0xefef0032 },
477 { "RTTimeNanoTS", 0xefef0034 },
478 { "RTTimeMillieTS", 0xefef0035 },
479 { "RTTimeSystemNanoTS", 0xefef0036 },
480 { "RTTimeSystemMillieTS", 0xefef0037 },
481 { "RTThreadNativeSelf", 0xefef0038 },
482 { "RTThreadSleep", 0xefef0039 },
483 { "RTThreadYield", 0xefef003a },
484 { "RTTimerCreate", 0xefef003a },
485 { "RTTimerCreateEx", 0xefef003a },
486 { "RTTimerDestroy", 0xefef003a },
487 { "RTTimerStart", 0xefef003a },
488 { "RTTimerStop", 0xefef003a },
489 { "RTTimerChangeInterval", 0xefef003a },
490 { "RTTimerGetSystemGranularity", 0xefef003a },
491 { "RTTimerRequestSystemGranularity", 0xefef003a },
492 { "RTTimerReleaseSystemGranularity", 0xefef003a },
493 { "RTTimerCanDoHighResolution", 0xefef003a },
494 { "RTLogDefaultInstance", 0xefef003b },
495 { "RTLogRelGetDefaultInstance", 0xefef003c },
496 { "RTLogSetDefaultInstanceThread", 0xefef003d },
497 { "RTLogLogger", 0xefef003e },
498 { "RTLogLoggerEx", 0xefef003f },
499 { "RTLogLoggerExV", 0xefef0040 },
500 { "RTAssertMsg1", 0xefef0041 },
501 { "RTAssertMsg2", 0xefef0042 },
502 { "RTAssertMsg2V", 0xefef0043 },
503 { "SUPR0QueryVTCaps", 0xefef0044 },
504 };
505
506 /* fake r0 functions. */
507 g_pSupFunctions = (PSUPQUERYFUNCS)RTMemAllocZ(SUP_IOCTL_QUERY_FUNCS_SIZE(RT_ELEMENTS(s_aFakeFunctions)));
508 if (g_pSupFunctions)
509 {
510 g_pSupFunctions->u.Out.cFunctions = RT_ELEMENTS(s_aFakeFunctions);
511 memcpy(&g_pSupFunctions->u.Out.aFunctions[0], &s_aFakeFunctions[0], sizeof(s_aFakeFunctions));
512 g_pSession = (PSUPDRVSESSION)(void *)g_pSupFunctions;
513 if (ppSession)
514 *ppSession = g_pSession;
515
516 /* fake the GIP. */
517 g_pSUPGlobalInfoPage = (PSUPGLOBALINFOPAGE)RTMemPageAllocZ(PAGE_SIZE);
518 if (g_pSUPGlobalInfoPage)
519 {
520 g_pSUPGlobalInfoPageR0 = g_pSUPGlobalInfoPage;
521 g_HCPhysSUPGlobalInfoPage = NIL_RTHCPHYS & ~(RTHCPHYS)PAGE_OFFSET_MASK;
522 /* the page is supposed to be invalid, so don't set the magic. */
523 return VINF_SUCCESS;
524 }
525
526 RTMemFree(g_pSupFunctions);
527 g_pSupFunctions = NULL;
528 }
529 return VERR_NO_MEMORY;
530}
531
532
533SUPR3DECL(int) SUPR3Term(bool fForced)
534{
535 /*
536 * Verify state.
537 */
538 AssertMsg(g_cInits > 0, ("SUPR3Term() is called before SUPR3Init()!\n"));
539 if (g_cInits == 0)
540 return VERR_WRONG_ORDER;
541 if (g_cInits == 1 || fForced)
542 {
543 /*
544 * NULL the GIP pointer.
545 */
546 if (g_pSUPGlobalInfoPage)
547 {
548 ASMAtomicWriteNullPtr((void * volatile *)&g_pSUPGlobalInfoPage);
549 ASMAtomicWriteNullPtr((void * volatile *)&g_pSUPGlobalInfoPageR0);
550 ASMAtomicWriteU64(&g_HCPhysSUPGlobalInfoPage, NIL_RTHCPHYS);
551 /* just a little safe guard against threads using the page. */
552 RTThreadSleep(50);
553 }
554
555 /*
556 * Close the support driver.
557 */
558 int rc = suplibOsTerm(&g_supLibData);
559 if (rc)
560 return rc;
561
562 g_u32Cookie = 0;
563 g_u32SessionCookie = 0;
564 g_cInits = 0;
565 }
566 else
567 g_cInits--;
568
569 return 0;
570}
571
572
573SUPR3DECL(SUPPAGINGMODE) SUPR3GetPagingMode(void)
574{
575 /* fake */
576 if (RT_UNLIKELY(g_uSupFakeMode))
577#ifdef RT_ARCH_AMD64
578 return SUPPAGINGMODE_AMD64_GLOBAL_NX;
579#else
580 return SUPPAGINGMODE_32_BIT_GLOBAL;
581#endif
582
583 /*
584 * Issue IOCtl to the SUPDRV kernel module.
585 */
586 SUPGETPAGINGMODE Req;
587 Req.Hdr.u32Cookie = g_u32Cookie;
588 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
589 Req.Hdr.cbIn = SUP_IOCTL_GET_PAGING_MODE_SIZE_IN;
590 Req.Hdr.cbOut = SUP_IOCTL_GET_PAGING_MODE_SIZE_OUT;
591 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
592 Req.Hdr.rc = VERR_INTERNAL_ERROR;
593 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_GET_PAGING_MODE, &Req, SUP_IOCTL_GET_PAGING_MODE_SIZE);
594 if ( RT_FAILURE(rc)
595 || RT_FAILURE(Req.Hdr.rc))
596 {
597 LogRel(("SUPR3GetPagingMode: %Rrc %Rrc\n", rc, Req.Hdr.rc));
598 Req.u.Out.enmMode = SUPPAGINGMODE_INVALID;
599 }
600
601 return Req.u.Out.enmMode;
602}
603
604
605/**
606 * For later.
607 */
608static int supCallVMMR0ExFake(PVMR0 pVMR0, unsigned uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
609{
610 AssertMsgFailed(("%d\n", uOperation)); NOREF(pVMR0); NOREF(uOperation); NOREF(u64Arg); NOREF(pReqHdr);
611 return VERR_NOT_SUPPORTED;
612}
613
614
615SUPR3DECL(int) SUPR3CallVMMR0Fast(PVMR0 pVMR0, unsigned uOperation, VMCPUID idCpu)
616{
617 NOREF(pVMR0);
618 static const uintptr_t s_auFunctions[3] =
619 {
620 SUP_IOCTL_FAST_DO_HM_RUN,
621 SUP_IOCTL_FAST_DO_NEM_RUN,
622 SUP_IOCTL_FAST_DO_NOP,
623 };
624 AssertCompile(SUP_VMMR0_DO_HM_RUN == 0);
625 AssertCompile(SUP_VMMR0_DO_NEM_RUN == 1);
626 AssertCompile(SUP_VMMR0_DO_NOP == 2);
627 AssertMsgReturn(uOperation < RT_ELEMENTS(s_auFunctions), ("%#x\n", uOperation), VERR_INTERNAL_ERROR);
628 return suplibOsIOCtlFast(&g_supLibData, s_auFunctions[uOperation], idCpu);
629}
630
631
632SUPR3DECL(int) SUPR3CallVMMR0Ex(PVMR0 pVMR0, VMCPUID idCpu, unsigned uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
633{
634 /*
635 * The following operations don't belong here.
636 */
637 AssertMsgReturn( uOperation != SUP_VMMR0_DO_HM_RUN
638 && uOperation != SUP_VMMR0_DO_NEM_RUN
639 && uOperation != SUP_VMMR0_DO_NOP,
640 ("%#x\n", uOperation),
641 VERR_INTERNAL_ERROR);
642
643 /* fake */
644 if (RT_UNLIKELY(g_uSupFakeMode))
645 return supCallVMMR0ExFake(pVMR0, uOperation, u64Arg, pReqHdr);
646
647 int rc;
648 if (!pReqHdr)
649 {
650 /* no data. */
651 SUPCALLVMMR0 Req;
652 Req.Hdr.u32Cookie = g_u32Cookie;
653 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
654 Req.Hdr.cbIn = SUP_IOCTL_CALL_VMMR0_SIZE_IN(0);
655 Req.Hdr.cbOut = SUP_IOCTL_CALL_VMMR0_SIZE_OUT(0);
656 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
657 Req.Hdr.rc = VERR_INTERNAL_ERROR;
658 Req.u.In.pVMR0 = pVMR0;
659 Req.u.In.idCpu = idCpu;
660 Req.u.In.uOperation = uOperation;
661 Req.u.In.u64Arg = u64Arg;
662 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_VMMR0(0), &Req, SUP_IOCTL_CALL_VMMR0_SIZE(0));
663 if (RT_SUCCESS(rc))
664 rc = Req.Hdr.rc;
665 }
666 else if (SUP_IOCTL_CALL_VMMR0_SIZE(pReqHdr->cbReq) < _4K) /* FreeBSD won't copy more than 4K. */
667 {
668 AssertPtrReturn(pReqHdr, VERR_INVALID_POINTER);
669 AssertReturn(pReqHdr->u32Magic == SUPVMMR0REQHDR_MAGIC, VERR_INVALID_MAGIC);
670 const size_t cbReq = pReqHdr->cbReq;
671
672 PSUPCALLVMMR0 pReq = (PSUPCALLVMMR0)alloca(SUP_IOCTL_CALL_VMMR0_SIZE(cbReq));
673 pReq->Hdr.u32Cookie = g_u32Cookie;
674 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
675 pReq->Hdr.cbIn = SUP_IOCTL_CALL_VMMR0_SIZE_IN(cbReq);
676 pReq->Hdr.cbOut = SUP_IOCTL_CALL_VMMR0_SIZE_OUT(cbReq);
677 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
678 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
679 pReq->u.In.pVMR0 = pVMR0;
680 pReq->u.In.idCpu = idCpu;
681 pReq->u.In.uOperation = uOperation;
682 pReq->u.In.u64Arg = u64Arg;
683 memcpy(&pReq->abReqPkt[0], pReqHdr, cbReq);
684 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_VMMR0(cbReq), pReq, SUP_IOCTL_CALL_VMMR0_SIZE(cbReq));
685 if (RT_SUCCESS(rc))
686 rc = pReq->Hdr.rc;
687 memcpy(pReqHdr, &pReq->abReqPkt[0], cbReq);
688 }
689 else if (pReqHdr->cbReq <= _512K)
690 {
691 AssertPtrReturn(pReqHdr, VERR_INVALID_POINTER);
692 AssertReturn(pReqHdr->u32Magic == SUPVMMR0REQHDR_MAGIC, VERR_INVALID_MAGIC);
693 const size_t cbReq = pReqHdr->cbReq;
694
695 PSUPCALLVMMR0 pReq = (PSUPCALLVMMR0)RTMemTmpAlloc(SUP_IOCTL_CALL_VMMR0_BIG_SIZE(cbReq));
696 pReq->Hdr.u32Cookie = g_u32Cookie;
697 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
698 pReq->Hdr.cbIn = SUP_IOCTL_CALL_VMMR0_BIG_SIZE_IN(cbReq);
699 pReq->Hdr.cbOut = SUP_IOCTL_CALL_VMMR0_BIG_SIZE_OUT(cbReq);
700 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
701 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
702 pReq->u.In.pVMR0 = pVMR0;
703 pReq->u.In.idCpu = idCpu;
704 pReq->u.In.uOperation = uOperation;
705 pReq->u.In.u64Arg = u64Arg;
706 memcpy(&pReq->abReqPkt[0], pReqHdr, cbReq);
707 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_VMMR0_BIG, pReq, SUP_IOCTL_CALL_VMMR0_BIG_SIZE(cbReq));
708 if (RT_SUCCESS(rc))
709 rc = pReq->Hdr.rc;
710 memcpy(pReqHdr, &pReq->abReqPkt[0], cbReq);
711 RTMemTmpFree(pReq);
712 }
713 else
714 AssertMsgFailedReturn(("cbReq=%#x\n", pReqHdr->cbReq), VERR_OUT_OF_RANGE);
715 return rc;
716}
717
718
719SUPR3DECL(int) SUPR3CallVMMR0(PVMR0 pVMR0, VMCPUID idCpu, unsigned uOperation, void *pvArg)
720{
721 /*
722 * The following operations don't belong here.
723 */
724 AssertMsgReturn( uOperation != SUP_VMMR0_DO_HM_RUN
725 && uOperation != SUP_VMMR0_DO_NEM_RUN
726 && uOperation != SUP_VMMR0_DO_NOP,
727 ("%#x\n", uOperation),
728 VERR_INTERNAL_ERROR);
729 return SUPR3CallVMMR0Ex(pVMR0, idCpu, uOperation, (uintptr_t)pvArg, NULL);
730}
731
732
733SUPR3DECL(int) SUPR3SetVMForFastIOCtl(PVMR0 pVMR0)
734{
735 if (RT_UNLIKELY(g_uSupFakeMode))
736 return VINF_SUCCESS;
737
738 SUPSETVMFORFAST Req;
739 Req.Hdr.u32Cookie = g_u32Cookie;
740 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
741 Req.Hdr.cbIn = SUP_IOCTL_SET_VM_FOR_FAST_SIZE_IN;
742 Req.Hdr.cbOut = SUP_IOCTL_SET_VM_FOR_FAST_SIZE_OUT;
743 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
744 Req.Hdr.rc = VERR_INTERNAL_ERROR;
745 Req.u.In.pVMR0 = pVMR0;
746 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_SET_VM_FOR_FAST, &Req, SUP_IOCTL_SET_VM_FOR_FAST_SIZE);
747 if (RT_SUCCESS(rc))
748 rc = Req.Hdr.rc;
749 return rc;
750}
751
752
753SUPR3DECL(int) SUPR3CallR0Service(const char *pszService, size_t cchService, uint32_t uOperation, uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr)
754{
755 AssertReturn(cchService < RT_SIZEOFMEMB(SUPCALLSERVICE, u.In.szName), VERR_INVALID_PARAMETER);
756 Assert(strlen(pszService) == cchService);
757
758 /* fake */
759 if (RT_UNLIKELY(g_uSupFakeMode))
760 return VERR_NOT_SUPPORTED;
761
762 int rc;
763 if (!pReqHdr)
764 {
765 /* no data. */
766 SUPCALLSERVICE Req;
767 Req.Hdr.u32Cookie = g_u32Cookie;
768 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
769 Req.Hdr.cbIn = SUP_IOCTL_CALL_SERVICE_SIZE_IN(0);
770 Req.Hdr.cbOut = SUP_IOCTL_CALL_SERVICE_SIZE_OUT(0);
771 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
772 Req.Hdr.rc = VERR_INTERNAL_ERROR;
773 memcpy(Req.u.In.szName, pszService, cchService);
774 Req.u.In.szName[cchService] = '\0';
775 Req.u.In.uOperation = uOperation;
776 Req.u.In.u64Arg = u64Arg;
777 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_SERVICE(0), &Req, SUP_IOCTL_CALL_SERVICE_SIZE(0));
778 if (RT_SUCCESS(rc))
779 rc = Req.Hdr.rc;
780 }
781 else if (SUP_IOCTL_CALL_SERVICE_SIZE(pReqHdr->cbReq) < _4K) /* FreeBSD won't copy more than 4K. */
782 {
783 AssertPtrReturn(pReqHdr, VERR_INVALID_POINTER);
784 AssertReturn(pReqHdr->u32Magic == SUPR0SERVICEREQHDR_MAGIC, VERR_INVALID_MAGIC);
785 const size_t cbReq = pReqHdr->cbReq;
786
787 PSUPCALLSERVICE pReq = (PSUPCALLSERVICE)alloca(SUP_IOCTL_CALL_SERVICE_SIZE(cbReq));
788 pReq->Hdr.u32Cookie = g_u32Cookie;
789 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
790 pReq->Hdr.cbIn = SUP_IOCTL_CALL_SERVICE_SIZE_IN(cbReq);
791 pReq->Hdr.cbOut = SUP_IOCTL_CALL_SERVICE_SIZE_OUT(cbReq);
792 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
793 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
794 memcpy(pReq->u.In.szName, pszService, cchService);
795 pReq->u.In.szName[cchService] = '\0';
796 pReq->u.In.uOperation = uOperation;
797 pReq->u.In.u64Arg = u64Arg;
798 memcpy(&pReq->abReqPkt[0], pReqHdr, cbReq);
799 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_SERVICE(cbReq), pReq, SUP_IOCTL_CALL_SERVICE_SIZE(cbReq));
800 if (RT_SUCCESS(rc))
801 rc = pReq->Hdr.rc;
802 memcpy(pReqHdr, &pReq->abReqPkt[0], cbReq);
803 }
804 else /** @todo may have to remove the size limits one this request... */
805 AssertMsgFailedReturn(("cbReq=%#x\n", pReqHdr->cbReq), VERR_INTERNAL_ERROR);
806 return rc;
807}
808
809
810/**
811 * Worker for the SUPR3Logger* APIs.
812 *
813 * @returns VBox status code.
814 * @param enmWhich Which logger.
815 * @param fWhat What to do with the logger.
816 * @param pszFlags The flags settings.
817 * @param pszGroups The groups settings.
818 * @param pszDest The destination specificier.
819 */
820static int supR3LoggerSettings(SUPLOGGER enmWhich, uint32_t fWhat, const char *pszFlags, const char *pszGroups, const char *pszDest)
821{
822 uint32_t const cchFlags = pszFlags ? (uint32_t)strlen(pszFlags) : 0;
823 uint32_t const cchGroups = pszGroups ? (uint32_t)strlen(pszGroups) : 0;
824 uint32_t const cchDest = pszDest ? (uint32_t)strlen(pszDest) : 0;
825 uint32_t const cbStrTab = cchFlags + !!cchFlags
826 + cchGroups + !!cchGroups
827 + cchDest + !!cchDest
828 + (!cchFlags && !cchGroups && !cchDest);
829
830 PSUPLOGGERSETTINGS pReq = (PSUPLOGGERSETTINGS)alloca(SUP_IOCTL_LOGGER_SETTINGS_SIZE(cbStrTab));
831 pReq->Hdr.u32Cookie = g_u32Cookie;
832 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
833 pReq->Hdr.cbIn = SUP_IOCTL_LOGGER_SETTINGS_SIZE_IN(cbStrTab);
834 pReq->Hdr.cbOut = SUP_IOCTL_LOGGER_SETTINGS_SIZE_OUT;
835 pReq->Hdr.fFlags= SUPREQHDR_FLAGS_DEFAULT;
836 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
837 switch (enmWhich)
838 {
839 case SUPLOGGER_DEBUG: pReq->u.In.fWhich = SUPLOGGERSETTINGS_WHICH_DEBUG; break;
840 case SUPLOGGER_RELEASE: pReq->u.In.fWhich = SUPLOGGERSETTINGS_WHICH_RELEASE; break;
841 default:
842 return VERR_INVALID_PARAMETER;
843 }
844 pReq->u.In.fWhat = fWhat;
845
846 uint32_t off = 0;
847 if (cchFlags)
848 {
849 pReq->u.In.offFlags = off;
850 memcpy(&pReq->u.In.szStrings[off], pszFlags, cchFlags + 1);
851 off += cchFlags + 1;
852 }
853 else
854 pReq->u.In.offFlags = cbStrTab - 1;
855
856 if (cchGroups)
857 {
858 pReq->u.In.offGroups = off;
859 memcpy(&pReq->u.In.szStrings[off], pszGroups, cchGroups + 1);
860 off += cchGroups + 1;
861 }
862 else
863 pReq->u.In.offGroups = cbStrTab - 1;
864
865 if (cchDest)
866 {
867 pReq->u.In.offDestination = off;
868 memcpy(&pReq->u.In.szStrings[off], pszDest, cchDest + 1);
869 off += cchDest + 1;
870 }
871 else
872 pReq->u.In.offDestination = cbStrTab - 1;
873
874 if (!off)
875 {
876 pReq->u.In.szStrings[0] = '\0';
877 off++;
878 }
879 Assert(off == cbStrTab);
880 Assert(pReq->u.In.szStrings[cbStrTab - 1] == '\0');
881
882
883 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LOGGER_SETTINGS(cbStrTab), pReq, SUP_IOCTL_LOGGER_SETTINGS_SIZE(cbStrTab));
884 if (RT_SUCCESS(rc))
885 rc = pReq->Hdr.rc;
886 return rc;
887}
888
889
890SUPR3DECL(int) SUPR3LoggerSettings(SUPLOGGER enmWhich, const char *pszFlags, const char *pszGroups, const char *pszDest)
891{
892 return supR3LoggerSettings(enmWhich, SUPLOGGERSETTINGS_WHAT_SETTINGS, pszFlags, pszGroups, pszDest);
893}
894
895
896SUPR3DECL(int) SUPR3LoggerCreate(SUPLOGGER enmWhich, const char *pszFlags, const char *pszGroups, const char *pszDest)
897{
898 return supR3LoggerSettings(enmWhich, SUPLOGGERSETTINGS_WHAT_CREATE, pszFlags, pszGroups, pszDest);
899}
900
901
902SUPR3DECL(int) SUPR3LoggerDestroy(SUPLOGGER enmWhich)
903{
904 return supR3LoggerSettings(enmWhich, SUPLOGGERSETTINGS_WHAT_DESTROY, NULL, NULL, NULL);
905}
906
907
908SUPR3DECL(int) SUPR3PageAlloc(size_t cPages, void **ppvPages)
909{
910 /*
911 * Validate.
912 */
913 AssertPtrReturn(ppvPages, VERR_INVALID_POINTER);
914 *ppvPages = NULL;
915 AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
916
917 /*
918 * Call OS specific worker.
919 */
920 return suplibOsPageAlloc(&g_supLibData, cPages, ppvPages);
921}
922
923
924SUPR3DECL(int) SUPR3PageFree(void *pvPages, size_t cPages)
925{
926 /*
927 * Validate.
928 */
929 AssertPtrReturn(pvPages, VERR_INVALID_POINTER);
930 AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
931
932 /*
933 * Call OS specific worker.
934 */
935 return suplibOsPageFree(&g_supLibData, pvPages, cPages);
936}
937
938
939/**
940 * Locks down the physical memory backing a virtual memory
941 * range in the current process.
942 *
943 * @returns VBox status code.
944 * @param pvStart Start of virtual memory range.
945 * Must be page aligned.
946 * @param cPages Number of pages.
947 * @param paPages Where to store the physical page addresses returned.
948 * On entry this will point to an array of with cbMemory >> PAGE_SHIFT entries.
949 */
950SUPR3DECL(int) supR3PageLock(void *pvStart, size_t cPages, PSUPPAGE paPages)
951{
952 /*
953 * Validate.
954 */
955 AssertPtr(pvStart);
956 AssertMsg(RT_ALIGN_P(pvStart, PAGE_SIZE) == pvStart, ("pvStart (%p) must be page aligned\n", pvStart));
957 AssertPtr(paPages);
958
959 /* fake */
960 if (RT_UNLIKELY(g_uSupFakeMode))
961 {
962 RTHCPHYS Phys = (uintptr_t)pvStart + PAGE_SIZE * 1024;
963 size_t iPage = cPages;
964 while (iPage-- > 0)
965 paPages[iPage].Phys = Phys + (iPage << PAGE_SHIFT);
966 return VINF_SUCCESS;
967 }
968
969 /*
970 * Issue IOCtl to the SUPDRV kernel module.
971 */
972 int rc;
973 PSUPPAGELOCK pReq = (PSUPPAGELOCK)RTMemTmpAllocZ(SUP_IOCTL_PAGE_LOCK_SIZE(cPages));
974 if (RT_LIKELY(pReq))
975 {
976 pReq->Hdr.u32Cookie = g_u32Cookie;
977 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
978 pReq->Hdr.cbIn = SUP_IOCTL_PAGE_LOCK_SIZE_IN;
979 pReq->Hdr.cbOut = SUP_IOCTL_PAGE_LOCK_SIZE_OUT(cPages);
980 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_OUT;
981 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
982 pReq->u.In.pvR3 = pvStart;
983 pReq->u.In.cPages = (uint32_t)cPages; AssertRelease(pReq->u.In.cPages == cPages);
984 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_LOCK, pReq, SUP_IOCTL_PAGE_LOCK_SIZE(cPages));
985 if (RT_SUCCESS(rc))
986 rc = pReq->Hdr.rc;
987 if (RT_SUCCESS(rc))
988 {
989 for (uint32_t iPage = 0; iPage < cPages; iPage++)
990 {
991 paPages[iPage].uReserved = 0;
992 paPages[iPage].Phys = pReq->u.Out.aPages[iPage];
993 Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
994 }
995 }
996 RTMemTmpFree(pReq);
997 }
998 else
999 rc = VERR_NO_TMP_MEMORY;
1000
1001 return rc;
1002}
1003
1004
1005/**
1006 * Releases locked down pages.
1007 *
1008 * @returns VBox status code.
1009 * @param pvStart Start of virtual memory range previously locked
1010 * down by SUPPageLock().
1011 */
1012SUPR3DECL(int) supR3PageUnlock(void *pvStart)
1013{
1014 /*
1015 * Validate.
1016 */
1017 AssertPtr(pvStart);
1018 AssertMsg(RT_ALIGN_P(pvStart, PAGE_SIZE) == pvStart, ("pvStart (%p) must be page aligned\n", pvStart));
1019
1020 /* fake */
1021 if (RT_UNLIKELY(g_uSupFakeMode))
1022 return VINF_SUCCESS;
1023
1024 /*
1025 * Issue IOCtl to the SUPDRV kernel module.
1026 */
1027 SUPPAGEUNLOCK Req;
1028 Req.Hdr.u32Cookie = g_u32Cookie;
1029 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1030 Req.Hdr.cbIn = SUP_IOCTL_PAGE_UNLOCK_SIZE_IN;
1031 Req.Hdr.cbOut = SUP_IOCTL_PAGE_UNLOCK_SIZE_OUT;
1032 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1033 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1034 Req.u.In.pvR3 = pvStart;
1035 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_UNLOCK, &Req, SUP_IOCTL_PAGE_UNLOCK_SIZE);
1036 if (RT_SUCCESS(rc))
1037 rc = Req.Hdr.rc;
1038 return rc;
1039}
1040
1041
1042SUPR3DECL(int) SUPR3LockDownLoader(PRTERRINFO pErrInfo)
1043{
1044 /* fake */
1045 if (RT_UNLIKELY(g_uSupFakeMode))
1046 return VINF_SUCCESS;
1047
1048 /*
1049 * Lock down the module loader interface.
1050 */
1051 SUPREQHDR ReqHdr;
1052 ReqHdr.u32Cookie = g_u32Cookie;
1053 ReqHdr.u32SessionCookie = g_u32SessionCookie;
1054 ReqHdr.cbIn = SUP_IOCTL_LDR_LOCK_DOWN_SIZE_IN;
1055 ReqHdr.cbOut = SUP_IOCTL_LDR_LOCK_DOWN_SIZE_OUT;
1056 ReqHdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1057 ReqHdr.rc = VERR_INTERNAL_ERROR;
1058 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_LOCK_DOWN, &ReqHdr, SUP_IOCTL_LDR_LOCK_DOWN_SIZE);
1059 if (RT_FAILURE(rc))
1060 return RTErrInfoSetF(pErrInfo, rc,
1061 "SUPR3LockDownLoader: SUP_IOCTL_LDR_LOCK_DOWN ioctl returned %Rrc", rc);
1062
1063 return ReqHdr.rc;
1064}
1065
1066
1067/**
1068 * Fallback for SUPR3PageAllocEx on systems where RTR0MemObjPhysAllocNC isn't
1069 * supported.
1070 */
1071static int supPagePageAllocNoKernelFallback(size_t cPages, void **ppvPages, PSUPPAGE paPages)
1072{
1073 int rc = suplibOsPageAlloc(&g_supLibData, cPages, ppvPages);
1074 if (RT_SUCCESS(rc))
1075 {
1076 if (!paPages)
1077 paPages = (PSUPPAGE)alloca(sizeof(paPages[0]) * cPages);
1078 rc = supR3PageLock(*ppvPages, cPages, paPages);
1079 if (RT_FAILURE(rc))
1080 suplibOsPageFree(&g_supLibData, *ppvPages, cPages);
1081 }
1082 return rc;
1083}
1084
1085
1086SUPR3DECL(int) SUPR3PageAllocEx(size_t cPages, uint32_t fFlags, void **ppvPages, PRTR0PTR pR0Ptr, PSUPPAGE paPages)
1087{
1088 /*
1089 * Validate.
1090 */
1091 AssertPtrReturn(ppvPages, VERR_INVALID_POINTER);
1092 *ppvPages = NULL;
1093 AssertPtrNullReturn(pR0Ptr, VERR_INVALID_POINTER);
1094 if (pR0Ptr)
1095 *pR0Ptr = NIL_RTR0PTR;
1096 AssertPtrNullReturn(paPages, VERR_INVALID_POINTER);
1097 AssertMsgReturn(cPages > 0 && cPages <= VBOX_MAX_ALLOC_PAGE_COUNT, ("cPages=%zu\n", cPages), VERR_PAGE_COUNT_OUT_OF_RANGE);
1098 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
1099
1100 /* fake */
1101 if (RT_UNLIKELY(g_uSupFakeMode))
1102 {
1103 void *pv = RTMemPageAllocZ(cPages * PAGE_SIZE);
1104 if (!pv)
1105 return VERR_NO_MEMORY;
1106 *ppvPages = pv;
1107 if (pR0Ptr)
1108 *pR0Ptr = (RTR0PTR)pv;
1109 if (paPages)
1110 for (size_t iPage = 0; iPage < cPages; iPage++)
1111 {
1112 paPages[iPage].uReserved = 0;
1113 paPages[iPage].Phys = (iPage + 4321) << PAGE_SHIFT;
1114 Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
1115 }
1116 return VINF_SUCCESS;
1117 }
1118
1119 /* Check that we've got a kernel connection so rtMemSaferSupR3AllocPages
1120 can do fallback without first having to hit assertions. */
1121 if (g_supLibData.hDevice != SUP_HDEVICE_NIL)
1122 { /* likely */ }
1123 else
1124 return VERR_WRONG_ORDER;
1125
1126 /*
1127 * Use fallback for non-R0 mapping?
1128 */
1129 if ( !pR0Ptr
1130 && !g_fSupportsPageAllocNoKernel)
1131 return supPagePageAllocNoKernelFallback(cPages, ppvPages, paPages);
1132
1133 /*
1134 * Issue IOCtl to the SUPDRV kernel module.
1135 */
1136 int rc;
1137 PSUPPAGEALLOCEX pReq = (PSUPPAGEALLOCEX)RTMemTmpAllocZ(SUP_IOCTL_PAGE_ALLOC_EX_SIZE(cPages));
1138 if (pReq)
1139 {
1140 pReq->Hdr.u32Cookie = g_u32Cookie;
1141 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
1142 pReq->Hdr.cbIn = SUP_IOCTL_PAGE_ALLOC_EX_SIZE_IN;
1143 pReq->Hdr.cbOut = SUP_IOCTL_PAGE_ALLOC_EX_SIZE_OUT(cPages);
1144 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_OUT;
1145 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
1146 pReq->u.In.cPages = (uint32_t)cPages; AssertRelease(pReq->u.In.cPages == cPages);
1147 pReq->u.In.fKernelMapping = pR0Ptr != NULL;
1148 pReq->u.In.fUserMapping = true;
1149 pReq->u.In.fReserved0 = false;
1150 pReq->u.In.fReserved1 = false;
1151 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_ALLOC_EX, pReq, SUP_IOCTL_PAGE_ALLOC_EX_SIZE(cPages));
1152 if (RT_SUCCESS(rc))
1153 {
1154 rc = pReq->Hdr.rc;
1155 if (RT_SUCCESS(rc))
1156 {
1157 *ppvPages = pReq->u.Out.pvR3;
1158 if (pR0Ptr)
1159 *pR0Ptr = pReq->u.Out.pvR0;
1160 if (paPages)
1161 for (size_t iPage = 0; iPage < cPages; iPage++)
1162 {
1163 paPages[iPage].uReserved = 0;
1164 paPages[iPage].Phys = pReq->u.Out.aPages[iPage];
1165 Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
1166 }
1167#ifdef RT_OS_DARWIN /* HACK ALERT! */
1168 supR3TouchPages(pReq->u.Out.pvR3, cPages);
1169#endif
1170 }
1171 else if ( rc == VERR_NOT_SUPPORTED
1172 && !pR0Ptr)
1173 {
1174 g_fSupportsPageAllocNoKernel = false;
1175 rc = supPagePageAllocNoKernelFallback(cPages, ppvPages, paPages);
1176 }
1177 }
1178
1179 RTMemTmpFree(pReq);
1180 }
1181 else
1182 rc = VERR_NO_TMP_MEMORY;
1183 return rc;
1184
1185}
1186
1187
1188SUPR3DECL(int) SUPR3PageMapKernel(void *pvR3, uint32_t off, uint32_t cb, uint32_t fFlags, PRTR0PTR pR0Ptr)
1189{
1190 /*
1191 * Validate.
1192 */
1193 AssertPtrReturn(pvR3, VERR_INVALID_POINTER);
1194 AssertPtrReturn(pR0Ptr, VERR_INVALID_POINTER);
1195 Assert(!(off & PAGE_OFFSET_MASK));
1196 Assert(!(cb & PAGE_OFFSET_MASK) && cb);
1197 Assert(!fFlags);
1198 *pR0Ptr = NIL_RTR0PTR;
1199
1200 /* fake */
1201 if (RT_UNLIKELY(g_uSupFakeMode))
1202 return VERR_NOT_SUPPORTED;
1203
1204 /*
1205 * Issue IOCtl to the SUPDRV kernel module.
1206 */
1207 SUPPAGEMAPKERNEL Req;
1208 Req.Hdr.u32Cookie = g_u32Cookie;
1209 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1210 Req.Hdr.cbIn = SUP_IOCTL_PAGE_MAP_KERNEL_SIZE_IN;
1211 Req.Hdr.cbOut = SUP_IOCTL_PAGE_MAP_KERNEL_SIZE_OUT;
1212 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1213 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1214 Req.u.In.pvR3 = pvR3;
1215 Req.u.In.offSub = off;
1216 Req.u.In.cbSub = cb;
1217 Req.u.In.fFlags = fFlags;
1218 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_MAP_KERNEL, &Req, SUP_IOCTL_PAGE_MAP_KERNEL_SIZE);
1219 if (RT_SUCCESS(rc))
1220 rc = Req.Hdr.rc;
1221 if (RT_SUCCESS(rc))
1222 *pR0Ptr = Req.u.Out.pvR0;
1223 return rc;
1224}
1225
1226
1227SUPR3DECL(int) SUPR3PageProtect(void *pvR3, RTR0PTR R0Ptr, uint32_t off, uint32_t cb, uint32_t fProt)
1228{
1229 /*
1230 * Validate.
1231 */
1232 AssertPtrReturn(pvR3, VERR_INVALID_POINTER);
1233 Assert(!(off & PAGE_OFFSET_MASK));
1234 Assert(!(cb & PAGE_OFFSET_MASK) && cb);
1235 AssertReturn(!(fProt & ~(RTMEM_PROT_NONE | RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC)), VERR_INVALID_PARAMETER);
1236
1237 /* fake */
1238 if (RT_UNLIKELY(g_uSupFakeMode))
1239 return RTMemProtect((uint8_t *)pvR3 + off, cb, fProt);
1240
1241 /*
1242 * Some OSes can do this from ring-3, so try that before we
1243 * issue the IOCtl to the SUPDRV kernel module.
1244 * (Yea, this isn't very nice, but just try get the job done for now.)
1245 */
1246#if !defined(RT_OS_SOLARIS)
1247 RTMemProtect((uint8_t *)pvR3 + off, cb, fProt);
1248#endif
1249
1250 SUPPAGEPROTECT Req;
1251 Req.Hdr.u32Cookie = g_u32Cookie;
1252 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1253 Req.Hdr.cbIn = SUP_IOCTL_PAGE_PROTECT_SIZE_IN;
1254 Req.Hdr.cbOut = SUP_IOCTL_PAGE_PROTECT_SIZE_OUT;
1255 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1256 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1257 Req.u.In.pvR3 = pvR3;
1258 Req.u.In.pvR0 = R0Ptr;
1259 Req.u.In.offSub = off;
1260 Req.u.In.cbSub = cb;
1261 Req.u.In.fProt = fProt;
1262 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_PROTECT, &Req, SUP_IOCTL_PAGE_PROTECT_SIZE);
1263 if (RT_SUCCESS(rc))
1264 rc = Req.Hdr.rc;
1265 return rc;
1266}
1267
1268
1269SUPR3DECL(int) SUPR3PageFreeEx(void *pvPages, size_t cPages)
1270{
1271 /*
1272 * Validate.
1273 */
1274 AssertPtrReturn(pvPages, VERR_INVALID_POINTER);
1275 AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
1276
1277 /* fake */
1278 if (RT_UNLIKELY(g_uSupFakeMode))
1279 {
1280 RTMemPageFree(pvPages, cPages * PAGE_SIZE);
1281 return VINF_SUCCESS;
1282 }
1283
1284 /*
1285 * Try normal free first, then if it fails check if we're using the fallback
1286 * for the allocations without kernel mappings and attempt unlocking it.
1287 */
1288 NOREF(cPages);
1289 SUPPAGEFREE Req;
1290 Req.Hdr.u32Cookie = g_u32Cookie;
1291 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1292 Req.Hdr.cbIn = SUP_IOCTL_PAGE_FREE_SIZE_IN;
1293 Req.Hdr.cbOut = SUP_IOCTL_PAGE_FREE_SIZE_OUT;
1294 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1295 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1296 Req.u.In.pvR3 = pvPages;
1297 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_FREE, &Req, SUP_IOCTL_PAGE_FREE_SIZE);
1298 if (RT_SUCCESS(rc))
1299 {
1300 rc = Req.Hdr.rc;
1301 if ( rc == VERR_INVALID_PARAMETER
1302 && !g_fSupportsPageAllocNoKernel)
1303 {
1304 int rc2 = supR3PageUnlock(pvPages);
1305 if (RT_SUCCESS(rc2))
1306 rc = suplibOsPageFree(&g_supLibData, pvPages, cPages);
1307 }
1308 }
1309 return rc;
1310}
1311
1312
1313SUPR3DECL(void *) SUPR3ContAlloc(size_t cPages, PRTR0PTR pR0Ptr, PRTHCPHYS pHCPhys)
1314{
1315 /*
1316 * Validate.
1317 */
1318 AssertPtrReturn(pHCPhys, NULL);
1319 *pHCPhys = NIL_RTHCPHYS;
1320 AssertPtrNullReturn(pR0Ptr, NULL);
1321 if (pR0Ptr)
1322 *pR0Ptr = NIL_RTR0PTR;
1323 AssertPtrNullReturn(pHCPhys, NULL);
1324 AssertMsgReturn(cPages > 0 && cPages < 256, ("cPages=%d must be > 0 and < 256\n", cPages), NULL);
1325
1326 /* fake */
1327 if (RT_UNLIKELY(g_uSupFakeMode))
1328 {
1329 void *pv = RTMemPageAllocZ(cPages * PAGE_SIZE);
1330 if (pR0Ptr)
1331 *pR0Ptr = (RTR0PTR)pv;
1332 if (pHCPhys)
1333 *pHCPhys = (uintptr_t)pv + (PAGE_SHIFT * 1024);
1334 return pv;
1335 }
1336
1337 /*
1338 * Issue IOCtl to the SUPDRV kernel module.
1339 */
1340 SUPCONTALLOC Req;
1341 Req.Hdr.u32Cookie = g_u32Cookie;
1342 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1343 Req.Hdr.cbIn = SUP_IOCTL_CONT_ALLOC_SIZE_IN;
1344 Req.Hdr.cbOut = SUP_IOCTL_CONT_ALLOC_SIZE_OUT;
1345 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1346 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1347 Req.u.In.cPages = (uint32_t)cPages;
1348 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CONT_ALLOC, &Req, SUP_IOCTL_CONT_ALLOC_SIZE);
1349 if ( RT_SUCCESS(rc)
1350 && RT_SUCCESS(Req.Hdr.rc))
1351 {
1352 *pHCPhys = Req.u.Out.HCPhys;
1353 if (pR0Ptr)
1354 *pR0Ptr = Req.u.Out.pvR0;
1355#ifdef RT_OS_DARWIN /* HACK ALERT! */
1356 supR3TouchPages(Req.u.Out.pvR3, cPages);
1357#endif
1358 return Req.u.Out.pvR3;
1359 }
1360
1361 return NULL;
1362}
1363
1364
1365SUPR3DECL(int) SUPR3ContFree(void *pv, size_t cPages)
1366{
1367 /*
1368 * Validate.
1369 */
1370 if (!pv)
1371 return VINF_SUCCESS;
1372 AssertPtrReturn(pv, VERR_INVALID_POINTER);
1373 AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
1374
1375 /* fake */
1376 if (RT_UNLIKELY(g_uSupFakeMode))
1377 {
1378 RTMemPageFree(pv, cPages * PAGE_SIZE);
1379 return VINF_SUCCESS;
1380 }
1381
1382 /*
1383 * Issue IOCtl to the SUPDRV kernel module.
1384 */
1385 SUPCONTFREE Req;
1386 Req.Hdr.u32Cookie = g_u32Cookie;
1387 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1388 Req.Hdr.cbIn = SUP_IOCTL_CONT_FREE_SIZE_IN;
1389 Req.Hdr.cbOut = SUP_IOCTL_CONT_FREE_SIZE_OUT;
1390 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1391 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1392 Req.u.In.pvR3 = pv;
1393 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CONT_FREE, &Req, SUP_IOCTL_CONT_FREE_SIZE);
1394 if (RT_SUCCESS(rc))
1395 rc = Req.Hdr.rc;
1396 return rc;
1397}
1398
1399
1400SUPR3DECL(int) SUPR3LowAlloc(size_t cPages, void **ppvPages, PRTR0PTR ppvPagesR0, PSUPPAGE paPages)
1401{
1402 /*
1403 * Validate.
1404 */
1405 AssertPtrReturn(ppvPages, VERR_INVALID_POINTER);
1406 *ppvPages = NULL;
1407 AssertPtrReturn(paPages, VERR_INVALID_POINTER);
1408 AssertMsgReturn(cPages > 0 && cPages < 256, ("cPages=%d must be > 0 and < 256\n", cPages), VERR_PAGE_COUNT_OUT_OF_RANGE);
1409
1410 /* fake */
1411 if (RT_UNLIKELY(g_uSupFakeMode))
1412 {
1413 *ppvPages = RTMemPageAllocZ((size_t)cPages * PAGE_SIZE);
1414 if (!*ppvPages)
1415 return VERR_NO_LOW_MEMORY;
1416
1417 /* fake physical addresses. */
1418 RTHCPHYS Phys = (uintptr_t)*ppvPages + PAGE_SIZE * 1024;
1419 size_t iPage = cPages;
1420 while (iPage-- > 0)
1421 paPages[iPage].Phys = Phys + (iPage << PAGE_SHIFT);
1422 return VINF_SUCCESS;
1423 }
1424
1425 /*
1426 * Issue IOCtl to the SUPDRV kernel module.
1427 */
1428 int rc;
1429 PSUPLOWALLOC pReq = (PSUPLOWALLOC)RTMemTmpAllocZ(SUP_IOCTL_LOW_ALLOC_SIZE(cPages));
1430 if (pReq)
1431 {
1432 pReq->Hdr.u32Cookie = g_u32Cookie;
1433 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
1434 pReq->Hdr.cbIn = SUP_IOCTL_LOW_ALLOC_SIZE_IN;
1435 pReq->Hdr.cbOut = SUP_IOCTL_LOW_ALLOC_SIZE_OUT(cPages);
1436 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_OUT;
1437 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
1438 pReq->u.In.cPages = (uint32_t)cPages; AssertRelease(pReq->u.In.cPages == cPages);
1439 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LOW_ALLOC, pReq, SUP_IOCTL_LOW_ALLOC_SIZE(cPages));
1440 if (RT_SUCCESS(rc))
1441 rc = pReq->Hdr.rc;
1442 if (RT_SUCCESS(rc))
1443 {
1444 *ppvPages = pReq->u.Out.pvR3;
1445 if (ppvPagesR0)
1446 *ppvPagesR0 = pReq->u.Out.pvR0;
1447 if (paPages)
1448 for (size_t iPage = 0; iPage < cPages; iPage++)
1449 {
1450 paPages[iPage].uReserved = 0;
1451 paPages[iPage].Phys = pReq->u.Out.aPages[iPage];
1452 Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
1453 Assert(paPages[iPage].Phys <= UINT32_C(0xfffff000));
1454 }
1455#ifdef RT_OS_DARWIN /* HACK ALERT! */
1456 supR3TouchPages(pReq->u.Out.pvR3, cPages);
1457#endif
1458 }
1459 RTMemTmpFree(pReq);
1460 }
1461 else
1462 rc = VERR_NO_TMP_MEMORY;
1463
1464 return rc;
1465}
1466
1467
1468SUPR3DECL(int) SUPR3LowFree(void *pv, size_t cPages)
1469{
1470 /*
1471 * Validate.
1472 */
1473 if (!pv)
1474 return VINF_SUCCESS;
1475 AssertPtrReturn(pv, VERR_INVALID_POINTER);
1476 AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
1477
1478 /* fake */
1479 if (RT_UNLIKELY(g_uSupFakeMode))
1480 {
1481 RTMemPageFree(pv, cPages * PAGE_SIZE);
1482 return VINF_SUCCESS;
1483 }
1484
1485 /*
1486 * Issue IOCtl to the SUPDRV kernel module.
1487 */
1488 SUPCONTFREE Req;
1489 Req.Hdr.u32Cookie = g_u32Cookie;
1490 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1491 Req.Hdr.cbIn = SUP_IOCTL_LOW_FREE_SIZE_IN;
1492 Req.Hdr.cbOut = SUP_IOCTL_LOW_FREE_SIZE_OUT;
1493 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1494 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1495 Req.u.In.pvR3 = pv;
1496 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LOW_FREE, &Req, SUP_IOCTL_LOW_FREE_SIZE);
1497 if (RT_SUCCESS(rc))
1498 rc = Req.Hdr.rc;
1499 return rc;
1500}
1501
1502
1503SUPR3DECL(int) SUPR3HardenedVerifyInit(void)
1504{
1505#ifdef RT_OS_WINDOWS
1506 if (g_cInits == 0)
1507 return suplibOsHardenedVerifyInit();
1508#endif
1509 return VINF_SUCCESS;
1510}
1511
1512
1513SUPR3DECL(int) SUPR3HardenedVerifyTerm(void)
1514{
1515#ifdef RT_OS_WINDOWS
1516 if (g_cInits == 0)
1517 return suplibOsHardenedVerifyTerm();
1518#endif
1519 return VINF_SUCCESS;
1520}
1521
1522
1523SUPR3DECL(int) SUPR3HardenedVerifyFile(const char *pszFilename, const char *pszMsg, PRTFILE phFile)
1524{
1525 /*
1526 * Quick input validation.
1527 */
1528 AssertPtr(pszFilename);
1529 AssertPtr(pszMsg);
1530 AssertReturn(!phFile, VERR_NOT_IMPLEMENTED); /** @todo Implement this. The deal is that we make sure the
1531 file is the same we verified after opening it. */
1532 RT_NOREF2(pszFilename, pszMsg);
1533
1534 /*
1535 * Only do the actual check in hardened builds.
1536 */
1537#ifdef VBOX_WITH_HARDENING
1538 int rc = supR3HardenedVerifyFixedFile(pszFilename, false /* fFatal */);
1539 if (RT_FAILURE(rc))
1540 LogRel(("SUPR3HardenedVerifyFile: %s: Verification of \"%s\" failed, rc=%Rrc\n", pszMsg, pszFilename, rc));
1541 return rc;
1542#else
1543 return VINF_SUCCESS;
1544#endif
1545}
1546
1547
1548SUPR3DECL(int) SUPR3HardenedVerifySelf(const char *pszArgv0, bool fInternal, PRTERRINFO pErrInfo)
1549{
1550 /*
1551 * Quick input validation.
1552 */
1553 AssertPtr(pszArgv0);
1554 RTErrInfoClear(pErrInfo);
1555
1556 /*
1557 * Get the executable image path as we need it for all the tests here.
1558 */
1559 char szExecPath[RTPATH_MAX];
1560 if (!RTProcGetExecutablePath(szExecPath, sizeof(szExecPath)))
1561 return RTErrInfoSet(pErrInfo, VERR_INTERNAL_ERROR_2, "RTProcGetExecutablePath failed");
1562
1563 int rc;
1564 if (fInternal)
1565 {
1566 /*
1567 * Internal applications must be launched directly without any PATH
1568 * searching involved.
1569 */
1570 if (RTPathCompare(pszArgv0, szExecPath) != 0)
1571 return RTErrInfoSetF(pErrInfo, VERR_SUPLIB_INVALID_ARGV0_INTERNAL,
1572 "argv[0] does not match the executable image path: '%s' != '%s'", pszArgv0, szExecPath);
1573
1574 /*
1575 * Internal applications must reside in or under the
1576 * RTPathAppPrivateArch directory.
1577 */
1578 char szAppPrivateArch[RTPATH_MAX];
1579 rc = RTPathAppPrivateArch(szAppPrivateArch, sizeof(szAppPrivateArch));
1580 if (RT_FAILURE(rc))
1581 return RTErrInfoSetF(pErrInfo, VERR_SUPLIB_INVALID_ARGV0_INTERNAL,
1582 "RTPathAppPrivateArch failed with rc=%Rrc", rc);
1583 size_t cchAppPrivateArch = strlen(szAppPrivateArch);
1584 if ( cchAppPrivateArch >= strlen(szExecPath)
1585 || !RTPATH_IS_SLASH(szExecPath[cchAppPrivateArch]))
1586 return RTErrInfoSet(pErrInfo, VERR_SUPLIB_INVALID_INTERNAL_APP_DIR,
1587 "Internal executable does reside under RTPathAppPrivateArch");
1588 szExecPath[cchAppPrivateArch] = '\0';
1589 if (RTPathCompare(szExecPath, szAppPrivateArch) != 0)
1590 return RTErrInfoSet(pErrInfo, VERR_SUPLIB_INVALID_INTERNAL_APP_DIR,
1591 "Internal executable does reside under RTPathAppPrivateArch");
1592 szExecPath[cchAppPrivateArch] = RTPATH_SLASH;
1593 }
1594
1595#ifdef VBOX_WITH_HARDENING
1596 /*
1597 * Verify that the image file and parent directories are sane.
1598 */
1599 rc = supR3HardenedVerifyFile(szExecPath, RTHCUINTPTR_MAX, false /*fMaybe3rdParty*/, pErrInfo);
1600 if (RT_FAILURE(rc))
1601 return rc;
1602#endif
1603
1604 return VINF_SUCCESS;
1605}
1606
1607
1608SUPR3DECL(int) SUPR3HardenedVerifyDir(const char *pszDirPath, bool fRecursive, bool fCheckFiles, PRTERRINFO pErrInfo)
1609{
1610 /*
1611 * Quick input validation
1612 */
1613 AssertPtr(pszDirPath);
1614 RTErrInfoClear(pErrInfo);
1615
1616 /*
1617 * Only do the actual check in hardened builds.
1618 */
1619#ifdef VBOX_WITH_HARDENING
1620 int rc = supR3HardenedVerifyDir(pszDirPath, fRecursive, fCheckFiles, pErrInfo);
1621 if (RT_FAILURE(rc) && !RTErrInfoIsSet(pErrInfo))
1622 LogRel(("supR3HardenedVerifyDir: Verification of \"%s\" failed, rc=%Rrc\n", pszDirPath, rc));
1623 return rc;
1624#else
1625 NOREF(pszDirPath); NOREF(fRecursive); NOREF(fCheckFiles);
1626 return VINF_SUCCESS;
1627#endif
1628}
1629
1630
1631SUPR3DECL(int) SUPR3HardenedVerifyPlugIn(const char *pszFilename, PRTERRINFO pErrInfo)
1632{
1633 /*
1634 * Quick input validation
1635 */
1636 AssertPtr(pszFilename);
1637 RTErrInfoClear(pErrInfo);
1638
1639 /*
1640 * Only do the actual check in hardened builds.
1641 */
1642#ifdef VBOX_WITH_HARDENING
1643 int rc = supR3HardenedVerifyFile(pszFilename, RTHCUINTPTR_MAX, true /*fMaybe3rdParty*/, pErrInfo);
1644 if (RT_FAILURE(rc) && !RTErrInfoIsSet(pErrInfo))
1645 LogRel(("supR3HardenedVerifyFile: Verification of \"%s\" failed, rc=%Rrc\n", pszFilename, rc));
1646 return rc;
1647#else
1648 RT_NOREF1(pszFilename);
1649 return VINF_SUCCESS;
1650#endif
1651}
1652
1653
1654SUPR3DECL(int) SUPR3GipGetPhys(PRTHCPHYS pHCPhys)
1655{
1656 if (g_pSUPGlobalInfoPage)
1657 {
1658 *pHCPhys = g_HCPhysSUPGlobalInfoPage;
1659 return VINF_SUCCESS;
1660 }
1661 *pHCPhys = NIL_RTHCPHYS;
1662 return VERR_WRONG_ORDER;
1663}
1664
1665
1666SUPR3DECL(int) SUPR3QueryVTxSupported(const char **ppszWhy)
1667{
1668 *ppszWhy = NULL;
1669#ifdef RT_OS_LINUX
1670 return suplibOsQueryVTxSupported(ppszWhy);
1671#else
1672 return VINF_SUCCESS;
1673#endif
1674}
1675
1676
1677SUPR3DECL(int) SUPR3QueryVTCaps(uint32_t *pfCaps)
1678{
1679 AssertPtrReturn(pfCaps, VERR_INVALID_POINTER);
1680
1681 *pfCaps = 0;
1682
1683 /* fake */
1684 if (RT_UNLIKELY(g_uSupFakeMode))
1685 return VINF_SUCCESS;
1686
1687 /*
1688 * Issue IOCtl to the SUPDRV kernel module.
1689 */
1690 SUPVTCAPS Req;
1691 Req.Hdr.u32Cookie = g_u32Cookie;
1692 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1693 Req.Hdr.cbIn = SUP_IOCTL_VT_CAPS_SIZE_IN;
1694 Req.Hdr.cbOut = SUP_IOCTL_VT_CAPS_SIZE_OUT;
1695 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1696 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1697 Req.u.Out.fCaps = 0;
1698 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_VT_CAPS, &Req, SUP_IOCTL_VT_CAPS_SIZE);
1699 if (RT_SUCCESS(rc))
1700 {
1701 rc = Req.Hdr.rc;
1702 if (RT_SUCCESS(rc))
1703 *pfCaps = Req.u.Out.fCaps;
1704 }
1705 return rc;
1706}
1707
1708
1709SUPR3DECL(bool) SUPR3IsNemSupportedWhenNoVtxOrAmdV(void)
1710{
1711#ifdef RT_OS_WINDOWS
1712 return suplibOsIsNemSupportedWhenNoVtxOrAmdV();
1713#else
1714 return false;
1715#endif
1716}
1717
1718
1719SUPR3DECL(int) SUPR3QueryMicrocodeRev(uint32_t *uMicrocodeRev)
1720{
1721 AssertPtrReturn(uMicrocodeRev, VERR_INVALID_POINTER);
1722
1723 *uMicrocodeRev = 0;
1724
1725 /* fake */
1726 if (RT_UNLIKELY(g_uSupFakeMode))
1727 return VINF_SUCCESS;
1728
1729 /*
1730 * Issue IOCtl to the SUPDRV kernel module.
1731 */
1732 SUPUCODEREV Req;
1733 Req.Hdr.u32Cookie = g_u32Cookie;
1734 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1735 Req.Hdr.cbIn = SUP_IOCTL_UCODE_REV_SIZE_IN;
1736 Req.Hdr.cbOut = SUP_IOCTL_UCODE_REV_SIZE_OUT;
1737 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1738 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1739 Req.u.Out.MicrocodeRev = 0;
1740 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_UCODE_REV, &Req, SUP_IOCTL_UCODE_REV_SIZE);
1741 if (RT_SUCCESS(rc))
1742 {
1743 rc = Req.Hdr.rc;
1744 if (RT_SUCCESS(rc))
1745 *uMicrocodeRev = Req.u.Out.MicrocodeRev;
1746 }
1747 return rc;
1748}
1749
1750
1751SUPR3DECL(int) SUPR3TracerOpen(uint32_t uCookie, uintptr_t uArg)
1752{
1753 /* fake */
1754 if (RT_UNLIKELY(g_uSupFakeMode))
1755 return VINF_SUCCESS;
1756
1757 /*
1758 * Issue IOCtl to the SUPDRV kernel module.
1759 */
1760 SUPTRACEROPEN Req;
1761 Req.Hdr.u32Cookie = g_u32Cookie;
1762 Req.Hdr.u32SessionCookie= g_u32SessionCookie;
1763 Req.Hdr.cbIn = SUP_IOCTL_TRACER_OPEN_SIZE_IN;
1764 Req.Hdr.cbOut = SUP_IOCTL_TRACER_OPEN_SIZE_OUT;
1765 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1766 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1767 Req.u.In.uCookie = uCookie;
1768 Req.u.In.uArg = uArg;
1769 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_TRACER_OPEN, &Req, SUP_IOCTL_TRACER_OPEN_SIZE);
1770 if (RT_SUCCESS(rc))
1771 rc = Req.Hdr.rc;
1772 return rc;
1773}
1774
1775
1776SUPR3DECL(int) SUPR3TracerClose(void)
1777{
1778 /* fake */
1779 if (RT_UNLIKELY(g_uSupFakeMode))
1780 return VINF_SUCCESS;
1781
1782 /*
1783 * Issue IOCtl to the SUPDRV kernel module.
1784 */
1785 SUPREQHDR Req;
1786 Req.u32Cookie = g_u32Cookie;
1787 Req.u32SessionCookie= g_u32SessionCookie;
1788 Req.cbIn = SUP_IOCTL_TRACER_OPEN_SIZE_IN;
1789 Req.cbOut = SUP_IOCTL_TRACER_OPEN_SIZE_OUT;
1790 Req.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1791 Req.rc = VERR_INTERNAL_ERROR;
1792 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_TRACER_CLOSE, &Req, SUP_IOCTL_TRACER_CLOSE_SIZE);
1793 if (RT_SUCCESS(rc))
1794 rc = Req.rc;
1795 return rc;
1796}
1797
1798
1799SUPR3DECL(int) SUPR3TracerIoCtl(uintptr_t uCmd, uintptr_t uArg, int32_t *piRetVal)
1800{
1801 /* fake */
1802 if (RT_UNLIKELY(g_uSupFakeMode))
1803 {
1804 *piRetVal = -1;
1805 return VERR_NOT_SUPPORTED;
1806 }
1807
1808 /*
1809 * Issue IOCtl to the SUPDRV kernel module.
1810 */
1811 SUPTRACERIOCTL Req;
1812 Req.Hdr.u32Cookie = g_u32Cookie;
1813 Req.Hdr.u32SessionCookie= g_u32SessionCookie;
1814 Req.Hdr.cbIn = SUP_IOCTL_TRACER_IOCTL_SIZE_IN;
1815 Req.Hdr.cbOut = SUP_IOCTL_TRACER_IOCTL_SIZE_OUT;
1816 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1817 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1818 Req.u.In.uCmd = uCmd;
1819 Req.u.In.uArg = uArg;
1820 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_TRACER_IOCTL, &Req, SUP_IOCTL_TRACER_IOCTL_SIZE);
1821 if (RT_SUCCESS(rc))
1822 {
1823 rc = Req.Hdr.rc;
1824 *piRetVal = Req.u.Out.iRetVal;
1825 }
1826 return rc;
1827}
1828
1829
1830
1831typedef struct SUPDRVTRACERSTRTAB
1832{
1833 /** Pointer to the string table. */
1834 char *pchStrTab;
1835 /** The actual string table size. */
1836 uint32_t cbStrTab;
1837 /** The original string pointers. */
1838 RTUINTPTR apszOrgFunctions[1];
1839} SUPDRVTRACERSTRTAB, *PSUPDRVTRACERSTRTAB;
1840
1841
1842/**
1843 * Destroys a string table, restoring the original pszFunction member valus.
1844 *
1845 * @param pThis The string table structure.
1846 * @param paProbeLocs32 The probe location array, 32-bit type variant.
1847 * @param paProbeLocs64 The probe location array, 64-bit type variant.
1848 * @param cProbeLocs The number of elements in the array.
1849 * @param f32Bit Set if @a paProbeLocs32 should be used, when
1850 * clear use @a paProbeLocs64.
1851 */
1852static void supr3TracerDestroyStrTab(PSUPDRVTRACERSTRTAB pThis, PVTGPROBELOC32 paProbeLocs32, PVTGPROBELOC64 paProbeLocs64,
1853 uint32_t cProbeLocs, bool f32Bit)
1854{
1855 /* Restore. */
1856 size_t i = cProbeLocs;
1857 if (f32Bit)
1858 while (i--)
1859 paProbeLocs32[i].pszFunction = (uint32_t)pThis->apszOrgFunctions[i];
1860 else
1861 while (i--)
1862 paProbeLocs64[i].pszFunction = pThis->apszOrgFunctions[i];
1863
1864 /* Free. */
1865 RTMemFree(pThis->pchStrTab);
1866 RTMemFree(pThis);
1867}
1868
1869
1870/**
1871 * Creates a string table for the pszFunction members in the probe location
1872 * array.
1873 *
1874 * This will save and replace the pszFunction members with offsets.
1875 *
1876 * @returns Pointer to a string table structure. NULL on failure.
1877 * @param paProbeLocs32 The probe location array, 32-bit type variant.
1878 * @param paProbeLocs64 The probe location array, 64-bit type variant.
1879 * @param cProbeLocs The number of elements in the array.
1880 * @param offDelta Relocation offset for the string pointers.
1881 * @param f32Bit Set if @a paProbeLocs32 should be used, when
1882 * clear use @a paProbeLocs64.
1883 */
1884static PSUPDRVTRACERSTRTAB supr3TracerCreateStrTab(PVTGPROBELOC32 paProbeLocs32,
1885 PVTGPROBELOC64 paProbeLocs64,
1886 uint32_t cProbeLocs,
1887 RTUINTPTR offDelta,
1888 bool f32Bit)
1889{
1890 if (cProbeLocs > _128K)
1891 return NULL;
1892
1893 /*
1894 * Allocate the string table structures.
1895 */
1896 size_t cbThis = RT_UOFFSETOF_DYN(SUPDRVTRACERSTRTAB, apszOrgFunctions[cProbeLocs]);
1897 PSUPDRVTRACERSTRTAB pThis = (PSUPDRVTRACERSTRTAB)RTMemAlloc(cbThis);
1898 if (!pThis)
1899 return NULL;
1900
1901 uint32_t const cHashBits = cProbeLocs * 2 - 1;
1902 uint32_t *pbmHash = (uint32_t *)RTMemAllocZ(RT_ALIGN_32(cHashBits, 64) / 8 );
1903 if (!pbmHash)
1904 {
1905 RTMemFree(pThis);
1906 return NULL;
1907 }
1908
1909 /*
1910 * Calc the max string table size and save the orignal pointers so we can
1911 * replace them later.
1912 */
1913 size_t cbMax = 1;
1914 for (uint32_t i = 0; i < cProbeLocs; i++)
1915 {
1916 pThis->apszOrgFunctions[i] = f32Bit ? paProbeLocs32[i].pszFunction : paProbeLocs64[i].pszFunction;
1917 const char *pszFunction = (const char *)(uintptr_t)(pThis->apszOrgFunctions[i] + offDelta);
1918 size_t cch = strlen(pszFunction);
1919 if (cch > _1K)
1920 {
1921 cbMax = 0;
1922 break;
1923 }
1924 cbMax += cch + 1;
1925 }
1926
1927 /* Alloc space for it. */
1928 if (cbMax > 0)
1929 pThis->pchStrTab = (char *)RTMemAlloc(cbMax);
1930 else
1931 pThis->pchStrTab = NULL;
1932 if (!pThis->pchStrTab)
1933 {
1934 RTMemFree(pbmHash);
1935 RTMemFree(pThis);
1936 return NULL;
1937 }
1938
1939 /*
1940 * Create the string table.
1941 */
1942 uint32_t off = 0;
1943 uint32_t offPrev = 0;
1944
1945 for (uint32_t i = 0; i < cProbeLocs; i++)
1946 {
1947 const char * const psz = (const char *)(uintptr_t)(pThis->apszOrgFunctions[i] + offDelta);
1948 size_t const cch = strlen(psz);
1949 uint32_t const iHashBit = RTStrHash1(psz) % cHashBits;
1950 if (ASMBitTestAndSet(pbmHash, iHashBit))
1951 {
1952 /* Often it's the most recent string. */
1953 if ( off - offPrev < cch + 1
1954 || memcmp(&pThis->pchStrTab[offPrev], psz, cch + 1))
1955 {
1956 /* It wasn't, search the entire string table. (lazy bird) */
1957 offPrev = 0;
1958 while (offPrev < off)
1959 {
1960 size_t cchCur = strlen(&pThis->pchStrTab[offPrev]);
1961 if ( cchCur == cch
1962 && !memcmp(&pThis->pchStrTab[offPrev], psz, cch + 1))
1963 break;
1964 offPrev += (uint32_t)cchCur + 1;
1965 }
1966 }
1967 }
1968 else
1969 offPrev = off;
1970
1971 /* Add the string to the table. */
1972 if (offPrev >= off)
1973 {
1974 memcpy(&pThis->pchStrTab[off], psz, cch + 1);
1975 offPrev = off;
1976 off += (uint32_t)cch + 1;
1977 }
1978
1979 /* Update the entry */
1980 if (f32Bit)
1981 paProbeLocs32[i].pszFunction = offPrev;
1982 else
1983 paProbeLocs64[i].pszFunction = offPrev;
1984 }
1985
1986 pThis->cbStrTab = off;
1987 RTMemFree(pbmHash);
1988 return pThis;
1989}
1990
1991
1992
1993SUPR3DECL(int) SUPR3TracerRegisterModule(uintptr_t hModNative, const char *pszModule, struct VTGOBJHDR *pVtgHdr,
1994 RTUINTPTR uVtgHdrAddr, uint32_t fFlags)
1995{
1996 /* Validate input. */
1997 NOREF(hModNative);
1998 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
1999 AssertReturn(!memcmp(pVtgHdr->szMagic, VTGOBJHDR_MAGIC, sizeof(pVtgHdr->szMagic)), VERR_SUPDRV_VTG_MAGIC);
2000 AssertPtrReturn(pszModule, VERR_INVALID_POINTER);
2001 size_t cchModule = strlen(pszModule);
2002 AssertReturn(cchModule < RT_SIZEOFMEMB(SUPTRACERUMODREG, u.In.szName), VERR_FILENAME_TOO_LONG);
2003 AssertReturn(!RTPathHavePath(pszModule), VERR_INVALID_PARAMETER);
2004 AssertReturn(fFlags == SUP_TRACER_UMOD_FLAGS_EXE || fFlags == SUP_TRACER_UMOD_FLAGS_SHARED, VERR_INVALID_PARAMETER);
2005
2006 /*
2007 * Set the probe location array offset and size members. If the size is
2008 * zero, don't bother ring-0 with it.
2009 */
2010 if (!pVtgHdr->offProbeLocs)
2011 {
2012 uint64_t u64Tmp = pVtgHdr->uProbeLocsEnd.u64 - pVtgHdr->uProbeLocs.u64;
2013 if (u64Tmp >= UINT32_MAX)
2014 return VERR_SUPDRV_VTG_BAD_HDR_TOO_MUCH;
2015 pVtgHdr->cbProbeLocs = (uint32_t)u64Tmp;
2016
2017 u64Tmp = pVtgHdr->uProbeLocs.u64 - uVtgHdrAddr;
2018 if ((int64_t)u64Tmp != (int32_t)u64Tmp)
2019 {
2020 LogRel(("SUPR3TracerRegisterModule: VERR_SUPDRV_VTG_BAD_HDR_PTR - u64Tmp=%#llx uProbeLocs=%#llx uVtgHdrAddr=%RTptr\n",
2021 u64Tmp, pVtgHdr->uProbeLocs.u64, uVtgHdrAddr));
2022 return VERR_SUPDRV_VTG_BAD_HDR_PTR;
2023 }
2024 pVtgHdr->offProbeLocs = (int32_t)u64Tmp;
2025 }
2026
2027 if ( !pVtgHdr->cbProbeLocs
2028 || !pVtgHdr->cbProbes)
2029 return VINF_SUCCESS;
2030
2031 /*
2032 * Fake out.
2033 */
2034 if (RT_UNLIKELY(g_uSupFakeMode))
2035 return VINF_SUCCESS;
2036
2037 /*
2038 * Create a string table for the function names in the location array.
2039 * It's somewhat easier to do that here than from ring-0.
2040 */
2041 uint32_t const cProbeLocs = pVtgHdr->cbProbeLocs
2042 / (pVtgHdr->cBits == 32 ? sizeof(VTGPROBELOC32) : sizeof(VTGPROBELOC64));
2043 PVTGPROBELOC paProbeLocs = (PVTGPROBELOC)((uintptr_t)pVtgHdr + pVtgHdr->offProbeLocs);
2044 PSUPDRVTRACERSTRTAB pStrTab = supr3TracerCreateStrTab((PVTGPROBELOC32)paProbeLocs,
2045 (PVTGPROBELOC64)paProbeLocs,
2046 cProbeLocs, (uintptr_t)pVtgHdr - uVtgHdrAddr,
2047 pVtgHdr->cBits == 32);
2048 if (!pStrTab)
2049 return VERR_NO_MEMORY;
2050
2051
2052 /*
2053 * Issue IOCtl to the SUPDRV kernel module.
2054 */
2055 SUPTRACERUMODREG Req;
2056 Req.Hdr.u32Cookie = g_u32Cookie;
2057 Req.Hdr.u32SessionCookie= g_u32SessionCookie;
2058 Req.Hdr.cbIn = SUP_IOCTL_TRACER_UMOD_REG_SIZE_IN;
2059 Req.Hdr.cbOut = SUP_IOCTL_TRACER_UMOD_REG_SIZE_OUT;
2060 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
2061 Req.Hdr.rc = VERR_INTERNAL_ERROR;
2062 Req.u.In.uVtgHdrAddr = uVtgHdrAddr;
2063 Req.u.In.R3PtrVtgHdr = pVtgHdr;
2064 Req.u.In.R3PtrStrTab = pStrTab->pchStrTab;
2065 Req.u.In.cbStrTab = pStrTab->cbStrTab;
2066 Req.u.In.fFlags = fFlags;
2067
2068 memcpy(Req.u.In.szName, pszModule, cchModule + 1);
2069 if (!RTPathHasSuffix(Req.u.In.szName))
2070 {
2071 /* Add the default suffix if none is given. */
2072 switch (fFlags & SUP_TRACER_UMOD_FLAGS_TYPE_MASK)
2073 {
2074#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
2075 case SUP_TRACER_UMOD_FLAGS_EXE:
2076 if (cchModule + sizeof(".exe") <= sizeof(Req.u.In.szName))
2077 strcpy(&Req.u.In.szName[cchModule], ".exe");
2078 break;
2079#endif
2080
2081 case SUP_TRACER_UMOD_FLAGS_SHARED:
2082 {
2083 const char *pszSuff = RTLdrGetSuff();
2084 size_t cchSuff = strlen(pszSuff);
2085 if (cchModule + cchSuff < sizeof(Req.u.In.szName))
2086 memcpy(&Req.u.In.szName[cchModule], pszSuff, cchSuff + 1);
2087 break;
2088 }
2089 }
2090 }
2091
2092 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_TRACER_UMOD_REG, &Req, SUP_IOCTL_TRACER_UMOD_REG_SIZE);
2093 if (RT_SUCCESS(rc))
2094 rc = Req.Hdr.rc;
2095
2096 supr3TracerDestroyStrTab(pStrTab, (PVTGPROBELOC32)paProbeLocs, (PVTGPROBELOC64)paProbeLocs,
2097 cProbeLocs, pVtgHdr->cBits == 32);
2098 return rc;
2099}
2100
2101
2102SUPR3DECL(int) SUPR3TracerDeregisterModule(struct VTGOBJHDR *pVtgHdr)
2103{
2104 /* Validate input. */
2105 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
2106 AssertReturn(!memcmp(pVtgHdr->szMagic, VTGOBJHDR_MAGIC, sizeof(pVtgHdr->szMagic)), VERR_SUPDRV_VTG_MAGIC);
2107
2108 /*
2109 * Don't bother if the object is empty.
2110 */
2111 if ( !pVtgHdr->cbProbeLocs
2112 || !pVtgHdr->cbProbes)
2113 return VINF_SUCCESS;
2114
2115 /*
2116 * Fake out.
2117 */
2118 if (RT_UNLIKELY(g_uSupFakeMode))
2119 return VINF_SUCCESS;
2120
2121 /*
2122 * Issue IOCtl to the SUPDRV kernel module.
2123 */
2124 SUPTRACERUMODDEREG Req;
2125 Req.Hdr.u32Cookie = g_u32Cookie;
2126 Req.Hdr.u32SessionCookie= g_u32SessionCookie;
2127 Req.Hdr.cbIn = SUP_IOCTL_TRACER_UMOD_REG_SIZE_IN;
2128 Req.Hdr.cbOut = SUP_IOCTL_TRACER_UMOD_REG_SIZE_OUT;
2129 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
2130 Req.Hdr.rc = VERR_INTERNAL_ERROR;
2131 Req.u.In.pVtgHdr = pVtgHdr;
2132
2133 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_TRACER_UMOD_DEREG, &Req, SUP_IOCTL_TRACER_UMOD_DEREG_SIZE);
2134 if (RT_SUCCESS(rc))
2135 rc = Req.Hdr.rc;
2136 return rc;
2137}
2138
2139
2140DECLASM(void) suplibTracerFireProbe(PVTGPROBELOC pProbeLoc, PSUPTRACERUMODFIREPROBE pReq)
2141{
2142 RT_NOREF1(pProbeLoc);
2143
2144 pReq->Hdr.u32Cookie = g_u32Cookie;
2145 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
2146 Assert(pReq->Hdr.cbIn == SUP_IOCTL_TRACER_UMOD_FIRE_PROBE_SIZE_IN);
2147 Assert(pReq->Hdr.cbOut == SUP_IOCTL_TRACER_UMOD_FIRE_PROBE_SIZE_OUT);
2148 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
2149 pReq->Hdr.rc = VINF_SUCCESS;
2150
2151 suplibOsIOCtl(&g_supLibData, SUP_IOCTL_TRACER_UMOD_FIRE_PROBE, pReq, SUP_IOCTL_TRACER_UMOD_FIRE_PROBE_SIZE);
2152}
2153
2154
2155SUPR3DECL(int) SUPR3MsrProberRead(uint32_t uMsr, RTCPUID idCpu, uint64_t *puValue, bool *pfGp)
2156{
2157 SUPMSRPROBER Req;
2158 Req.Hdr.u32Cookie = g_u32Cookie;
2159 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
2160 Req.Hdr.cbIn = SUP_IOCTL_MSR_PROBER_SIZE_IN;
2161 Req.Hdr.cbOut = SUP_IOCTL_MSR_PROBER_SIZE_OUT;
2162 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
2163 Req.Hdr.rc = VERR_INTERNAL_ERROR;
2164
2165 Req.u.In.enmOp = SUPMSRPROBEROP_READ;
2166 Req.u.In.uMsr = uMsr;
2167 Req.u.In.idCpu = idCpu == NIL_RTCPUID ? UINT32_MAX : idCpu;
2168
2169 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_MSR_PROBER, &Req, SUP_IOCTL_MSR_PROBER_SIZE);
2170 if (RT_SUCCESS(rc))
2171 rc = Req.Hdr.rc;
2172 if (RT_SUCCESS(rc))
2173 {
2174 if (puValue)
2175 *puValue = Req.u.Out.uResults.Read.uValue;
2176 if (pfGp)
2177 *pfGp = Req.u.Out.uResults.Read.fGp;
2178 }
2179
2180 return rc;
2181}
2182
2183
2184SUPR3DECL(int) SUPR3MsrProberWrite(uint32_t uMsr, RTCPUID idCpu, uint64_t uValue, bool *pfGp)
2185{
2186 SUPMSRPROBER Req;
2187 Req.Hdr.u32Cookie = g_u32Cookie;
2188 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
2189 Req.Hdr.cbIn = SUP_IOCTL_MSR_PROBER_SIZE_IN;
2190 Req.Hdr.cbOut = SUP_IOCTL_MSR_PROBER_SIZE_OUT;
2191 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
2192 Req.Hdr.rc = VERR_INTERNAL_ERROR;
2193
2194 Req.u.In.enmOp = SUPMSRPROBEROP_WRITE;
2195 Req.u.In.uMsr = uMsr;
2196 Req.u.In.idCpu = idCpu == NIL_RTCPUID ? UINT32_MAX : idCpu;
2197 Req.u.In.uArgs.Write.uToWrite = uValue;
2198
2199 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_MSR_PROBER, &Req, SUP_IOCTL_MSR_PROBER_SIZE);
2200 if (RT_SUCCESS(rc))
2201 rc = Req.Hdr.rc;
2202 if (RT_SUCCESS(rc) && pfGp)
2203 *pfGp = Req.u.Out.uResults.Write.fGp;
2204
2205 return rc;
2206}
2207
2208
2209SUPR3DECL(int) SUPR3MsrProberModify(uint32_t uMsr, RTCPUID idCpu, uint64_t fAndMask, uint64_t fOrMask,
2210 PSUPMSRPROBERMODIFYRESULT pResult)
2211{
2212 return SUPR3MsrProberModifyEx(uMsr, idCpu, fAndMask, fOrMask, false /*fFaster*/, pResult);
2213}
2214
2215
2216SUPR3DECL(int) SUPR3MsrProberModifyEx(uint32_t uMsr, RTCPUID idCpu, uint64_t fAndMask, uint64_t fOrMask, bool fFaster,
2217 PSUPMSRPROBERMODIFYRESULT pResult)
2218{
2219 SUPMSRPROBER Req;
2220 Req.Hdr.u32Cookie = g_u32Cookie;
2221 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
2222 Req.Hdr.cbIn = SUP_IOCTL_MSR_PROBER_SIZE_IN;
2223 Req.Hdr.cbOut = SUP_IOCTL_MSR_PROBER_SIZE_OUT;
2224 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
2225 Req.Hdr.rc = VERR_INTERNAL_ERROR;
2226
2227 Req.u.In.enmOp = fFaster ? SUPMSRPROBEROP_MODIFY_FASTER : SUPMSRPROBEROP_MODIFY;
2228 Req.u.In.uMsr = uMsr;
2229 Req.u.In.idCpu = idCpu == NIL_RTCPUID ? UINT32_MAX : idCpu;
2230 Req.u.In.uArgs.Modify.fAndMask = fAndMask;
2231 Req.u.In.uArgs.Modify.fOrMask = fOrMask;
2232
2233 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_MSR_PROBER, &Req, SUP_IOCTL_MSR_PROBER_SIZE);
2234 if (RT_SUCCESS(rc))
2235 rc = Req.Hdr.rc;
2236 if (RT_SUCCESS(rc))
2237 *pResult = Req.u.Out.uResults.Modify;
2238
2239 return rc;
2240}
2241
2242
2243SUPR3DECL(int) SUPR3ResumeSuspendedKeyboards(void)
2244{
2245#ifdef RT_OS_DARWIN
2246 /*
2247 * Issue IOCtl to the SUPDRV kernel module.
2248 */
2249 SUPREQHDR Req;
2250 Req.u32Cookie = g_u32Cookie;
2251 Req.u32SessionCookie= g_u32SessionCookie;
2252 Req.cbIn = SUP_IOCTL_RESUME_SUSPENDED_KBDS_SIZE_IN;
2253 Req.cbOut = SUP_IOCTL_RESUME_SUSPENDED_KBDS_SIZE_OUT;
2254 Req.fFlags = SUPREQHDR_FLAGS_DEFAULT;
2255 Req.rc = VERR_INTERNAL_ERROR;
2256 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_RESUME_SUSPENDED_KBDS, &Req, SUP_IOCTL_RESUME_SUSPENDED_KBDS_SIZE);
2257 if (RT_SUCCESS(rc))
2258 rc = Req.rc;
2259 return rc;
2260#else /* !RT_OS_DARWIN */
2261 return VERR_NOT_SUPPORTED;
2262#endif
2263}
2264
2265
2266SUPR3DECL(int) SUPR3TscDeltaMeasure(RTCPUID idCpu, bool fAsync, bool fForce, uint8_t cRetries, uint8_t cMsWaitRetry)
2267{
2268 SUPTSCDELTAMEASURE Req;
2269 Req.Hdr.u32Cookie = g_u32Cookie;
2270 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
2271 Req.Hdr.cbIn = SUP_IOCTL_TSC_DELTA_MEASURE_SIZE_IN;
2272 Req.Hdr.cbOut = SUP_IOCTL_TSC_DELTA_MEASURE_SIZE_OUT;
2273 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
2274 Req.Hdr.rc = VERR_INTERNAL_ERROR;
2275
2276 Req.u.In.cRetries = cRetries;
2277 Req.u.In.fAsync = fAsync;
2278 Req.u.In.fForce = fForce;
2279 Req.u.In.idCpu = idCpu;
2280 Req.u.In.cMsWaitRetry = cMsWaitRetry;
2281
2282 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_TSC_DELTA_MEASURE, &Req, SUP_IOCTL_TSC_DELTA_MEASURE_SIZE);
2283 if (RT_SUCCESS(rc))
2284 rc = Req.Hdr.rc;
2285 return rc;
2286}
2287
2288
2289SUPR3DECL(int) SUPR3ReadTsc(uint64_t *puTsc, uint16_t *pidApic)
2290{
2291 AssertReturn(puTsc, VERR_INVALID_PARAMETER);
2292
2293 SUPTSCREAD Req;
2294 Req.Hdr.u32Cookie = g_u32Cookie;
2295 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
2296 Req.Hdr.cbIn = SUP_IOCTL_TSC_READ_SIZE_IN;
2297 Req.Hdr.cbOut = SUP_IOCTL_TSC_READ_SIZE_OUT;
2298 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
2299 Req.Hdr.rc = VERR_INTERNAL_ERROR;
2300
2301 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_TSC_READ, &Req, SUP_IOCTL_TSC_READ_SIZE);
2302 if (RT_SUCCESS(rc))
2303 {
2304 rc = Req.Hdr.rc;
2305 *puTsc = Req.u.Out.u64AdjustedTsc;
2306 if (pidApic)
2307 *pidApic = Req.u.Out.idApic;
2308 }
2309 return rc;
2310}
2311
2312
2313SUPR3DECL(int) SUPR3GipSetFlags(uint32_t fOrMask, uint32_t fAndMask)
2314{
2315 AssertMsgReturn(!(fOrMask & ~SUPGIP_FLAGS_VALID_MASK),
2316 ("fOrMask=%#x ValidMask=%#x\n", fOrMask, SUPGIP_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
2317 AssertMsgReturn((fAndMask & ~SUPGIP_FLAGS_VALID_MASK) == ~SUPGIP_FLAGS_VALID_MASK,
2318 ("fAndMask=%#x ValidMask=%#x\n", fAndMask, SUPGIP_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
2319
2320 SUPGIPSETFLAGS Req;
2321 Req.Hdr.u32Cookie = g_u32Cookie;
2322 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
2323 Req.Hdr.cbIn = SUP_IOCTL_GIP_SET_FLAGS_SIZE_IN;
2324 Req.Hdr.cbOut = SUP_IOCTL_GIP_SET_FLAGS_SIZE_OUT;
2325 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
2326 Req.Hdr.rc = VERR_INTERNAL_ERROR;
2327
2328 Req.u.In.fAndMask = fAndMask;
2329 Req.u.In.fOrMask = fOrMask;
2330
2331 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_GIP_SET_FLAGS, &Req, SUP_IOCTL_GIP_SET_FLAGS_SIZE);
2332 if (RT_SUCCESS(rc))
2333 rc = Req.Hdr.rc;
2334 return rc;
2335}
2336
2337
2338SUPR3DECL(int) SUPR3GetHwvirtMsrs(PSUPHWVIRTMSRS pHwvirtMsrs, bool fForceRequery)
2339{
2340 AssertReturn(pHwvirtMsrs, VERR_INVALID_PARAMETER);
2341
2342 SUPGETHWVIRTMSRS Req;
2343 Req.Hdr.u32Cookie = g_u32Cookie;
2344 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
2345 Req.Hdr.cbIn = SUP_IOCTL_GET_HWVIRT_MSRS_SIZE_IN;
2346 Req.Hdr.cbOut = SUP_IOCTL_GET_HWVIRT_MSRS_SIZE_OUT;
2347 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
2348 Req.Hdr.rc = VERR_INTERNAL_ERROR;
2349
2350 Req.u.In.fForce = fForceRequery;
2351 Req.u.In.fReserved0 = false;
2352 Req.u.In.fReserved1 = false;
2353 Req.u.In.fReserved2 = false;
2354
2355 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_GET_HWVIRT_MSRS, &Req, SUP_IOCTL_GET_HWVIRT_MSRS_SIZE);
2356 if (RT_SUCCESS(rc))
2357 {
2358 rc = Req.Hdr.rc;
2359 *pHwvirtMsrs = Req.u.Out.HwvirtMsrs;
2360 }
2361 else
2362 RT_ZERO(*pHwvirtMsrs);
2363 return rc;
2364}
2365
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