VirtualBox

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

Last change on this file since 86719 was 85507, checked in by vboxsync, 4 years ago

SUP,*: Some changes to the SUP_IOCTL_LDR_OPEN and SUP_IOCTL_LDR_LOAD interfaces adding memory protection regions for better WX compliance. Preps for linux 5.8 where we'll be using RTR0MemObjAllocPage rather than RTMemExecAlloc for images, switch from relocatable ELF files to shared objects. bugref:9801

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