summaryrefslogtreecommitdiffstats
path: root/src/VBox/HostDrivers/Support/SUPLib.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/HostDrivers/Support/SUPLib.cpp')
-rw-r--r--src/VBox/HostDrivers/Support/SUPLib.cpp2364
1 files changed, 2364 insertions, 0 deletions
diff --git a/src/VBox/HostDrivers/Support/SUPLib.cpp b/src/VBox/HostDrivers/Support/SUPLib.cpp
new file mode 100644
index 00000000..cee26f2a
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/SUPLib.cpp
@@ -0,0 +1,2364 @@
+/* $Id: SUPLib.cpp $ */
+/** @file
+ * VirtualBox Support Library - Common code.
+ */
+
+/*
+ * Copyright (C) 2006-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+/** @page pg_sup SUP - The Support Library
+ *
+ * The support library is responsible for providing facilities to load
+ * VMM Host Ring-0 code, to call Host VMM Ring-0 code from Ring-3 Host
+ * code, to pin down physical memory, and more.
+ *
+ * The VMM Host Ring-0 code can be combined in the support driver if
+ * permitted by kernel module license policies. If it is not combined
+ * it will be externalized in a .r0 module that will be loaded using
+ * the IPRT loader.
+ *
+ * The Ring-0 calling is done thru a generic SUP interface which will
+ * transfer an argument set and call a predefined entry point in the Host
+ * VMM Ring-0 code.
+ *
+ * See @ref grp_sup "SUP - Support APIs" for API details.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_SUP
+#include <VBox/sup.h>
+#include <VBox/err.h>
+#include <VBox/param.h>
+#include <VBox/log.h>
+#include <VBox/VBoxTpG.h>
+
+#include <iprt/assert.h>
+#include <iprt/alloc.h>
+#include <iprt/alloca.h>
+#include <iprt/ldr.h>
+#include <iprt/asm.h>
+#include <iprt/mp.h>
+#include <iprt/cpuset.h>
+#include <iprt/thread.h>
+#include <iprt/process.h>
+#include <iprt/path.h>
+#include <iprt/string.h>
+#include <iprt/env.h>
+#include <iprt/rand.h>
+#include <iprt/x86.h>
+
+#include "SUPDrvIOC.h"
+#include "SUPLibInternal.h"
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/** R0 VMM module name. */
+#define VMMR0_NAME "VMMR0"
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+typedef DECLCALLBACK(int) FNCALLVMMR0(PVMR0 pVMR0, unsigned uOperation, void *pvArg);
+typedef FNCALLVMMR0 *PFNCALLVMMR0;
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/** Init counter. */
+static uint32_t g_cInits = 0;
+/** Whether we've been preinitied. */
+static bool g_fPreInited = false;
+/** The SUPLib instance data.
+ * Well, at least parts of it, specifically the parts that are being handed over
+ * via the pre-init mechanism from the hardened executable stub. */
+SUPLIBDATA g_supLibData =
+{
+ /*.hDevice = */ SUP_HDEVICE_NIL,
+ /*.fUnrestricted = */ true
+#if defined(RT_OS_DARWIN)
+ ,/* .uConnection = */ 0
+#elif defined(RT_OS_LINUX)
+ ,/* .fSysMadviseWorks = */ false
+#endif
+};
+
+/** Pointer to the Global Information Page.
+ *
+ * This pointer is valid as long as SUPLib has a open session. Anyone using
+ * the page must treat this pointer as highly volatile and not trust it beyond
+ * one transaction.
+ *
+ * @todo This will probably deserve it's own session or some other good solution...
+ */
+DECLEXPORT(PSUPGLOBALINFOPAGE) g_pSUPGlobalInfoPage;
+/** Address of the ring-0 mapping of the GIP. */
+PSUPGLOBALINFOPAGE g_pSUPGlobalInfoPageR0;
+/** The physical address of the GIP. */
+static RTHCPHYS g_HCPhysSUPGlobalInfoPage = NIL_RTHCPHYS;
+
+/** The negotiated cookie. */
+uint32_t g_u32Cookie = 0;
+/** The negotiated session cookie. */
+uint32_t g_u32SessionCookie;
+/** Session handle. */
+PSUPDRVSESSION g_pSession;
+/** R0 SUP Functions used for resolving referenced to the SUPR0 module. */
+PSUPQUERYFUNCS g_pSupFunctions;
+
+/** PAGE_ALLOC_EX sans kernel mapping support indicator. */
+static bool g_fSupportsPageAllocNoKernel = true;
+/** Fake mode indicator. (~0 at first, 0 or 1 after first test) */
+uint32_t g_uSupFakeMode = UINT32_MAX;
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+static int supInitFake(PSUPDRVSESSION *ppSession);
+
+
+/** Touch a range of pages. */
+DECLINLINE(void) supR3TouchPages(void *pv, size_t cPages)
+{
+ uint32_t volatile *pu32 = (uint32_t volatile *)pv;
+ while (cPages-- > 0)
+ {
+ ASMAtomicCmpXchgU32(pu32, 0, 0);
+ pu32 += PAGE_SIZE / sizeof(uint32_t);
+ }
+}
+
+
+SUPR3DECL(int) SUPR3Install(void)
+{
+ return suplibOsInstall();
+}
+
+
+SUPR3DECL(int) SUPR3Uninstall(void)
+{
+ return suplibOsUninstall();
+}
+
+
+DECLEXPORT(int) supR3PreInit(PSUPPREINITDATA pPreInitData, uint32_t fFlags)
+{
+ /*
+ * The caller is kind of trustworthy, just perform some basic checks.
+ *
+ * Note! Do not do any fancy stuff here because IPRT has NOT been
+ * initialized at this point.
+ */
+ if (!VALID_PTR(pPreInitData))
+ return VERR_INVALID_POINTER;
+ if (g_fPreInited || g_cInits > 0)
+ return VERR_WRONG_ORDER;
+
+ if ( pPreInitData->u32Magic != SUPPREINITDATA_MAGIC
+ || pPreInitData->u32EndMagic != SUPPREINITDATA_MAGIC)
+ return VERR_INVALID_MAGIC;
+ if ( !(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV)
+ && pPreInitData->Data.hDevice == SUP_HDEVICE_NIL)
+ return VERR_INVALID_HANDLE;
+ if ( (fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV)
+ && pPreInitData->Data.hDevice != SUP_HDEVICE_NIL)
+ return VERR_INVALID_PARAMETER;
+
+ /*
+ * Hand out the data.
+ */
+ int rc = supR3HardenedRecvPreInitData(pPreInitData);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /** @todo This may need some small restructuring later, it doesn't quite work with a root service flag... */
+ if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV))
+ {
+ g_supLibData = pPreInitData->Data;
+ g_fPreInited = true;
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+SUPR3DECL(int) SUPR3InitEx(bool fUnrestricted, PSUPDRVSESSION *ppSession)
+{
+ /*
+ * Perform some sanity checks.
+ * (Got some trouble with compile time member alignment assertions.)
+ */
+ Assert(!(RT_UOFFSETOF(SUPGLOBALINFOPAGE, u64NanoTSLastUpdateHz) & 0x7));
+ Assert(!(RT_UOFFSETOF(SUPGLOBALINFOPAGE, aCPUs) & 0x1f));
+ Assert(!(RT_UOFFSETOF(SUPGLOBALINFOPAGE, aCPUs[1]) & 0x1f));
+ Assert(!(RT_UOFFSETOF(SUPGLOBALINFOPAGE, aCPUs[0].u64NanoTS) & 0x7));
+ Assert(!(RT_UOFFSETOF(SUPGLOBALINFOPAGE, aCPUs[0].u64TSC) & 0x7));
+ Assert(!(RT_UOFFSETOF(SUPGLOBALINFOPAGE, aCPUs[0].u64CpuHz) & 0x7));
+
+ /*
+ * Check if already initialized.
+ */
+ if (ppSession)
+ *ppSession = g_pSession;
+ if (g_cInits++ > 0)
+ {
+ if (fUnrestricted && !g_supLibData.fUnrestricted)
+ {
+ g_cInits--;
+ if (ppSession)
+ *ppSession = NIL_RTR0PTR;
+ return VERR_VM_DRIVER_NOT_ACCESSIBLE; /** @todo different status code? */
+ }
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Check for fake mode.
+ *
+ * Fake mode is used when we're doing smoke testing and debugging.
+ * It's also useful on platforms where we haven't root access or which
+ * we haven't ported the support driver to.
+ */
+ if (g_uSupFakeMode == ~0U)
+ {
+ const char *psz = RTEnvGet("VBOX_SUPLIB_FAKE");
+ if (psz && !strcmp(psz, "fake"))
+ ASMAtomicCmpXchgU32(&g_uSupFakeMode, 1, ~0U);
+ else
+ ASMAtomicCmpXchgU32(&g_uSupFakeMode, 0, ~0U);
+ }
+ if (RT_UNLIKELY(g_uSupFakeMode))
+ return supInitFake(ppSession);
+
+ /*
+ * Open the support driver.
+ */
+ SUPINITOP enmWhat = kSupInitOp_Driver;
+ int rc = suplibOsInit(&g_supLibData, g_fPreInited, fUnrestricted, &enmWhat, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Negotiate the cookie.
+ */
+ SUPCOOKIE CookieReq;
+ memset(&CookieReq, 0xff, sizeof(CookieReq));
+ CookieReq.Hdr.u32Cookie = SUPCOOKIE_INITIAL_COOKIE;
+ CookieReq.Hdr.u32SessionCookie = RTRandU32();
+ CookieReq.Hdr.cbIn = SUP_IOCTL_COOKIE_SIZE_IN;
+ CookieReq.Hdr.cbOut = SUP_IOCTL_COOKIE_SIZE_OUT;
+ CookieReq.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ CookieReq.Hdr.rc = VERR_INTERNAL_ERROR;
+ strcpy(CookieReq.u.In.szMagic, SUPCOOKIE_MAGIC);
+ CookieReq.u.In.u32ReqVersion = SUPDRV_IOC_VERSION;
+ const uint32_t uMinVersion = (SUPDRV_IOC_VERSION & 0xffff0000) == 0x00290000
+ ? 0x00290008
+ : SUPDRV_IOC_VERSION & 0xffff0000;
+ CookieReq.u.In.u32MinVersion = uMinVersion;
+ rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_COOKIE, &CookieReq, SUP_IOCTL_COOKIE_SIZE);
+ if ( RT_SUCCESS(rc)
+ && RT_SUCCESS(CookieReq.Hdr.rc))
+ {
+ if ( (CookieReq.u.Out.u32SessionVersion & 0xffff0000) == (SUPDRV_IOC_VERSION & 0xffff0000)
+ && CookieReq.u.Out.u32SessionVersion >= uMinVersion)
+ {
+ /*
+ * Query the functions.
+ */
+ PSUPQUERYFUNCS pFuncsReq = NULL;
+ if (g_supLibData.fUnrestricted)
+ {
+ pFuncsReq = (PSUPQUERYFUNCS)RTMemAllocZ(SUP_IOCTL_QUERY_FUNCS_SIZE(CookieReq.u.Out.cFunctions));
+ if (pFuncsReq)
+ {
+ pFuncsReq->Hdr.u32Cookie = CookieReq.u.Out.u32Cookie;
+ pFuncsReq->Hdr.u32SessionCookie = CookieReq.u.Out.u32SessionCookie;
+ pFuncsReq->Hdr.cbIn = SUP_IOCTL_QUERY_FUNCS_SIZE_IN;
+ pFuncsReq->Hdr.cbOut = SUP_IOCTL_QUERY_FUNCS_SIZE_OUT(CookieReq.u.Out.cFunctions);
+ pFuncsReq->Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ pFuncsReq->Hdr.rc = VERR_INTERNAL_ERROR;
+ rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_QUERY_FUNCS(CookieReq.u.Out.cFunctions), pFuncsReq,
+ SUP_IOCTL_QUERY_FUNCS_SIZE(CookieReq.u.Out.cFunctions));
+ if (RT_SUCCESS(rc))
+ rc = pFuncsReq->Hdr.rc;
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Map the GIP into userspace.
+ */
+ Assert(!g_pSUPGlobalInfoPage);
+ SUPGIPMAP GipMapReq;
+ GipMapReq.Hdr.u32Cookie = CookieReq.u.Out.u32Cookie;
+ GipMapReq.Hdr.u32SessionCookie = CookieReq.u.Out.u32SessionCookie;
+ GipMapReq.Hdr.cbIn = SUP_IOCTL_GIP_MAP_SIZE_IN;
+ GipMapReq.Hdr.cbOut = SUP_IOCTL_GIP_MAP_SIZE_OUT;
+ GipMapReq.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ GipMapReq.Hdr.rc = VERR_INTERNAL_ERROR;
+ GipMapReq.u.Out.HCPhysGip = NIL_RTHCPHYS;
+ GipMapReq.u.Out.pGipR0 = NIL_RTR0PTR;
+ GipMapReq.u.Out.pGipR3 = NULL;
+ rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_GIP_MAP, &GipMapReq, SUP_IOCTL_GIP_MAP_SIZE);
+ if (RT_SUCCESS(rc))
+ rc = GipMapReq.Hdr.rc;
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Set the GIP globals.
+ */
+ AssertRelease(GipMapReq.u.Out.pGipR3->u32Magic == SUPGLOBALINFOPAGE_MAGIC);
+ AssertRelease(GipMapReq.u.Out.pGipR3->u32Version >= SUPGLOBALINFOPAGE_VERSION);
+
+ ASMAtomicXchgSize(&g_HCPhysSUPGlobalInfoPage, GipMapReq.u.Out.HCPhysGip);
+ ASMAtomicCmpXchgPtr((void * volatile *)&g_pSUPGlobalInfoPage, GipMapReq.u.Out.pGipR3, NULL);
+ ASMAtomicCmpXchgPtr((void * volatile *)&g_pSUPGlobalInfoPageR0, (void *)GipMapReq.u.Out.pGipR0, NULL);
+ }
+ }
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Set the globals and return success.
+ */
+ g_u32Cookie = CookieReq.u.Out.u32Cookie;
+ g_u32SessionCookie = CookieReq.u.Out.u32SessionCookie;
+ g_pSession = CookieReq.u.Out.pSession;
+ g_pSupFunctions = pFuncsReq;
+ if (ppSession)
+ *ppSession = CookieReq.u.Out.pSession;
+ return VINF_SUCCESS;
+ }
+
+ /* bailout */
+ RTMemFree(pFuncsReq);
+ }
+ else
+ {
+ LogRel(("Support driver version mismatch: SessionVersion=%#x DriverVersion=%#x ClientVersion=%#x MinVersion=%#x\n",
+ CookieReq.u.Out.u32SessionVersion, CookieReq.u.Out.u32DriverVersion, SUPDRV_IOC_VERSION, uMinVersion));
+ rc = VERR_VM_DRIVER_VERSION_MISMATCH;
+ }
+ }
+ else
+ {
+ if (RT_SUCCESS(rc))
+ {
+ rc = CookieReq.Hdr.rc;
+ LogRel(("Support driver version mismatch: DriverVersion=%#x ClientVersion=%#x rc=%Rrc\n",
+ CookieReq.u.Out.u32DriverVersion, SUPDRV_IOC_VERSION, rc));
+ if (rc != VERR_VM_DRIVER_VERSION_MISMATCH)
+ rc = VERR_VM_DRIVER_VERSION_MISMATCH;
+ }
+ else
+ {
+ /* for pre 0x00060000 drivers */
+ LogRel(("Support driver version mismatch: DriverVersion=too-old ClientVersion=%#x\n", SUPDRV_IOC_VERSION));
+ rc = VERR_VM_DRIVER_VERSION_MISMATCH;
+ }
+ }
+
+ suplibOsTerm(&g_supLibData);
+ }
+ g_cInits--;
+
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPR3Init(PSUPDRVSESSION *ppSession)
+{
+ return SUPR3InitEx(true, ppSession);
+}
+
+/**
+ * Fake mode init.
+ */
+static int supInitFake(PSUPDRVSESSION *ppSession)
+{
+ Log(("SUP: Fake mode!\n"));
+ static const SUPFUNC s_aFakeFunctions[] =
+ {
+ /* name function */
+ { "SUPR0AbsIs64bit", 0 },
+ { "SUPR0Abs64bitKernelCS", 0 },
+ { "SUPR0Abs64bitKernelSS", 0 },
+ { "SUPR0Abs64bitKernelDS", 0 },
+ { "SUPR0AbsKernelCS", 8 },
+ { "SUPR0AbsKernelSS", 16 },
+ { "SUPR0AbsKernelDS", 16 },
+ { "SUPR0AbsKernelES", 16 },
+ { "SUPR0AbsKernelFS", 24 },
+ { "SUPR0AbsKernelGS", 32 },
+ { "SUPR0ComponentRegisterFactory", 0xefeefffd },
+ { "SUPR0ComponentDeregisterFactory", 0xefeefffe },
+ { "SUPR0ComponentQueryFactory", 0xefeeffff },
+ { "SUPR0ObjRegister", 0xefef0000 },
+ { "SUPR0ObjAddRef", 0xefef0001 },
+ { "SUPR0ObjAddRefEx", 0xefef0001 },
+ { "SUPR0ObjRelease", 0xefef0002 },
+ { "SUPR0ObjVerifyAccess", 0xefef0003 },
+ { "SUPR0LockMem", 0xefef0004 },
+ { "SUPR0UnlockMem", 0xefef0005 },
+ { "SUPR0ContAlloc", 0xefef0006 },
+ { "SUPR0ContFree", 0xefef0007 },
+ { "SUPR0MemAlloc", 0xefef0008 },
+ { "SUPR0MemGetPhys", 0xefef0009 },
+ { "SUPR0MemFree", 0xefef000a },
+ { "SUPR0Printf", 0xefef000b },
+ { "SUPR0GetPagingMode", 0xefef000c },
+ { "SUPR0EnableVTx", 0xefef000e },
+ { "RTMemAlloc", 0xefef000f },
+ { "RTMemAllocZ", 0xefef0010 },
+ { "RTMemFree", 0xefef0011 },
+ { "RTR0MemObjAddress", 0xefef0012 },
+ { "RTR0MemObjAddressR3", 0xefef0013 },
+ { "RTR0MemObjAllocPage", 0xefef0014 },
+ { "RTR0MemObjAllocPhysNC", 0xefef0015 },
+ { "RTR0MemObjAllocLow", 0xefef0016 },
+ { "RTR0MemObjEnterPhys", 0xefef0017 },
+ { "RTR0MemObjFree", 0xefef0018 },
+ { "RTR0MemObjGetPagePhysAddr", 0xefef0019 },
+ { "RTR0MemObjMapUser", 0xefef001a },
+ { "RTR0MemObjMapKernel", 0xefef001b },
+ { "RTR0MemObjMapKernelEx", 0xefef001c },
+ { "RTMpGetArraySize", 0xefef001c },
+ { "RTProcSelf", 0xefef001d },
+ { "RTR0ProcHandleSelf", 0xefef001e },
+ { "RTSemEventCreate", 0xefef001f },
+ { "RTSemEventSignal", 0xefef0020 },
+ { "RTSemEventWait", 0xefef0021 },
+ { "RTSemEventWaitNoResume", 0xefef0022 },
+ { "RTSemEventDestroy", 0xefef0023 },
+ { "RTSemEventMultiCreate", 0xefef0024 },
+ { "RTSemEventMultiSignal", 0xefef0025 },
+ { "RTSemEventMultiReset", 0xefef0026 },
+ { "RTSemEventMultiWait", 0xefef0027 },
+ { "RTSemEventMultiWaitNoResume", 0xefef0028 },
+ { "RTSemEventMultiDestroy", 0xefef0029 },
+ { "RTSemFastMutexCreate", 0xefef002a },
+ { "RTSemFastMutexDestroy", 0xefef002b },
+ { "RTSemFastMutexRequest", 0xefef002c },
+ { "RTSemFastMutexRelease", 0xefef002d },
+ { "RTSpinlockCreate", 0xefef002e },
+ { "RTSpinlockDestroy", 0xefef002f },
+ { "RTSpinlockAcquire", 0xefef0030 },
+ { "RTSpinlockRelease", 0xefef0031 },
+ { "RTSpinlockAcquireNoInts", 0xefef0032 },
+ { "RTTimeNanoTS", 0xefef0034 },
+ { "RTTimeMillieTS", 0xefef0035 },
+ { "RTTimeSystemNanoTS", 0xefef0036 },
+ { "RTTimeSystemMillieTS", 0xefef0037 },
+ { "RTThreadNativeSelf", 0xefef0038 },
+ { "RTThreadSleep", 0xefef0039 },
+ { "RTThreadYield", 0xefef003a },
+ { "RTTimerCreate", 0xefef003a },
+ { "RTTimerCreateEx", 0xefef003a },
+ { "RTTimerDestroy", 0xefef003a },
+ { "RTTimerStart", 0xefef003a },
+ { "RTTimerStop", 0xefef003a },
+ { "RTTimerChangeInterval", 0xefef003a },
+ { "RTTimerGetSystemGranularity", 0xefef003a },
+ { "RTTimerRequestSystemGranularity", 0xefef003a },
+ { "RTTimerReleaseSystemGranularity", 0xefef003a },
+ { "RTTimerCanDoHighResolution", 0xefef003a },
+ { "RTLogDefaultInstance", 0xefef003b },
+ { "RTLogRelGetDefaultInstance", 0xefef003c },
+ { "RTLogSetDefaultInstanceThread", 0xefef003d },
+ { "RTLogLogger", 0xefef003e },
+ { "RTLogLoggerEx", 0xefef003f },
+ { "RTLogLoggerExV", 0xefef0040 },
+ { "RTAssertMsg1", 0xefef0041 },
+ { "RTAssertMsg2", 0xefef0042 },
+ { "RTAssertMsg2V", 0xefef0043 },
+ { "SUPR0QueryVTCaps", 0xefef0044 },
+ };
+
+ /* fake r0 functions. */
+ g_pSupFunctions = (PSUPQUERYFUNCS)RTMemAllocZ(SUP_IOCTL_QUERY_FUNCS_SIZE(RT_ELEMENTS(s_aFakeFunctions)));
+ if (g_pSupFunctions)
+ {
+ g_pSupFunctions->u.Out.cFunctions = RT_ELEMENTS(s_aFakeFunctions);
+ memcpy(&g_pSupFunctions->u.Out.aFunctions[0], &s_aFakeFunctions[0], sizeof(s_aFakeFunctions));
+ g_pSession = (PSUPDRVSESSION)(void *)g_pSupFunctions;
+ if (ppSession)
+ *ppSession = g_pSession;
+
+ /* fake the GIP. */
+ g_pSUPGlobalInfoPage = (PSUPGLOBALINFOPAGE)RTMemPageAllocZ(PAGE_SIZE);
+ if (g_pSUPGlobalInfoPage)
+ {
+ g_pSUPGlobalInfoPageR0 = g_pSUPGlobalInfoPage;
+ g_HCPhysSUPGlobalInfoPage = NIL_RTHCPHYS & ~(RTHCPHYS)PAGE_OFFSET_MASK;
+ /* the page is supposed to be invalid, so don't set the magic. */
+ return VINF_SUCCESS;
+ }
+
+ RTMemFree(g_pSupFunctions);
+ g_pSupFunctions = NULL;
+ }
+ return VERR_NO_MEMORY;
+}
+
+
+SUPR3DECL(int) SUPR3Term(bool fForced)
+{
+ /*
+ * Verify state.
+ */
+ AssertMsg(g_cInits > 0, ("SUPR3Term() is called before SUPR3Init()!\n"));
+ if (g_cInits == 0)
+ return VERR_WRONG_ORDER;
+ if (g_cInits == 1 || fForced)
+ {
+ /*
+ * NULL the GIP pointer.
+ */
+ if (g_pSUPGlobalInfoPage)
+ {
+ ASMAtomicWriteNullPtr((void * volatile *)&g_pSUPGlobalInfoPage);
+ ASMAtomicWriteNullPtr((void * volatile *)&g_pSUPGlobalInfoPageR0);
+ ASMAtomicWriteU64(&g_HCPhysSUPGlobalInfoPage, NIL_RTHCPHYS);
+ /* just a little safe guard against threads using the page. */
+ RTThreadSleep(50);
+ }
+
+ /*
+ * Close the support driver.
+ */
+ int rc = suplibOsTerm(&g_supLibData);
+ if (rc)
+ return rc;
+
+ g_u32Cookie = 0;
+ g_u32SessionCookie = 0;
+ g_cInits = 0;
+ }
+ else
+ g_cInits--;
+
+ return 0;
+}
+
+
+SUPR3DECL(SUPPAGINGMODE) SUPR3GetPagingMode(void)
+{
+ /* fake */
+ if (RT_UNLIKELY(g_uSupFakeMode))
+#ifdef RT_ARCH_AMD64
+ return SUPPAGINGMODE_AMD64_GLOBAL_NX;
+#else
+ return SUPPAGINGMODE_32_BIT_GLOBAL;
+#endif
+
+ /*
+ * Issue IOCtl to the SUPDRV kernel module.
+ */
+ SUPGETPAGINGMODE Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_GET_PAGING_MODE_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_GET_PAGING_MODE_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_GET_PAGING_MODE, &Req, SUP_IOCTL_GET_PAGING_MODE_SIZE);
+ if ( RT_FAILURE(rc)
+ || RT_FAILURE(Req.Hdr.rc))
+ {
+ LogRel(("SUPR3GetPagingMode: %Rrc %Rrc\n", rc, Req.Hdr.rc));
+ Req.u.Out.enmMode = SUPPAGINGMODE_INVALID;
+ }
+
+ return Req.u.Out.enmMode;
+}
+
+
+/**
+ * For later.
+ */
+static int supCallVMMR0ExFake(PVMR0 pVMR0, unsigned uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
+{
+ AssertMsgFailed(("%d\n", uOperation)); NOREF(pVMR0); NOREF(uOperation); NOREF(u64Arg); NOREF(pReqHdr);
+ return VERR_NOT_SUPPORTED;
+}
+
+
+SUPR3DECL(int) SUPR3CallVMMR0Fast(PVMR0 pVMR0, unsigned uOperation, VMCPUID idCpu)
+{
+ NOREF(pVMR0);
+ static const uintptr_t s_auFunctions[4] =
+ {
+ SUP_IOCTL_FAST_DO_RAW_RUN,
+ SUP_IOCTL_FAST_DO_HM_RUN,
+ SUP_IOCTL_FAST_DO_NOP,
+ SUP_IOCTL_FAST_DO_NEM_RUN
+ };
+ AssertCompile(SUP_VMMR0_DO_RAW_RUN == 0);
+ AssertCompile(SUP_VMMR0_DO_HM_RUN == 1);
+ AssertCompile(SUP_VMMR0_DO_NOP == 2);
+ AssertCompile(SUP_VMMR0_DO_NEM_RUN == 3);
+ AssertMsgReturn(uOperation < RT_ELEMENTS(s_auFunctions), ("%#x\n", uOperation), VERR_INTERNAL_ERROR);
+ return suplibOsIOCtlFast(&g_supLibData, s_auFunctions[uOperation], idCpu);
+}
+
+
+SUPR3DECL(int) SUPR3CallVMMR0Ex(PVMR0 pVMR0, VMCPUID idCpu, unsigned uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
+{
+ /*
+ * The following operations don't belong here.
+ */
+ AssertMsgReturn( uOperation != SUP_VMMR0_DO_RAW_RUN
+ && uOperation != SUP_VMMR0_DO_HM_RUN
+ && uOperation != SUP_VMMR0_DO_NOP,
+ ("%#x\n", uOperation),
+ VERR_INTERNAL_ERROR);
+
+ /* fake */
+ if (RT_UNLIKELY(g_uSupFakeMode))
+ return supCallVMMR0ExFake(pVMR0, uOperation, u64Arg, pReqHdr);
+
+ int rc;
+ if (!pReqHdr)
+ {
+ /* no data. */
+ SUPCALLVMMR0 Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_CALL_VMMR0_SIZE_IN(0);
+ Req.Hdr.cbOut = SUP_IOCTL_CALL_VMMR0_SIZE_OUT(0);
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ Req.u.In.pVMR0 = pVMR0;
+ Req.u.In.idCpu = idCpu;
+ Req.u.In.uOperation = uOperation;
+ Req.u.In.u64Arg = u64Arg;
+ rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_VMMR0(0), &Req, SUP_IOCTL_CALL_VMMR0_SIZE(0));
+ if (RT_SUCCESS(rc))
+ rc = Req.Hdr.rc;
+ }
+ else if (SUP_IOCTL_CALL_VMMR0_SIZE(pReqHdr->cbReq) < _4K) /* FreeBSD won't copy more than 4K. */
+ {
+ AssertPtrReturn(pReqHdr, VERR_INVALID_POINTER);
+ AssertReturn(pReqHdr->u32Magic == SUPVMMR0REQHDR_MAGIC, VERR_INVALID_MAGIC);
+ const size_t cbReq = pReqHdr->cbReq;
+
+ PSUPCALLVMMR0 pReq = (PSUPCALLVMMR0)alloca(SUP_IOCTL_CALL_VMMR0_SIZE(cbReq));
+ pReq->Hdr.u32Cookie = g_u32Cookie;
+ pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
+ pReq->Hdr.cbIn = SUP_IOCTL_CALL_VMMR0_SIZE_IN(cbReq);
+ pReq->Hdr.cbOut = SUP_IOCTL_CALL_VMMR0_SIZE_OUT(cbReq);
+ pReq->Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ pReq->Hdr.rc = VERR_INTERNAL_ERROR;
+ pReq->u.In.pVMR0 = pVMR0;
+ pReq->u.In.idCpu = idCpu;
+ pReq->u.In.uOperation = uOperation;
+ pReq->u.In.u64Arg = u64Arg;
+ memcpy(&pReq->abReqPkt[0], pReqHdr, cbReq);
+ rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_VMMR0(cbReq), pReq, SUP_IOCTL_CALL_VMMR0_SIZE(cbReq));
+ if (RT_SUCCESS(rc))
+ rc = pReq->Hdr.rc;
+ memcpy(pReqHdr, &pReq->abReqPkt[0], cbReq);
+ }
+ else if (pReqHdr->cbReq <= _512K)
+ {
+ AssertPtrReturn(pReqHdr, VERR_INVALID_POINTER);
+ AssertReturn(pReqHdr->u32Magic == SUPVMMR0REQHDR_MAGIC, VERR_INVALID_MAGIC);
+ const size_t cbReq = pReqHdr->cbReq;
+
+ PSUPCALLVMMR0 pReq = (PSUPCALLVMMR0)RTMemTmpAlloc(SUP_IOCTL_CALL_VMMR0_BIG_SIZE(cbReq));
+ pReq->Hdr.u32Cookie = g_u32Cookie;
+ pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
+ pReq->Hdr.cbIn = SUP_IOCTL_CALL_VMMR0_BIG_SIZE_IN(cbReq);
+ pReq->Hdr.cbOut = SUP_IOCTL_CALL_VMMR0_BIG_SIZE_OUT(cbReq);
+ pReq->Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ pReq->Hdr.rc = VERR_INTERNAL_ERROR;
+ pReq->u.In.pVMR0 = pVMR0;
+ pReq->u.In.idCpu = idCpu;
+ pReq->u.In.uOperation = uOperation;
+ pReq->u.In.u64Arg = u64Arg;
+ memcpy(&pReq->abReqPkt[0], pReqHdr, cbReq);
+ rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_VMMR0_BIG, pReq, SUP_IOCTL_CALL_VMMR0_BIG_SIZE(cbReq));
+ if (RT_SUCCESS(rc))
+ rc = pReq->Hdr.rc;
+ memcpy(pReqHdr, &pReq->abReqPkt[0], cbReq);
+ RTMemTmpFree(pReq);
+ }
+ else
+ AssertMsgFailedReturn(("cbReq=%#x\n", pReqHdr->cbReq), VERR_OUT_OF_RANGE);
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPR3CallVMMR0(PVMR0 pVMR0, VMCPUID idCpu, unsigned uOperation, void *pvArg)
+{
+ /*
+ * The following operations don't belong here.
+ */
+ AssertMsgReturn( uOperation != SUP_VMMR0_DO_RAW_RUN
+ && uOperation != SUP_VMMR0_DO_HM_RUN
+ && uOperation != SUP_VMMR0_DO_NOP,
+ ("%#x\n", uOperation),
+ VERR_INTERNAL_ERROR);
+ return SUPR3CallVMMR0Ex(pVMR0, idCpu, uOperation, (uintptr_t)pvArg, NULL);
+}
+
+
+SUPR3DECL(int) SUPR3SetVMForFastIOCtl(PVMR0 pVMR0)
+{
+ if (RT_UNLIKELY(g_uSupFakeMode))
+ return VINF_SUCCESS;
+
+ SUPSETVMFORFAST Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_SET_VM_FOR_FAST_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_SET_VM_FOR_FAST_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ Req.u.In.pVMR0 = pVMR0;
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_SET_VM_FOR_FAST, &Req, SUP_IOCTL_SET_VM_FOR_FAST_SIZE);
+ if (RT_SUCCESS(rc))
+ rc = Req.Hdr.rc;
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPR3CallR0Service(const char *pszService, size_t cchService, uint32_t uOperation, uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr)
+{
+ AssertReturn(cchService < RT_SIZEOFMEMB(SUPCALLSERVICE, u.In.szName), VERR_INVALID_PARAMETER);
+ Assert(strlen(pszService) == cchService);
+
+ /* fake */
+ if (RT_UNLIKELY(g_uSupFakeMode))
+ return VERR_NOT_SUPPORTED;
+
+ int rc;
+ if (!pReqHdr)
+ {
+ /* no data. */
+ SUPCALLSERVICE Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_CALL_SERVICE_SIZE_IN(0);
+ Req.Hdr.cbOut = SUP_IOCTL_CALL_SERVICE_SIZE_OUT(0);
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ memcpy(Req.u.In.szName, pszService, cchService);
+ Req.u.In.szName[cchService] = '\0';
+ Req.u.In.uOperation = uOperation;
+ Req.u.In.u64Arg = u64Arg;
+ rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_SERVICE(0), &Req, SUP_IOCTL_CALL_SERVICE_SIZE(0));
+ if (RT_SUCCESS(rc))
+ rc = Req.Hdr.rc;
+ }
+ else if (SUP_IOCTL_CALL_SERVICE_SIZE(pReqHdr->cbReq) < _4K) /* FreeBSD won't copy more than 4K. */
+ {
+ AssertPtrReturn(pReqHdr, VERR_INVALID_POINTER);
+ AssertReturn(pReqHdr->u32Magic == SUPR0SERVICEREQHDR_MAGIC, VERR_INVALID_MAGIC);
+ const size_t cbReq = pReqHdr->cbReq;
+
+ PSUPCALLSERVICE pReq = (PSUPCALLSERVICE)alloca(SUP_IOCTL_CALL_SERVICE_SIZE(cbReq));
+ pReq->Hdr.u32Cookie = g_u32Cookie;
+ pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
+ pReq->Hdr.cbIn = SUP_IOCTL_CALL_SERVICE_SIZE_IN(cbReq);
+ pReq->Hdr.cbOut = SUP_IOCTL_CALL_SERVICE_SIZE_OUT(cbReq);
+ pReq->Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ pReq->Hdr.rc = VERR_INTERNAL_ERROR;
+ memcpy(pReq->u.In.szName, pszService, cchService);
+ pReq->u.In.szName[cchService] = '\0';
+ pReq->u.In.uOperation = uOperation;
+ pReq->u.In.u64Arg = u64Arg;
+ memcpy(&pReq->abReqPkt[0], pReqHdr, cbReq);
+ rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_SERVICE(cbReq), pReq, SUP_IOCTL_CALL_SERVICE_SIZE(cbReq));
+ if (RT_SUCCESS(rc))
+ rc = pReq->Hdr.rc;
+ memcpy(pReqHdr, &pReq->abReqPkt[0], cbReq);
+ }
+ else /** @todo may have to remove the size limits one this request... */
+ AssertMsgFailedReturn(("cbReq=%#x\n", pReqHdr->cbReq), VERR_INTERNAL_ERROR);
+ return rc;
+}
+
+
+/**
+ * Worker for the SUPR3Logger* APIs.
+ *
+ * @returns VBox status code.
+ * @param enmWhich Which logger.
+ * @param fWhat What to do with the logger.
+ * @param pszFlags The flags settings.
+ * @param pszGroups The groups settings.
+ * @param pszDest The destination specificier.
+ */
+static int supR3LoggerSettings(SUPLOGGER enmWhich, uint32_t fWhat, const char *pszFlags, const char *pszGroups, const char *pszDest)
+{
+ uint32_t const cchFlags = pszFlags ? (uint32_t)strlen(pszFlags) : 0;
+ uint32_t const cchGroups = pszGroups ? (uint32_t)strlen(pszGroups) : 0;
+ uint32_t const cchDest = pszDest ? (uint32_t)strlen(pszDest) : 0;
+ uint32_t const cbStrTab = cchFlags + !!cchFlags
+ + cchGroups + !!cchGroups
+ + cchDest + !!cchDest
+ + (!cchFlags && !cchGroups && !cchDest);
+
+ PSUPLOGGERSETTINGS pReq = (PSUPLOGGERSETTINGS)alloca(SUP_IOCTL_LOGGER_SETTINGS_SIZE(cbStrTab));
+ pReq->Hdr.u32Cookie = g_u32Cookie;
+ pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
+ pReq->Hdr.cbIn = SUP_IOCTL_LOGGER_SETTINGS_SIZE_IN(cbStrTab);
+ pReq->Hdr.cbOut = SUP_IOCTL_LOGGER_SETTINGS_SIZE_OUT;
+ pReq->Hdr.fFlags= SUPREQHDR_FLAGS_DEFAULT;
+ pReq->Hdr.rc = VERR_INTERNAL_ERROR;
+ switch (enmWhich)
+ {
+ case SUPLOGGER_DEBUG: pReq->u.In.fWhich = SUPLOGGERSETTINGS_WHICH_DEBUG; break;
+ case SUPLOGGER_RELEASE: pReq->u.In.fWhich = SUPLOGGERSETTINGS_WHICH_RELEASE; break;
+ default:
+ return VERR_INVALID_PARAMETER;
+ }
+ pReq->u.In.fWhat = fWhat;
+
+ uint32_t off = 0;
+ if (cchFlags)
+ {
+ pReq->u.In.offFlags = off;
+ memcpy(&pReq->u.In.szStrings[off], pszFlags, cchFlags + 1);
+ off += cchFlags + 1;
+ }
+ else
+ pReq->u.In.offFlags = cbStrTab - 1;
+
+ if (cchGroups)
+ {
+ pReq->u.In.offGroups = off;
+ memcpy(&pReq->u.In.szStrings[off], pszGroups, cchGroups + 1);
+ off += cchGroups + 1;
+ }
+ else
+ pReq->u.In.offGroups = cbStrTab - 1;
+
+ if (cchDest)
+ {
+ pReq->u.In.offDestination = off;
+ memcpy(&pReq->u.In.szStrings[off], pszDest, cchDest + 1);
+ off += cchDest + 1;
+ }
+ else
+ pReq->u.In.offDestination = cbStrTab - 1;
+
+ if (!off)
+ {
+ pReq->u.In.szStrings[0] = '\0';
+ off++;
+ }
+ Assert(off == cbStrTab);
+ Assert(pReq->u.In.szStrings[cbStrTab - 1] == '\0');
+
+
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LOGGER_SETTINGS(cbStrTab), pReq, SUP_IOCTL_LOGGER_SETTINGS_SIZE(cbStrTab));
+ if (RT_SUCCESS(rc))
+ rc = pReq->Hdr.rc;
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPR3LoggerSettings(SUPLOGGER enmWhich, const char *pszFlags, const char *pszGroups, const char *pszDest)
+{
+ return supR3LoggerSettings(enmWhich, SUPLOGGERSETTINGS_WHAT_SETTINGS, pszFlags, pszGroups, pszDest);
+}
+
+
+SUPR3DECL(int) SUPR3LoggerCreate(SUPLOGGER enmWhich, const char *pszFlags, const char *pszGroups, const char *pszDest)
+{
+ return supR3LoggerSettings(enmWhich, SUPLOGGERSETTINGS_WHAT_CREATE, pszFlags, pszGroups, pszDest);
+}
+
+
+SUPR3DECL(int) SUPR3LoggerDestroy(SUPLOGGER enmWhich)
+{
+ return supR3LoggerSettings(enmWhich, SUPLOGGERSETTINGS_WHAT_DESTROY, NULL, NULL, NULL);
+}
+
+
+SUPR3DECL(int) SUPR3PageAlloc(size_t cPages, void **ppvPages)
+{
+ /*
+ * Validate.
+ */
+ AssertPtrReturn(ppvPages, VERR_INVALID_POINTER);
+ *ppvPages = NULL;
+ AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
+
+ /*
+ * Call OS specific worker.
+ */
+ return suplibOsPageAlloc(&g_supLibData, cPages, ppvPages);
+}
+
+
+SUPR3DECL(int) SUPR3PageFree(void *pvPages, size_t cPages)
+{
+ /*
+ * Validate.
+ */
+ AssertPtrReturn(pvPages, VERR_INVALID_POINTER);
+ AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
+
+ /*
+ * Call OS specific worker.
+ */
+ return suplibOsPageFree(&g_supLibData, pvPages, cPages);
+}
+
+
+/**
+ * Locks down the physical memory backing a virtual memory
+ * range in the current process.
+ *
+ * @returns VBox status code.
+ * @param pvStart Start of virtual memory range.
+ * Must be page aligned.
+ * @param cPages Number of pages.
+ * @param paPages Where to store the physical page addresses returned.
+ * On entry this will point to an array of with cbMemory >> PAGE_SHIFT entries.
+ */
+SUPR3DECL(int) supR3PageLock(void *pvStart, size_t cPages, PSUPPAGE paPages)
+{
+ /*
+ * Validate.
+ */
+ AssertPtr(pvStart);
+ AssertMsg(RT_ALIGN_P(pvStart, PAGE_SIZE) == pvStart, ("pvStart (%p) must be page aligned\n", pvStart));
+ AssertPtr(paPages);
+
+ /* fake */
+ if (RT_UNLIKELY(g_uSupFakeMode))
+ {
+ RTHCPHYS Phys = (uintptr_t)pvStart + PAGE_SIZE * 1024;
+ size_t iPage = cPages;
+ while (iPage-- > 0)
+ paPages[iPage].Phys = Phys + (iPage << PAGE_SHIFT);
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Issue IOCtl to the SUPDRV kernel module.
+ */
+ int rc;
+ PSUPPAGELOCK pReq = (PSUPPAGELOCK)RTMemTmpAllocZ(SUP_IOCTL_PAGE_LOCK_SIZE(cPages));
+ if (RT_LIKELY(pReq))
+ {
+ pReq->Hdr.u32Cookie = g_u32Cookie;
+ pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
+ pReq->Hdr.cbIn = SUP_IOCTL_PAGE_LOCK_SIZE_IN;
+ pReq->Hdr.cbOut = SUP_IOCTL_PAGE_LOCK_SIZE_OUT(cPages);
+ pReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_OUT;
+ pReq->Hdr.rc = VERR_INTERNAL_ERROR;
+ pReq->u.In.pvR3 = pvStart;
+ pReq->u.In.cPages = (uint32_t)cPages; AssertRelease(pReq->u.In.cPages == cPages);
+ rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_LOCK, pReq, SUP_IOCTL_PAGE_LOCK_SIZE(cPages));
+ if (RT_SUCCESS(rc))
+ rc = pReq->Hdr.rc;
+ if (RT_SUCCESS(rc))
+ {
+ for (uint32_t iPage = 0; iPage < cPages; iPage++)
+ {
+ paPages[iPage].uReserved = 0;
+ paPages[iPage].Phys = pReq->u.Out.aPages[iPage];
+ Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
+ }
+ }
+ RTMemTmpFree(pReq);
+ }
+ else
+ rc = VERR_NO_TMP_MEMORY;
+
+ return rc;
+}
+
+
+/**
+ * Releases locked down pages.
+ *
+ * @returns VBox status code.
+ * @param pvStart Start of virtual memory range previously locked
+ * down by SUPPageLock().
+ */
+SUPR3DECL(int) supR3PageUnlock(void *pvStart)
+{
+ /*
+ * Validate.
+ */
+ AssertPtr(pvStart);
+ AssertMsg(RT_ALIGN_P(pvStart, PAGE_SIZE) == pvStart, ("pvStart (%p) must be page aligned\n", pvStart));
+
+ /* fake */
+ if (RT_UNLIKELY(g_uSupFakeMode))
+ return VINF_SUCCESS;
+
+ /*
+ * Issue IOCtl to the SUPDRV kernel module.
+ */
+ SUPPAGEUNLOCK Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_PAGE_UNLOCK_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_PAGE_UNLOCK_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ Req.u.In.pvR3 = pvStart;
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_UNLOCK, &Req, SUP_IOCTL_PAGE_UNLOCK_SIZE);
+ if (RT_SUCCESS(rc))
+ rc = Req.Hdr.rc;
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPR3LockDownLoader(PRTERRINFO pErrInfo)
+{
+ /* fake */
+ if (RT_UNLIKELY(g_uSupFakeMode))
+ return VINF_SUCCESS;
+
+ /*
+ * Lock down the module loader interface.
+ */
+ SUPREQHDR ReqHdr;
+ ReqHdr.u32Cookie = g_u32Cookie;
+ ReqHdr.u32SessionCookie = g_u32SessionCookie;
+ ReqHdr.cbIn = SUP_IOCTL_LDR_LOCK_DOWN_SIZE_IN;
+ ReqHdr.cbOut = SUP_IOCTL_LDR_LOCK_DOWN_SIZE_OUT;
+ ReqHdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ ReqHdr.rc = VERR_INTERNAL_ERROR;
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_LOCK_DOWN, &ReqHdr, SUP_IOCTL_LDR_LOCK_DOWN_SIZE);
+ if (RT_FAILURE(rc))
+ return RTErrInfoSetF(pErrInfo, rc,
+ "SUPR3LockDownLoader: SUP_IOCTL_LDR_LOCK_DOWN ioctl returned %Rrc", rc);
+
+ return ReqHdr.rc;
+}
+
+
+/**
+ * Fallback for SUPR3PageAllocEx on systems where RTR0MemObjPhysAllocNC isn't
+ * supported.
+ */
+static int supPagePageAllocNoKernelFallback(size_t cPages, void **ppvPages, PSUPPAGE paPages)
+{
+ int rc = suplibOsPageAlloc(&g_supLibData, cPages, ppvPages);
+ if (RT_SUCCESS(rc))
+ {
+ if (!paPages)
+ paPages = (PSUPPAGE)alloca(sizeof(paPages[0]) * cPages);
+ rc = supR3PageLock(*ppvPages, cPages, paPages);
+ if (RT_FAILURE(rc))
+ suplibOsPageFree(&g_supLibData, *ppvPages, cPages);
+ }
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPR3PageAllocEx(size_t cPages, uint32_t fFlags, void **ppvPages, PRTR0PTR pR0Ptr, PSUPPAGE paPages)
+{
+ /*
+ * Validate.
+ */
+ AssertPtrReturn(ppvPages, VERR_INVALID_POINTER);
+ *ppvPages = NULL;
+ AssertPtrNullReturn(pR0Ptr, VERR_INVALID_POINTER);
+ if (pR0Ptr)
+ *pR0Ptr = NIL_RTR0PTR;
+ AssertPtrNullReturn(paPages, VERR_INVALID_POINTER);
+ AssertMsgReturn(cPages > 0 && cPages <= VBOX_MAX_ALLOC_PAGE_COUNT, ("cPages=%zu\n", cPages), VERR_PAGE_COUNT_OUT_OF_RANGE);
+ AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
+
+ /* fake */
+ if (RT_UNLIKELY(g_uSupFakeMode))
+ {
+ void *pv = RTMemPageAllocZ(cPages * PAGE_SIZE);
+ if (!pv)
+ return VERR_NO_MEMORY;
+ *ppvPages = pv;
+ if (pR0Ptr)
+ *pR0Ptr = (RTR0PTR)pv;
+ if (paPages)
+ for (size_t iPage = 0; iPage < cPages; iPage++)
+ {
+ paPages[iPage].uReserved = 0;
+ paPages[iPage].Phys = (iPage + 4321) << PAGE_SHIFT;
+ Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
+ }
+ return VINF_SUCCESS;
+ }
+
+ /* Check that we've got a kernel connection so rtMemSaferSupR3AllocPages
+ can do fallback without first having to hit assertions. */
+ if (g_supLibData.hDevice != SUP_HDEVICE_NIL)
+ { /* likely */ }
+ else
+ return VERR_WRONG_ORDER;
+
+ /*
+ * Use fallback for non-R0 mapping?
+ */
+ if ( !pR0Ptr
+ && !g_fSupportsPageAllocNoKernel)
+ return supPagePageAllocNoKernelFallback(cPages, ppvPages, paPages);
+
+ /*
+ * Issue IOCtl to the SUPDRV kernel module.
+ */
+ int rc;
+ PSUPPAGEALLOCEX pReq = (PSUPPAGEALLOCEX)RTMemTmpAllocZ(SUP_IOCTL_PAGE_ALLOC_EX_SIZE(cPages));
+ if (pReq)
+ {
+ pReq->Hdr.u32Cookie = g_u32Cookie;
+ pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
+ pReq->Hdr.cbIn = SUP_IOCTL_PAGE_ALLOC_EX_SIZE_IN;
+ pReq->Hdr.cbOut = SUP_IOCTL_PAGE_ALLOC_EX_SIZE_OUT(cPages);
+ pReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_OUT;
+ pReq->Hdr.rc = VERR_INTERNAL_ERROR;
+ pReq->u.In.cPages = (uint32_t)cPages; AssertRelease(pReq->u.In.cPages == cPages);
+ pReq->u.In.fKernelMapping = pR0Ptr != NULL;
+ pReq->u.In.fUserMapping = true;
+ pReq->u.In.fReserved0 = false;
+ pReq->u.In.fReserved1 = false;
+ rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_ALLOC_EX, pReq, SUP_IOCTL_PAGE_ALLOC_EX_SIZE(cPages));
+ if (RT_SUCCESS(rc))
+ {
+ rc = pReq->Hdr.rc;
+ if (RT_SUCCESS(rc))
+ {
+ *ppvPages = pReq->u.Out.pvR3;
+ if (pR0Ptr)
+ *pR0Ptr = pReq->u.Out.pvR0;
+ if (paPages)
+ for (size_t iPage = 0; iPage < cPages; iPage++)
+ {
+ paPages[iPage].uReserved = 0;
+ paPages[iPage].Phys = pReq->u.Out.aPages[iPage];
+ Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
+ }
+#ifdef RT_OS_DARWIN /* HACK ALERT! */
+ supR3TouchPages(pReq->u.Out.pvR3, cPages);
+#endif
+ }
+ else if ( rc == VERR_NOT_SUPPORTED
+ && !pR0Ptr)
+ {
+ g_fSupportsPageAllocNoKernel = false;
+ rc = supPagePageAllocNoKernelFallback(cPages, ppvPages, paPages);
+ }
+ }
+
+ RTMemTmpFree(pReq);
+ }
+ else
+ rc = VERR_NO_TMP_MEMORY;
+ return rc;
+
+}
+
+
+SUPR3DECL(int) SUPR3PageMapKernel(void *pvR3, uint32_t off, uint32_t cb, uint32_t fFlags, PRTR0PTR pR0Ptr)
+{
+ /*
+ * Validate.
+ */
+ AssertPtrReturn(pvR3, VERR_INVALID_POINTER);
+ AssertPtrReturn(pR0Ptr, VERR_INVALID_POINTER);
+ Assert(!(off & PAGE_OFFSET_MASK));
+ Assert(!(cb & PAGE_OFFSET_MASK) && cb);
+ Assert(!fFlags);
+ *pR0Ptr = NIL_RTR0PTR;
+
+ /* fake */
+ if (RT_UNLIKELY(g_uSupFakeMode))
+ return VERR_NOT_SUPPORTED;
+
+ /*
+ * Issue IOCtl to the SUPDRV kernel module.
+ */
+ SUPPAGEMAPKERNEL Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_PAGE_MAP_KERNEL_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_PAGE_MAP_KERNEL_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ Req.u.In.pvR3 = pvR3;
+ Req.u.In.offSub = off;
+ Req.u.In.cbSub = cb;
+ Req.u.In.fFlags = fFlags;
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_MAP_KERNEL, &Req, SUP_IOCTL_PAGE_MAP_KERNEL_SIZE);
+ if (RT_SUCCESS(rc))
+ rc = Req.Hdr.rc;
+ if (RT_SUCCESS(rc))
+ *pR0Ptr = Req.u.Out.pvR0;
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPR3PageProtect(void *pvR3, RTR0PTR R0Ptr, uint32_t off, uint32_t cb, uint32_t fProt)
+{
+ /*
+ * Validate.
+ */
+ AssertPtrReturn(pvR3, VERR_INVALID_POINTER);
+ Assert(!(off & PAGE_OFFSET_MASK));
+ Assert(!(cb & PAGE_OFFSET_MASK) && cb);
+ AssertReturn(!(fProt & ~(RTMEM_PROT_NONE | RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC)), VERR_INVALID_PARAMETER);
+
+ /* fake */
+ if (RT_UNLIKELY(g_uSupFakeMode))
+ return RTMemProtect((uint8_t *)pvR3 + off, cb, fProt);
+
+ /*
+ * Some OSes can do this from ring-3, so try that before we
+ * issue the IOCtl to the SUPDRV kernel module.
+ * (Yea, this isn't very nice, but just try get the job done for now.)
+ */
+#if !defined(RT_OS_SOLARIS)
+ RTMemProtect((uint8_t *)pvR3 + off, cb, fProt);
+#endif
+
+ SUPPAGEPROTECT Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_PAGE_PROTECT_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_PAGE_PROTECT_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ Req.u.In.pvR3 = pvR3;
+ Req.u.In.pvR0 = R0Ptr;
+ Req.u.In.offSub = off;
+ Req.u.In.cbSub = cb;
+ Req.u.In.fProt = fProt;
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_PROTECT, &Req, SUP_IOCTL_PAGE_PROTECT_SIZE);
+ if (RT_SUCCESS(rc))
+ rc = Req.Hdr.rc;
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPR3PageFreeEx(void *pvPages, size_t cPages)
+{
+ /*
+ * Validate.
+ */
+ AssertPtrReturn(pvPages, VERR_INVALID_POINTER);
+ AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
+
+ /* fake */
+ if (RT_UNLIKELY(g_uSupFakeMode))
+ {
+ RTMemPageFree(pvPages, cPages * PAGE_SIZE);
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Try normal free first, then if it fails check if we're using the fallback
+ * for the allocations without kernel mappings and attempt unlocking it.
+ */
+ NOREF(cPages);
+ SUPPAGEFREE Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_PAGE_FREE_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_PAGE_FREE_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ Req.u.In.pvR3 = pvPages;
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_FREE, &Req, SUP_IOCTL_PAGE_FREE_SIZE);
+ if (RT_SUCCESS(rc))
+ {
+ rc = Req.Hdr.rc;
+ if ( rc == VERR_INVALID_PARAMETER
+ && !g_fSupportsPageAllocNoKernel)
+ {
+ int rc2 = supR3PageUnlock(pvPages);
+ if (RT_SUCCESS(rc2))
+ rc = suplibOsPageFree(&g_supLibData, pvPages, cPages);
+ }
+ }
+ return rc;
+}
+
+
+SUPR3DECL(void *) SUPR3ContAlloc(size_t cPages, PRTR0PTR pR0Ptr, PRTHCPHYS pHCPhys)
+{
+ /*
+ * Validate.
+ */
+ AssertPtrReturn(pHCPhys, NULL);
+ *pHCPhys = NIL_RTHCPHYS;
+ AssertPtrNullReturn(pR0Ptr, NULL);
+ if (pR0Ptr)
+ *pR0Ptr = NIL_RTR0PTR;
+ AssertPtrNullReturn(pHCPhys, NULL);
+ AssertMsgReturn(cPages > 0 && cPages < 256, ("cPages=%d must be > 0 and < 256\n", cPages), NULL);
+
+ /* fake */
+ if (RT_UNLIKELY(g_uSupFakeMode))
+ {
+ void *pv = RTMemPageAllocZ(cPages * PAGE_SIZE);
+ if (pR0Ptr)
+ *pR0Ptr = (RTR0PTR)pv;
+ if (pHCPhys)
+ *pHCPhys = (uintptr_t)pv + (PAGE_SHIFT * 1024);
+ return pv;
+ }
+
+ /*
+ * Issue IOCtl to the SUPDRV kernel module.
+ */
+ SUPCONTALLOC Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_CONT_ALLOC_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_CONT_ALLOC_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ Req.u.In.cPages = (uint32_t)cPages;
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CONT_ALLOC, &Req, SUP_IOCTL_CONT_ALLOC_SIZE);
+ if ( RT_SUCCESS(rc)
+ && RT_SUCCESS(Req.Hdr.rc))
+ {
+ *pHCPhys = Req.u.Out.HCPhys;
+ if (pR0Ptr)
+ *pR0Ptr = Req.u.Out.pvR0;
+#ifdef RT_OS_DARWIN /* HACK ALERT! */
+ supR3TouchPages(Req.u.Out.pvR3, cPages);
+#endif
+ return Req.u.Out.pvR3;
+ }
+
+ return NULL;
+}
+
+
+SUPR3DECL(int) SUPR3ContFree(void *pv, size_t cPages)
+{
+ /*
+ * Validate.
+ */
+ if (!pv)
+ return VINF_SUCCESS;
+ AssertPtrReturn(pv, VERR_INVALID_POINTER);
+ AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
+
+ /* fake */
+ if (RT_UNLIKELY(g_uSupFakeMode))
+ {
+ RTMemPageFree(pv, cPages * PAGE_SIZE);
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Issue IOCtl to the SUPDRV kernel module.
+ */
+ SUPCONTFREE Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_CONT_FREE_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_CONT_FREE_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ Req.u.In.pvR3 = pv;
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CONT_FREE, &Req, SUP_IOCTL_CONT_FREE_SIZE);
+ if (RT_SUCCESS(rc))
+ rc = Req.Hdr.rc;
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPR3LowAlloc(size_t cPages, void **ppvPages, PRTR0PTR ppvPagesR0, PSUPPAGE paPages)
+{
+ /*
+ * Validate.
+ */
+ AssertPtrReturn(ppvPages, VERR_INVALID_POINTER);
+ *ppvPages = NULL;
+ AssertPtrReturn(paPages, VERR_INVALID_POINTER);
+ AssertMsgReturn(cPages > 0 && cPages < 256, ("cPages=%d must be > 0 and < 256\n", cPages), VERR_PAGE_COUNT_OUT_OF_RANGE);
+
+ /* fake */
+ if (RT_UNLIKELY(g_uSupFakeMode))
+ {
+ *ppvPages = RTMemPageAllocZ((size_t)cPages * PAGE_SIZE);
+ if (!*ppvPages)
+ return VERR_NO_LOW_MEMORY;
+
+ /* fake physical addresses. */
+ RTHCPHYS Phys = (uintptr_t)*ppvPages + PAGE_SIZE * 1024;
+ size_t iPage = cPages;
+ while (iPage-- > 0)
+ paPages[iPage].Phys = Phys + (iPage << PAGE_SHIFT);
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Issue IOCtl to the SUPDRV kernel module.
+ */
+ int rc;
+ PSUPLOWALLOC pReq = (PSUPLOWALLOC)RTMemTmpAllocZ(SUP_IOCTL_LOW_ALLOC_SIZE(cPages));
+ if (pReq)
+ {
+ pReq->Hdr.u32Cookie = g_u32Cookie;
+ pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
+ pReq->Hdr.cbIn = SUP_IOCTL_LOW_ALLOC_SIZE_IN;
+ pReq->Hdr.cbOut = SUP_IOCTL_LOW_ALLOC_SIZE_OUT(cPages);
+ pReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_OUT;
+ pReq->Hdr.rc = VERR_INTERNAL_ERROR;
+ pReq->u.In.cPages = (uint32_t)cPages; AssertRelease(pReq->u.In.cPages == cPages);
+ rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LOW_ALLOC, pReq, SUP_IOCTL_LOW_ALLOC_SIZE(cPages));
+ if (RT_SUCCESS(rc))
+ rc = pReq->Hdr.rc;
+ if (RT_SUCCESS(rc))
+ {
+ *ppvPages = pReq->u.Out.pvR3;
+ if (ppvPagesR0)
+ *ppvPagesR0 = pReq->u.Out.pvR0;
+ if (paPages)
+ for (size_t iPage = 0; iPage < cPages; iPage++)
+ {
+ paPages[iPage].uReserved = 0;
+ paPages[iPage].Phys = pReq->u.Out.aPages[iPage];
+ Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
+ Assert(paPages[iPage].Phys <= UINT32_C(0xfffff000));
+ }
+#ifdef RT_OS_DARWIN /* HACK ALERT! */
+ supR3TouchPages(pReq->u.Out.pvR3, cPages);
+#endif
+ }
+ RTMemTmpFree(pReq);
+ }
+ else
+ rc = VERR_NO_TMP_MEMORY;
+
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPR3LowFree(void *pv, size_t cPages)
+{
+ /*
+ * Validate.
+ */
+ if (!pv)
+ return VINF_SUCCESS;
+ AssertPtrReturn(pv, VERR_INVALID_POINTER);
+ AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
+
+ /* fake */
+ if (RT_UNLIKELY(g_uSupFakeMode))
+ {
+ RTMemPageFree(pv, cPages * PAGE_SIZE);
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Issue IOCtl to the SUPDRV kernel module.
+ */
+ SUPCONTFREE Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_LOW_FREE_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_LOW_FREE_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ Req.u.In.pvR3 = pv;
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LOW_FREE, &Req, SUP_IOCTL_LOW_FREE_SIZE);
+ if (RT_SUCCESS(rc))
+ rc = Req.Hdr.rc;
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPR3HardenedVerifyInit(void)
+{
+#ifdef RT_OS_WINDOWS
+ if (g_cInits == 0)
+ return suplibOsHardenedVerifyInit();
+#endif
+ return VINF_SUCCESS;
+}
+
+
+SUPR3DECL(int) SUPR3HardenedVerifyTerm(void)
+{
+#ifdef RT_OS_WINDOWS
+ if (g_cInits == 0)
+ return suplibOsHardenedVerifyTerm();
+#endif
+ return VINF_SUCCESS;
+}
+
+
+SUPR3DECL(int) SUPR3HardenedVerifyFile(const char *pszFilename, const char *pszMsg, PRTFILE phFile)
+{
+ /*
+ * Quick input validation.
+ */
+ AssertPtr(pszFilename);
+ AssertPtr(pszMsg);
+ AssertReturn(!phFile, VERR_NOT_IMPLEMENTED); /** @todo Implement this. The deal is that we make sure the
+ file is the same we verified after opening it. */
+ RT_NOREF2(pszFilename, pszMsg);
+
+ /*
+ * Only do the actual check in hardened builds.
+ */
+#ifdef VBOX_WITH_HARDENING
+ int rc = supR3HardenedVerifyFixedFile(pszFilename, false /* fFatal */);
+ if (RT_FAILURE(rc))
+ LogRel(("SUPR3HardenedVerifyFile: %s: Verification of \"%s\" failed, rc=%Rrc\n", pszMsg, pszFilename, rc));
+ return rc;
+#else
+ return VINF_SUCCESS;
+#endif
+}
+
+
+SUPR3DECL(int) SUPR3HardenedVerifySelf(const char *pszArgv0, bool fInternal, PRTERRINFO pErrInfo)
+{
+ /*
+ * Quick input validation.
+ */
+ AssertPtr(pszArgv0);
+ RTErrInfoClear(pErrInfo);
+
+ /*
+ * Get the executable image path as we need it for all the tests here.
+ */
+ char szExecPath[RTPATH_MAX];
+ if (!RTProcGetExecutablePath(szExecPath, sizeof(szExecPath)))
+ return RTErrInfoSet(pErrInfo, VERR_INTERNAL_ERROR_2, "RTProcGetExecutablePath failed");
+
+ int rc;
+ if (fInternal)
+ {
+ /*
+ * Internal applications must be launched directly without any PATH
+ * searching involved.
+ */
+ if (RTPathCompare(pszArgv0, szExecPath) != 0)
+ return RTErrInfoSetF(pErrInfo, VERR_SUPLIB_INVALID_ARGV0_INTERNAL,
+ "argv[0] does not match the executable image path: '%s' != '%s'", pszArgv0, szExecPath);
+
+ /*
+ * Internal applications must reside in or under the
+ * RTPathAppPrivateArch directory.
+ */
+ char szAppPrivateArch[RTPATH_MAX];
+ rc = RTPathAppPrivateArch(szAppPrivateArch, sizeof(szAppPrivateArch));
+ if (RT_FAILURE(rc))
+ return RTErrInfoSetF(pErrInfo, VERR_SUPLIB_INVALID_ARGV0_INTERNAL,
+ "RTPathAppPrivateArch failed with rc=%Rrc", rc);
+ size_t cchAppPrivateArch = strlen(szAppPrivateArch);
+ if ( cchAppPrivateArch >= strlen(szExecPath)
+ || !RTPATH_IS_SLASH(szExecPath[cchAppPrivateArch]))
+ return RTErrInfoSet(pErrInfo, VERR_SUPLIB_INVALID_INTERNAL_APP_DIR,
+ "Internal executable does reside under RTPathAppPrivateArch");
+ szExecPath[cchAppPrivateArch] = '\0';
+ if (RTPathCompare(szExecPath, szAppPrivateArch) != 0)
+ return RTErrInfoSet(pErrInfo, VERR_SUPLIB_INVALID_INTERNAL_APP_DIR,
+ "Internal executable does reside under RTPathAppPrivateArch");
+ szExecPath[cchAppPrivateArch] = RTPATH_SLASH;
+ }
+
+#ifdef VBOX_WITH_HARDENING
+ /*
+ * Verify that the image file and parent directories are sane.
+ */
+ rc = supR3HardenedVerifyFile(szExecPath, RTHCUINTPTR_MAX, false /*fMaybe3rdParty*/, pErrInfo);
+ if (RT_FAILURE(rc))
+ return rc;
+#endif
+
+ return VINF_SUCCESS;
+}
+
+
+SUPR3DECL(int) SUPR3HardenedVerifyDir(const char *pszDirPath, bool fRecursive, bool fCheckFiles, PRTERRINFO pErrInfo)
+{
+ /*
+ * Quick input validation
+ */
+ AssertPtr(pszDirPath);
+ RTErrInfoClear(pErrInfo);
+
+ /*
+ * Only do the actual check in hardened builds.
+ */
+#ifdef VBOX_WITH_HARDENING
+ int rc = supR3HardenedVerifyDir(pszDirPath, fRecursive, fCheckFiles, pErrInfo);
+ if (RT_FAILURE(rc) && !RTErrInfoIsSet(pErrInfo))
+ LogRel(("supR3HardenedVerifyDir: Verification of \"%s\" failed, rc=%Rrc\n", pszDirPath, rc));
+ return rc;
+#else
+ NOREF(pszDirPath); NOREF(fRecursive); NOREF(fCheckFiles);
+ return VINF_SUCCESS;
+#endif
+}
+
+
+SUPR3DECL(int) SUPR3HardenedVerifyPlugIn(const char *pszFilename, PRTERRINFO pErrInfo)
+{
+ /*
+ * Quick input validation
+ */
+ AssertPtr(pszFilename);
+ RTErrInfoClear(pErrInfo);
+
+ /*
+ * Only do the actual check in hardened builds.
+ */
+#ifdef VBOX_WITH_HARDENING
+ int rc = supR3HardenedVerifyFile(pszFilename, RTHCUINTPTR_MAX, true /*fMaybe3rdParty*/, pErrInfo);
+ if (RT_FAILURE(rc) && !RTErrInfoIsSet(pErrInfo))
+ LogRel(("supR3HardenedVerifyFile: Verification of \"%s\" failed, rc=%Rrc\n", pszFilename, rc));
+ return rc;
+#else
+ RT_NOREF1(pszFilename);
+ return VINF_SUCCESS;
+#endif
+}
+
+
+SUPR3DECL(int) SUPR3GipGetPhys(PRTHCPHYS pHCPhys)
+{
+ if (g_pSUPGlobalInfoPage)
+ {
+ *pHCPhys = g_HCPhysSUPGlobalInfoPage;
+ return VINF_SUCCESS;
+ }
+ *pHCPhys = NIL_RTHCPHYS;
+ return VERR_WRONG_ORDER;
+}
+
+
+SUPR3DECL(int) SUPR3QueryVTxSupported(const char **ppszWhy)
+{
+ *ppszWhy = NULL;
+#ifdef RT_OS_LINUX
+ return suplibOsQueryVTxSupported(ppszWhy);
+#else
+ return VINF_SUCCESS;
+#endif
+}
+
+
+SUPR3DECL(int) SUPR3QueryVTCaps(uint32_t *pfCaps)
+{
+ AssertPtrReturn(pfCaps, VERR_INVALID_POINTER);
+
+ *pfCaps = 0;
+
+ /* fake */
+ if (RT_UNLIKELY(g_uSupFakeMode))
+ return VINF_SUCCESS;
+
+ /*
+ * Issue IOCtl to the SUPDRV kernel module.
+ */
+ SUPVTCAPS Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_VT_CAPS_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_VT_CAPS_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ Req.u.Out.fCaps = 0;
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_VT_CAPS, &Req, SUP_IOCTL_VT_CAPS_SIZE);
+ if (RT_SUCCESS(rc))
+ {
+ rc = Req.Hdr.rc;
+ if (RT_SUCCESS(rc))
+ *pfCaps = Req.u.Out.fCaps;
+ }
+ return rc;
+}
+
+
+SUPR3DECL(bool) SUPR3IsNemSupportedWhenNoVtxOrAmdV(void)
+{
+#ifdef RT_OS_WINDOWS
+ return suplibOsIsNemSupportedWhenNoVtxOrAmdV();
+#else
+ return false;
+#endif
+}
+
+
+SUPR3DECL(int) SUPR3QueryMicrocodeRev(uint32_t *uMicrocodeRev)
+{
+ AssertPtrReturn(uMicrocodeRev, VERR_INVALID_POINTER);
+
+ *uMicrocodeRev = 0;
+
+ /* fake */
+ if (RT_UNLIKELY(g_uSupFakeMode))
+ return VINF_SUCCESS;
+
+ /*
+ * Issue IOCtl to the SUPDRV kernel module.
+ */
+ SUPUCODEREV Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_UCODE_REV_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_UCODE_REV_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ Req.u.Out.MicrocodeRev = 0;
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_UCODE_REV, &Req, SUP_IOCTL_UCODE_REV_SIZE);
+ if (RT_SUCCESS(rc))
+ {
+ rc = Req.Hdr.rc;
+ if (RT_SUCCESS(rc))
+ *uMicrocodeRev = Req.u.Out.MicrocodeRev;
+ }
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPR3TracerOpen(uint32_t uCookie, uintptr_t uArg)
+{
+ /* fake */
+ if (RT_UNLIKELY(g_uSupFakeMode))
+ return VINF_SUCCESS;
+
+ /*
+ * Issue IOCtl to the SUPDRV kernel module.
+ */
+ SUPTRACEROPEN Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie= g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_TRACER_OPEN_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_TRACER_OPEN_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ Req.u.In.uCookie = uCookie;
+ Req.u.In.uArg = uArg;
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_TRACER_OPEN, &Req, SUP_IOCTL_TRACER_OPEN_SIZE);
+ if (RT_SUCCESS(rc))
+ rc = Req.Hdr.rc;
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPR3TracerClose(void)
+{
+ /* fake */
+ if (RT_UNLIKELY(g_uSupFakeMode))
+ return VINF_SUCCESS;
+
+ /*
+ * Issue IOCtl to the SUPDRV kernel module.
+ */
+ SUPREQHDR Req;
+ Req.u32Cookie = g_u32Cookie;
+ Req.u32SessionCookie= g_u32SessionCookie;
+ Req.cbIn = SUP_IOCTL_TRACER_OPEN_SIZE_IN;
+ Req.cbOut = SUP_IOCTL_TRACER_OPEN_SIZE_OUT;
+ Req.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.rc = VERR_INTERNAL_ERROR;
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_TRACER_CLOSE, &Req, SUP_IOCTL_TRACER_CLOSE_SIZE);
+ if (RT_SUCCESS(rc))
+ rc = Req.rc;
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPR3TracerIoCtl(uintptr_t uCmd, uintptr_t uArg, int32_t *piRetVal)
+{
+ /* fake */
+ if (RT_UNLIKELY(g_uSupFakeMode))
+ {
+ *piRetVal = -1;
+ return VERR_NOT_SUPPORTED;
+ }
+
+ /*
+ * Issue IOCtl to the SUPDRV kernel module.
+ */
+ SUPTRACERIOCTL Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie= g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_TRACER_IOCTL_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_TRACER_IOCTL_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ Req.u.In.uCmd = uCmd;
+ Req.u.In.uArg = uArg;
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_TRACER_IOCTL, &Req, SUP_IOCTL_TRACER_IOCTL_SIZE);
+ if (RT_SUCCESS(rc))
+ {
+ rc = Req.Hdr.rc;
+ *piRetVal = Req.u.Out.iRetVal;
+ }
+ return rc;
+}
+
+
+
+typedef struct SUPDRVTRACERSTRTAB
+{
+ /** Pointer to the string table. */
+ char *pchStrTab;
+ /** The actual string table size. */
+ uint32_t cbStrTab;
+ /** The original string pointers. */
+ RTUINTPTR apszOrgFunctions[1];
+} SUPDRVTRACERSTRTAB, *PSUPDRVTRACERSTRTAB;
+
+
+/**
+ * Destroys a string table, restoring the original pszFunction member valus.
+ *
+ * @param pThis The string table structure.
+ * @param paProbeLocs32 The probe location array, 32-bit type variant.
+ * @param paProbeLocs64 The probe location array, 64-bit type variant.
+ * @param cProbeLocs The number of elements in the array.
+ * @param f32Bit Set if @a paProbeLocs32 should be used, when
+ * clear use @a paProbeLocs64.
+ */
+static void supr3TracerDestroyStrTab(PSUPDRVTRACERSTRTAB pThis, PVTGPROBELOC32 paProbeLocs32, PVTGPROBELOC64 paProbeLocs64,
+ uint32_t cProbeLocs, bool f32Bit)
+{
+ /* Restore. */
+ size_t i = cProbeLocs;
+ if (f32Bit)
+ while (i--)
+ paProbeLocs32[i].pszFunction = (uint32_t)pThis->apszOrgFunctions[i];
+ else
+ while (i--)
+ paProbeLocs64[i].pszFunction = pThis->apszOrgFunctions[i];
+
+ /* Free. */
+ RTMemFree(pThis->pchStrTab);
+ RTMemFree(pThis);
+}
+
+
+/**
+ * Creates a string table for the pszFunction members in the probe location
+ * array.
+ *
+ * This will save and replace the pszFunction members with offsets.
+ *
+ * @returns Pointer to a string table structure. NULL on failure.
+ * @param paProbeLocs32 The probe location array, 32-bit type variant.
+ * @param paProbeLocs64 The probe location array, 64-bit type variant.
+ * @param cProbeLocs The number of elements in the array.
+ * @param offDelta Relocation offset for the string pointers.
+ * @param f32Bit Set if @a paProbeLocs32 should be used, when
+ * clear use @a paProbeLocs64.
+ */
+static PSUPDRVTRACERSTRTAB supr3TracerCreateStrTab(PVTGPROBELOC32 paProbeLocs32,
+ PVTGPROBELOC64 paProbeLocs64,
+ uint32_t cProbeLocs,
+ RTUINTPTR offDelta,
+ bool f32Bit)
+{
+ if (cProbeLocs > _128K)
+ return NULL;
+
+ /*
+ * Allocate the string table structures.
+ */
+ size_t cbThis = RT_UOFFSETOF_DYN(SUPDRVTRACERSTRTAB, apszOrgFunctions[cProbeLocs]);
+ PSUPDRVTRACERSTRTAB pThis = (PSUPDRVTRACERSTRTAB)RTMemAlloc(cbThis);
+ if (!pThis)
+ return NULL;
+
+ uint32_t const cHashBits = cProbeLocs * 2 - 1;
+ uint32_t *pbmHash = (uint32_t *)RTMemAllocZ(RT_ALIGN_32(cHashBits, 64) / 8 );
+ if (!pbmHash)
+ {
+ RTMemFree(pThis);
+ return NULL;
+ }
+
+ /*
+ * Calc the max string table size and save the orignal pointers so we can
+ * replace them later.
+ */
+ size_t cbMax = 1;
+ for (uint32_t i = 0; i < cProbeLocs; i++)
+ {
+ pThis->apszOrgFunctions[i] = f32Bit ? paProbeLocs32[i].pszFunction : paProbeLocs64[i].pszFunction;
+ const char *pszFunction = (const char *)(uintptr_t)(pThis->apszOrgFunctions[i] + offDelta);
+ size_t cch = strlen(pszFunction);
+ if (cch > _1K)
+ {
+ cbMax = 0;
+ break;
+ }
+ cbMax += cch + 1;
+ }
+
+ /* Alloc space for it. */
+ if (cbMax > 0)
+ pThis->pchStrTab = (char *)RTMemAlloc(cbMax);
+ else
+ pThis->pchStrTab = NULL;
+ if (!pThis->pchStrTab)
+ {
+ RTMemFree(pbmHash);
+ RTMemFree(pThis);
+ return NULL;
+ }
+
+ /*
+ * Create the string table.
+ */
+ uint32_t off = 0;
+ uint32_t offPrev = 0;
+
+ for (uint32_t i = 0; i < cProbeLocs; i++)
+ {
+ const char * const psz = (const char *)(uintptr_t)(pThis->apszOrgFunctions[i] + offDelta);
+ size_t const cch = strlen(psz);
+ uint32_t const iHashBit = RTStrHash1(psz) % cHashBits;
+ if (ASMBitTestAndSet(pbmHash, iHashBit))
+ {
+ /* Often it's the most recent string. */
+ if ( off - offPrev < cch + 1
+ || memcmp(&pThis->pchStrTab[offPrev], psz, cch + 1))
+ {
+ /* It wasn't, search the entire string table. (lazy bird) */
+ offPrev = 0;
+ while (offPrev < off)
+ {
+ size_t cchCur = strlen(&pThis->pchStrTab[offPrev]);
+ if ( cchCur == cch
+ && !memcmp(&pThis->pchStrTab[offPrev], psz, cch + 1))
+ break;
+ offPrev += (uint32_t)cchCur + 1;
+ }
+ }
+ }
+ else
+ offPrev = off;
+
+ /* Add the string to the table. */
+ if (offPrev >= off)
+ {
+ memcpy(&pThis->pchStrTab[off], psz, cch + 1);
+ offPrev = off;
+ off += (uint32_t)cch + 1;
+ }
+
+ /* Update the entry */
+ if (f32Bit)
+ paProbeLocs32[i].pszFunction = offPrev;
+ else
+ paProbeLocs64[i].pszFunction = offPrev;
+ }
+
+ pThis->cbStrTab = off;
+ RTMemFree(pbmHash);
+ return pThis;
+}
+
+
+
+SUPR3DECL(int) SUPR3TracerRegisterModule(uintptr_t hModNative, const char *pszModule, struct VTGOBJHDR *pVtgHdr,
+ RTUINTPTR uVtgHdrAddr, uint32_t fFlags)
+{
+ /* Validate input. */
+ NOREF(hModNative);
+ AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
+ AssertReturn(!memcmp(pVtgHdr->szMagic, VTGOBJHDR_MAGIC, sizeof(pVtgHdr->szMagic)), VERR_SUPDRV_VTG_MAGIC);
+ AssertPtrReturn(pszModule, VERR_INVALID_POINTER);
+ size_t cchModule = strlen(pszModule);
+ AssertReturn(cchModule < RT_SIZEOFMEMB(SUPTRACERUMODREG, u.In.szName), VERR_FILENAME_TOO_LONG);
+ AssertReturn(!RTPathHavePath(pszModule), VERR_INVALID_PARAMETER);
+ AssertReturn(fFlags == SUP_TRACER_UMOD_FLAGS_EXE || fFlags == SUP_TRACER_UMOD_FLAGS_SHARED, VERR_INVALID_PARAMETER);
+
+ /*
+ * Set the probe location array offset and size members. If the size is
+ * zero, don't bother ring-0 with it.
+ */
+ if (!pVtgHdr->offProbeLocs)
+ {
+ uint64_t u64Tmp = pVtgHdr->uProbeLocsEnd.u64 - pVtgHdr->uProbeLocs.u64;
+ if (u64Tmp >= UINT32_MAX)
+ return VERR_SUPDRV_VTG_BAD_HDR_TOO_MUCH;
+ pVtgHdr->cbProbeLocs = (uint32_t)u64Tmp;
+
+ u64Tmp = pVtgHdr->uProbeLocs.u64 - uVtgHdrAddr;
+ if ((int64_t)u64Tmp != (int32_t)u64Tmp)
+ {
+ LogRel(("SUPR3TracerRegisterModule: VERR_SUPDRV_VTG_BAD_HDR_PTR - u64Tmp=%#llx uProbeLocs=%#llx uVtgHdrAddr=%RTptr\n",
+ u64Tmp, pVtgHdr->uProbeLocs.u64, uVtgHdrAddr));
+ return VERR_SUPDRV_VTG_BAD_HDR_PTR;
+ }
+ pVtgHdr->offProbeLocs = (int32_t)u64Tmp;
+ }
+
+ if ( !pVtgHdr->cbProbeLocs
+ || !pVtgHdr->cbProbes)
+ return VINF_SUCCESS;
+
+ /*
+ * Fake out.
+ */
+ if (RT_UNLIKELY(g_uSupFakeMode))
+ return VINF_SUCCESS;
+
+ /*
+ * Create a string table for the function names in the location array.
+ * It's somewhat easier to do that here than from ring-0.
+ */
+ uint32_t const cProbeLocs = pVtgHdr->cbProbeLocs
+ / (pVtgHdr->cBits == 32 ? sizeof(VTGPROBELOC32) : sizeof(VTGPROBELOC64));
+ PVTGPROBELOC paProbeLocs = (PVTGPROBELOC)((uintptr_t)pVtgHdr + pVtgHdr->offProbeLocs);
+ PSUPDRVTRACERSTRTAB pStrTab = supr3TracerCreateStrTab((PVTGPROBELOC32)paProbeLocs,
+ (PVTGPROBELOC64)paProbeLocs,
+ cProbeLocs, (uintptr_t)pVtgHdr - uVtgHdrAddr,
+ pVtgHdr->cBits == 32);
+ if (!pStrTab)
+ return VERR_NO_MEMORY;
+
+
+ /*
+ * Issue IOCtl to the SUPDRV kernel module.
+ */
+ SUPTRACERUMODREG Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie= g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_TRACER_UMOD_REG_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_TRACER_UMOD_REG_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ Req.u.In.uVtgHdrAddr = uVtgHdrAddr;
+ Req.u.In.R3PtrVtgHdr = pVtgHdr;
+ Req.u.In.R3PtrStrTab = pStrTab->pchStrTab;
+ Req.u.In.cbStrTab = pStrTab->cbStrTab;
+ Req.u.In.fFlags = fFlags;
+
+ memcpy(Req.u.In.szName, pszModule, cchModule + 1);
+ if (!RTPathHasSuffix(Req.u.In.szName))
+ {
+ /* Add the default suffix if none is given. */
+ switch (fFlags & SUP_TRACER_UMOD_FLAGS_TYPE_MASK)
+ {
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
+ case SUP_TRACER_UMOD_FLAGS_EXE:
+ if (cchModule + sizeof(".exe") <= sizeof(Req.u.In.szName))
+ strcpy(&Req.u.In.szName[cchModule], ".exe");
+ break;
+#endif
+
+ case SUP_TRACER_UMOD_FLAGS_SHARED:
+ {
+ const char *pszSuff = RTLdrGetSuff();
+ size_t cchSuff = strlen(pszSuff);
+ if (cchModule + cchSuff < sizeof(Req.u.In.szName))
+ memcpy(&Req.u.In.szName[cchModule], pszSuff, cchSuff + 1);
+ break;
+ }
+ }
+ }
+
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_TRACER_UMOD_REG, &Req, SUP_IOCTL_TRACER_UMOD_REG_SIZE);
+ if (RT_SUCCESS(rc))
+ rc = Req.Hdr.rc;
+
+ supr3TracerDestroyStrTab(pStrTab, (PVTGPROBELOC32)paProbeLocs, (PVTGPROBELOC64)paProbeLocs,
+ cProbeLocs, pVtgHdr->cBits == 32);
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPR3TracerDeregisterModule(struct VTGOBJHDR *pVtgHdr)
+{
+ /* Validate input. */
+ AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
+ AssertReturn(!memcmp(pVtgHdr->szMagic, VTGOBJHDR_MAGIC, sizeof(pVtgHdr->szMagic)), VERR_SUPDRV_VTG_MAGIC);
+
+ /*
+ * Don't bother if the object is empty.
+ */
+ if ( !pVtgHdr->cbProbeLocs
+ || !pVtgHdr->cbProbes)
+ return VINF_SUCCESS;
+
+ /*
+ * Fake out.
+ */
+ if (RT_UNLIKELY(g_uSupFakeMode))
+ return VINF_SUCCESS;
+
+ /*
+ * Issue IOCtl to the SUPDRV kernel module.
+ */
+ SUPTRACERUMODDEREG Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie= g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_TRACER_UMOD_REG_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_TRACER_UMOD_REG_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ Req.u.In.pVtgHdr = pVtgHdr;
+
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_TRACER_UMOD_DEREG, &Req, SUP_IOCTL_TRACER_UMOD_DEREG_SIZE);
+ if (RT_SUCCESS(rc))
+ rc = Req.Hdr.rc;
+ return rc;
+}
+
+
+DECLASM(void) suplibTracerFireProbe(PVTGPROBELOC pProbeLoc, PSUPTRACERUMODFIREPROBE pReq)
+{
+ RT_NOREF1(pProbeLoc);
+
+ pReq->Hdr.u32Cookie = g_u32Cookie;
+ pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
+ Assert(pReq->Hdr.cbIn == SUP_IOCTL_TRACER_UMOD_FIRE_PROBE_SIZE_IN);
+ Assert(pReq->Hdr.cbOut == SUP_IOCTL_TRACER_UMOD_FIRE_PROBE_SIZE_OUT);
+ pReq->Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ pReq->Hdr.rc = VINF_SUCCESS;
+
+ suplibOsIOCtl(&g_supLibData, SUP_IOCTL_TRACER_UMOD_FIRE_PROBE, pReq, SUP_IOCTL_TRACER_UMOD_FIRE_PROBE_SIZE);
+}
+
+
+SUPR3DECL(int) SUPR3MsrProberRead(uint32_t uMsr, RTCPUID idCpu, uint64_t *puValue, bool *pfGp)
+{
+ SUPMSRPROBER Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_MSR_PROBER_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_MSR_PROBER_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+
+ Req.u.In.enmOp = SUPMSRPROBEROP_READ;
+ Req.u.In.uMsr = uMsr;
+ Req.u.In.idCpu = idCpu == NIL_RTCPUID ? UINT32_MAX : idCpu;
+
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_MSR_PROBER, &Req, SUP_IOCTL_MSR_PROBER_SIZE);
+ if (RT_SUCCESS(rc))
+ rc = Req.Hdr.rc;
+ if (RT_SUCCESS(rc))
+ {
+ if (puValue)
+ *puValue = Req.u.Out.uResults.Read.uValue;
+ if (pfGp)
+ *pfGp = Req.u.Out.uResults.Read.fGp;
+ }
+
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPR3MsrProberWrite(uint32_t uMsr, RTCPUID idCpu, uint64_t uValue, bool *pfGp)
+{
+ SUPMSRPROBER Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_MSR_PROBER_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_MSR_PROBER_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+
+ Req.u.In.enmOp = SUPMSRPROBEROP_WRITE;
+ Req.u.In.uMsr = uMsr;
+ Req.u.In.idCpu = idCpu == NIL_RTCPUID ? UINT32_MAX : idCpu;
+ Req.u.In.uArgs.Write.uToWrite = uValue;
+
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_MSR_PROBER, &Req, SUP_IOCTL_MSR_PROBER_SIZE);
+ if (RT_SUCCESS(rc))
+ rc = Req.Hdr.rc;
+ if (RT_SUCCESS(rc) && pfGp)
+ *pfGp = Req.u.Out.uResults.Write.fGp;
+
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPR3MsrProberModify(uint32_t uMsr, RTCPUID idCpu, uint64_t fAndMask, uint64_t fOrMask,
+ PSUPMSRPROBERMODIFYRESULT pResult)
+{
+ return SUPR3MsrProberModifyEx(uMsr, idCpu, fAndMask, fOrMask, false /*fFaster*/, pResult);
+}
+
+
+SUPR3DECL(int) SUPR3MsrProberModifyEx(uint32_t uMsr, RTCPUID idCpu, uint64_t fAndMask, uint64_t fOrMask, bool fFaster,
+ PSUPMSRPROBERMODIFYRESULT pResult)
+{
+ SUPMSRPROBER Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_MSR_PROBER_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_MSR_PROBER_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+
+ Req.u.In.enmOp = fFaster ? SUPMSRPROBEROP_MODIFY_FASTER : SUPMSRPROBEROP_MODIFY;
+ Req.u.In.uMsr = uMsr;
+ Req.u.In.idCpu = idCpu == NIL_RTCPUID ? UINT32_MAX : idCpu;
+ Req.u.In.uArgs.Modify.fAndMask = fAndMask;
+ Req.u.In.uArgs.Modify.fOrMask = fOrMask;
+
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_MSR_PROBER, &Req, SUP_IOCTL_MSR_PROBER_SIZE);
+ if (RT_SUCCESS(rc))
+ rc = Req.Hdr.rc;
+ if (RT_SUCCESS(rc))
+ *pResult = Req.u.Out.uResults.Modify;
+
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPR3ResumeSuspendedKeyboards(void)
+{
+#ifdef RT_OS_DARWIN
+ /*
+ * Issue IOCtl to the SUPDRV kernel module.
+ */
+ SUPREQHDR Req;
+ Req.u32Cookie = g_u32Cookie;
+ Req.u32SessionCookie= g_u32SessionCookie;
+ Req.cbIn = SUP_IOCTL_RESUME_SUSPENDED_KBDS_SIZE_IN;
+ Req.cbOut = SUP_IOCTL_RESUME_SUSPENDED_KBDS_SIZE_OUT;
+ Req.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.rc = VERR_INTERNAL_ERROR;
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_RESUME_SUSPENDED_KBDS, &Req, SUP_IOCTL_RESUME_SUSPENDED_KBDS_SIZE);
+ if (RT_SUCCESS(rc))
+ rc = Req.rc;
+ return rc;
+#else /* !RT_OS_DARWIN */
+ return VERR_NOT_SUPPORTED;
+#endif
+}
+
+
+SUPR3DECL(int) SUPR3TscDeltaMeasure(RTCPUID idCpu, bool fAsync, bool fForce, uint8_t cRetries, uint8_t cMsWaitRetry)
+{
+ SUPTSCDELTAMEASURE Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_TSC_DELTA_MEASURE_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_TSC_DELTA_MEASURE_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+
+ Req.u.In.cRetries = cRetries;
+ Req.u.In.fAsync = fAsync;
+ Req.u.In.fForce = fForce;
+ Req.u.In.idCpu = idCpu;
+ Req.u.In.cMsWaitRetry = cMsWaitRetry;
+
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_TSC_DELTA_MEASURE, &Req, SUP_IOCTL_TSC_DELTA_MEASURE_SIZE);
+ if (RT_SUCCESS(rc))
+ rc = Req.Hdr.rc;
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPR3ReadTsc(uint64_t *puTsc, uint16_t *pidApic)
+{
+ AssertReturn(puTsc, VERR_INVALID_PARAMETER);
+
+ SUPTSCREAD Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_TSC_READ_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_TSC_READ_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_TSC_READ, &Req, SUP_IOCTL_TSC_READ_SIZE);
+ if (RT_SUCCESS(rc))
+ {
+ rc = Req.Hdr.rc;
+ *puTsc = Req.u.Out.u64AdjustedTsc;
+ if (pidApic)
+ *pidApic = Req.u.Out.idApic;
+ }
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPR3GipSetFlags(uint32_t fOrMask, uint32_t fAndMask)
+{
+ AssertMsgReturn(!(fOrMask & ~SUPGIP_FLAGS_VALID_MASK),
+ ("fOrMask=%#x ValidMask=%#x\n", fOrMask, SUPGIP_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
+ AssertMsgReturn((fAndMask & ~SUPGIP_FLAGS_VALID_MASK) == ~SUPGIP_FLAGS_VALID_MASK,
+ ("fAndMask=%#x ValidMask=%#x\n", fAndMask, SUPGIP_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
+
+ SUPGIPSETFLAGS Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_GIP_SET_FLAGS_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_GIP_SET_FLAGS_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+
+ Req.u.In.fAndMask = fAndMask;
+ Req.u.In.fOrMask = fOrMask;
+
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_GIP_SET_FLAGS, &Req, SUP_IOCTL_GIP_SET_FLAGS_SIZE);
+ if (RT_SUCCESS(rc))
+ rc = Req.Hdr.rc;
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPR3GetHwvirtMsrs(PSUPHWVIRTMSRS pHwvirtMsrs, bool fForceRequery)
+{
+ AssertReturn(pHwvirtMsrs, VERR_INVALID_PARAMETER);
+
+ SUPGETHWVIRTMSRS Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_GET_HWVIRT_MSRS_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_GET_HWVIRT_MSRS_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+
+ Req.u.In.fForce = fForceRequery;
+ Req.u.In.fReserved0 = false;
+ Req.u.In.fReserved1 = false;
+ Req.u.In.fReserved2 = false;
+
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_GET_HWVIRT_MSRS, &Req, SUP_IOCTL_GET_HWVIRT_MSRS_SIZE);
+ if (RT_SUCCESS(rc))
+ {
+ rc = Req.Hdr.rc;
+ *pHwvirtMsrs = Req.u.Out.HwvirtMsrs;
+ }
+ else
+ RT_ZERO(*pHwvirtMsrs);
+ return rc;
+}
+