SUPLib.cpp revision e02da0ade531aac5984e686bc3ce62fc279bb82a
/* $Id$ */
/** @file
* VirtualBox Support Library - Common code.
*/
/*
* Copyright (C) 2006-2007 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* 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.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
/** @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
* tranfer 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 "SUPLibInternal.h"
#include "SUPDrvIOC.h"
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** R0 VMM module name. */
#define VMMR0_NAME "VMMR0"
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
typedef FNCALLVMMR0 *PFNCALLVMMR0;
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** 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 higly volatile and not trust it beyond
* one transaction.
*
* @todo This will probably deserve it's own session or some other good solution...
*/
/** Address of the ring-0 mapping of the GIP. */
/** The physical address of the GIP. */
/** The negotiated cookie. */
uint32_t g_u32Cookie = 0;
/** The negotiated session cookie. */
/** Session handle. */
/** R0 SUP Functions used for resolving referenced to the SUPR0 module. */
static PSUPQUERYFUNCS g_pFunctions;
#ifdef VBOX_WITH_IDT_PATCHING
/** The negotiated interrupt number. */
/** Pointer to the generated code fore calling VMMR0. */
static PFNCALLVMMR0 g_pfnCallVMMR0;
#endif
/** VMMR0 Load Address. */
/** Init counter. */
static unsigned g_cInits = 0;
/** PAGE_ALLOC support indicator. */
static bool g_fSupportsPageAllocLocked = true;
/** Fake mode indicator. (~0 at first, 0 or 1 after first test) */
static uint32_t g_u32FakeMode = ~0;
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
#ifdef VBOX_WITH_IDT_PATCHING
static int supInstallIDTE(void);
#endif
static DECLCALLBACK(int) supLoadModuleResolveImport(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser);
SUPR3DECL(int) SUPInstall(void)
{
return suplibOsInstall();
}
SUPR3DECL(int) SUPUninstall(void)
{
return suplibOsUninstall();
}
{
/*
* Perform some sanity checks.
* (Got some trouble with compile time member alignment assertions.)
*/
/*
* Check if already initialized.
*/
if (ppSession)
*ppSession = g_pSession;
if (g_cInits++ > 0)
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_u32FakeMode == ~0U)
{
else
ASMAtomicCmpXchgU32(&g_u32FakeMode, 0, ~0U);
}
if (RT_UNLIKELY(g_u32FakeMode))
return supInitFake(ppSession);
/**
* Open the support driver.
*/
if (RT_SUCCESS(rc))
{
/*
* Negotiate the cookie.
*/
? 0x00080001
: SUPDRV_IOC_VERSION & 0xffff0000;
if ( RT_SUCCESS(rc)
{
{
/*
* Query the functions.
*/
PSUPQUERYFUNCS pFuncsReq = (PSUPQUERYFUNCS)RTMemAllocZ(SUP_IOCTL_QUERY_FUNCS_SIZE(CookieReq.u.Out.cFunctions));
if (pFuncsReq)
{
rc = suplibOsIOCtl(SUP_IOCTL_QUERY_FUNCS(CookieReq.u.Out.cFunctions), pFuncsReq, SUP_IOCTL_QUERY_FUNCS_SIZE(CookieReq.u.Out.cFunctions));
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
{
if (ppSession)
/*
* Map the GIP into userspace.
* This is an optional feature, so we will ignore any failures here.
*/
if (!g_pSUPGlobalInfoPage)
{
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
{
ASMAtomicCmpXchgPtr((void * volatile *)&g_pSUPGlobalInfoPageR0, (void *)GipMapReq.u.Out.pGipR0, NULL);
}
}
return VINF_SUCCESS;
}
/* bailout */
}
else
rc = VERR_NO_MEMORY;
}
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, MinVersion));
}
}
else
{
if (RT_SUCCESS(rc))
{
LogRel(("Support driver version mismatch: DriverVersion=%#x ClientVersion=%#x rc=%Rrc\n",
if (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));
}
}
suplibOsTerm();
}
g_cInits--;
return rc;
}
/**
* Fake mode init.
*/
{
Log(("SUP: Fake mode!\n"));
static const SUPFUNC s_aFakeFunctions[] =
{
/* name function */
{ "SUPR0ComponentRegisterFactory", 0xefeefffd },
{ "SUPR0ComponentDeregisterFactory", 0xefeefffe },
{ "SUPR0ComponentQueryFactory", 0xefeeffff },
{ "SUPR0ObjRegister", 0xefef0000 },
{ "SUPR0ObjAddRef", 0xefef0001 },
{ "SUPR0ObjRelease", 0xefef0002 },
{ "SUPR0ObjVerifyAccess", 0xefef0003 },
{ "SUPR0LockMem", 0xefef0004 },
{ "SUPR0UnlockMem", 0xefef0005 },
{ "SUPR0ContAlloc", 0xefef0006 },
{ "SUPR0ContFree", 0xefef0007 },
{ "SUPR0MemAlloc", 0xefef0008 },
{ "SUPR0MemGetPhys", 0xefef0009 },
{ "SUPR0MemFree", 0xefef000a },
{ "SUPR0Printf", 0xefef000b },
{ "SUPR0ExecuteCallback", 0xefef000c },
{ "RTMemAlloc", 0xefef000d },
{ "RTMemAllocZ", 0xefef000e },
{ "RTMemFree", 0xefef000f },
{ "RTR0MemObjAddress", 0xefef0010 },
{ "RTR0MemObjAddressR3", 0xefef0011 },
{ "RTR0MemObjAllocPage", 0xefef0012 },
{ "RTR0MemObjAllocPhysNC", 0xefef0013 },
{ "RTR0MemObjAllocLow", 0xefef0014 },
{ "RTR0MemObjFree", 0xefef0015 },
{ "RTR0MemObjGetPagePhysAddr", 0xefef0016 },
{ "RTR0MemObjMapUser", 0xefef0017 },
{ "RTProcSelf", 0xefef0038 },
{ "RTR0ProcHandleSelf", 0xefef0039 },
{ "RTSemEventCreate", 0xefef0018 },
{ "RTSemEventSignal", 0xefef0019 },
{ "RTSemEventWait", 0xefef001a },
{ "RTSemEventWaitNoResume", 0xefef001b },
{ "RTSemEventDestroy", 0xefef001c },
{ "RTSemEventMultiCreate", 0xefef001d },
{ "RTSemEventMultiSignal", 0xefef001e },
{ "RTSemEventMultiReset", 0xefef001f },
{ "RTSemEventMultiWait", 0xefef0020 },
{ "RTSemEventMultiWaitNoResume", 0xefef0021 },
{ "RTSemEventMultiDestroy", 0xefef0022 },
{ "RTSemFastMutexCreate", 0xefef0023 },
{ "RTSemFastMutexDestroy", 0xefef0024 },
{ "RTSemFastMutexRequest", 0xefef0025 },
{ "RTSemFastMutexRelease", 0xefef0026 },
{ "RTSpinlockCreate", 0xefef0027 },
{ "RTSpinlockDestroy", 0xefef0028 },
{ "RTSpinlockAcquire", 0xefef0029 },
{ "RTSpinlockRelease", 0xefef002a },
{ "RTSpinlockAcquireNoInts", 0xefef002b },
{ "RTSpinlockReleaseNoInts", 0xefef002c },
{ "RTTimeNanoTS", 0xefef002d },
{ "RTTimeMillieTS", 0xefef002e },
{ "RTTimeSystemNanoTS", 0xefef002f },
{ "RTTimeSystemMillieTS", 0xefef0030 },
{ "RTThreadNativeSelf", 0xefef0031 },
{ "RTThreadSleep", 0xefef0032 },
{ "RTThreadYield", 0xefef0033 },
{ "RTLogDefaultInstance", 0xefef0034 },
{ "RTLogRelDefaultInstance", 0xefef0035 },
{ "RTLogSetDefaultInstanceThread", 0xefef0036 },
{ "RTLogLogger", 0xefef0037 },
{ "RTLogLoggerEx", 0xefef0038 },
{ "RTLogLoggerExV", 0xefef0039 },
{ "AssertMsg1", 0xefef003a },
{ "AssertMsg2", 0xefef003b },
};
/* fake r0 functions. */
g_pFunctions = (PSUPQUERYFUNCS)RTMemAllocZ(SUP_IOCTL_QUERY_FUNCS_SIZE(RT_ELEMENTS(s_aFakeFunctions)));
if (g_pFunctions)
{
if (ppSession)
*ppSession = g_pSession;
#ifdef VBOX_WITH_IDT_PATCHING
#endif
/* fake the GIP. */
if (g_pSUPGlobalInfoPage)
{
/* the page is supposed to be invalid, so don't set the magic. */
return VINF_SUCCESS;
}
g_pFunctions = NULL;
}
return VERR_NO_MEMORY;
}
{
/*
* Verify state.
*/
if (g_cInits == 0)
return VERR_WRONG_ORDER;
{
/*
* NULL the GIP pointer.
*/
if (g_pSUPGlobalInfoPage)
{
/* just a little safe guard against threads using the page. */
RTThreadSleep(50);
}
/*
* Close the support driver.
*/
int rc = suplibOsTerm();
if (rc)
return rc;
g_u32Cookie = 0;
g_u32SessionCookie = 0;
#ifdef VBOX_WITH_IDT_PATCHING
g_u8Interrupt = 3;
#endif
g_cInits = 0;
}
else
g_cInits--;
return 0;
}
{
/* fake */
if (RT_UNLIKELY(g_u32FakeMode))
#ifdef RT_ARCH_AMD64
return SUPPAGINGMODE_AMD64_GLOBAL_NX;
#else
return SUPPAGINGMODE_32_BIT_GLOBAL;
#endif
/*
* Issue IOCtl to the SUPDRV kernel module.
*/
if ( RT_FAILURE(rc)
{
}
}
/**
* For later.
*/
static int supCallVMMR0ExFake(PVMR0 pVMR0, unsigned uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
{
return VERR_NOT_SUPPORTED;
}
{
return suplibOsIOCtlFast(SUP_IOCTL_FAST_DO_NOP);
return VERR_INTERNAL_ERROR;
}
SUPR3DECL(int) SUPCallVMMR0Ex(PVMR0 pVMR0, unsigned uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
{
/*
* The following operations don't belong here.
*/
&& uOperation != SUP_VMMR0_DO_NOP,
("%#x\n", uOperation),
/* fake */
if (RT_UNLIKELY(g_u32FakeMode))
int rc;
if (!pReqHdr)
{
/* no data. */
if (RT_SUCCESS(rc))
}
{
if (RT_SUCCESS(rc))
}
else /** @todo may have to remove the size limits one this request... */
return rc;
}
{
#if defined(VBOX_WITH_IDT_PATCHING)
#else
/*
* The following operations don't belong here.
*/
&& uOperation != SUP_VMMR0_DO_NOP,
("%#x\n", uOperation),
#endif
}
{
if (RT_UNLIKELY(g_u32FakeMode))
return VINF_SUCCESS;
if (RT_SUCCESS(rc))
return rc;
}
{
/*
* Validate.
*/
#ifdef RT_OS_WINDOWS
/*
* Temporary hack for windows until we've sorted out the
* locked memory that doesn't need to be accessible from kernel space.
*/
#else
/*
* Call OS specific worker.
*/
#endif
}
{
/*
* Validate.
*/
#ifdef RT_OS_WINDOWS
/*
* Temporary hack for windows, see above.
*/
#else
/*
* Call OS specific worker.
*/
#endif
}
{
/*
* Validate.
*/
AssertMsg(RT_ALIGN_P(pvStart, PAGE_SIZE) == pvStart, ("pvStart (%p) must be page aligned\n", pvStart));
/* fake */
if (RT_UNLIKELY(g_u32FakeMode))
{
while (iPage-- > 0)
return VINF_SUCCESS;
}
/*
* Issue IOCtl to the SUPDRV kernel module.
*/
int rc;
{
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
{
{
}
}
}
else
return rc;
}
{
/*
* Validate.
*/
AssertMsg(RT_ALIGN_P(pvStart, PAGE_SIZE) == pvStart, ("pvStart (%p) must be page aligned\n", pvStart));
/* fake */
if (RT_UNLIKELY(g_u32FakeMode))
return VINF_SUCCESS;
/*
* Issue IOCtl to the SUPDRV kernel module.
*/
if (RT_SUCCESS(rc))
return rc;
}
{
}
/**
* Fallback for SUPPageAllocLockedEx on systems where RTR0MemObjPhysAllocNC isn't supported.
*/
{
if (RT_SUCCESS(rc))
{
if (!paPages)
if (RT_FAILURE(rc))
}
return rc;
}
{
/*
* Validate.
*/
/* fake */
if (RT_UNLIKELY(g_u32FakeMode))
{
if (!*ppvPages)
return VERR_NO_MEMORY;
if (paPages)
{
}
return VINF_SUCCESS;
}
/* use fallback? */
/*
* Issue IOCtl to the SUPDRV kernel module.
*/
int rc;
if (pReq)
{
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
if (paPages)
{
}
}
else if (rc == VERR_NOT_SUPPORTED)
{
g_fSupportsPageAllocLocked = false;
}
}
}
else
return rc;
}
{
/*
* Validate.
*/
/* fake */
if (RT_UNLIKELY(g_u32FakeMode))
{
return VINF_SUCCESS;
}
/*
* Issue IOCtl to the SUPDRV kernel module.
*/
int rc;
{
if (RT_SUCCESS(rc))
}
else
{
/* fallback */
if (RT_SUCCESS(rc))
}
return rc;
}
{
}
{
/*
* Validate.
*/
*pHCPhys = NIL_RTHCPHYS;
if (pR0Ptr)
*pR0Ptr = NIL_RTR0PTR;
/* fake */
if (RT_UNLIKELY(g_u32FakeMode))
{
if (pR0Ptr)
if (pHCPhys)
return pv;
}
/*
* Issue IOCtl to the SUPDRV kernel module.
*/
if ( RT_SUCCESS(rc)
{
if (pR0Ptr)
}
return NULL;
}
{
/*
* Validate.
*/
if (!pv)
return VINF_SUCCESS;
/* fake */
if (RT_UNLIKELY(g_u32FakeMode))
{
return VINF_SUCCESS;
}
/*
* Issue IOCtl to the SUPDRV kernel module.
*/
if (RT_SUCCESS(rc))
return rc;
}
{
/*
* Validate.
*/
AssertMsgReturn(cPages > 0 && cPages < 256, ("cPages=%d must be > 0 and < 256\n", cPages), VERR_INVALID_PARAMETER);
/* fake */
if (RT_UNLIKELY(g_u32FakeMode))
{
if (!*ppvPages)
return VERR_NO_LOW_MEMORY;
/* fake physical addresses. */
while (iPage-- > 0)
return VINF_SUCCESS;
}
/*
* Issue IOCtl to the SUPDRV kernel module.
*/
int rc;
if (pReq)
{
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
{
if (ppvPagesR0)
if (paPages)
{
}
}
}
else
return rc;
}
{
/*
* Validate.
*/
if (!pv)
return VINF_SUCCESS;
/* fake */
if (RT_UNLIKELY(g_u32FakeMode))
{
return VINF_SUCCESS;
}
/*
* Issue IOCtl to the SUPDRV kernel module.
*/
if (RT_SUCCESS(rc))
return rc;
}
{
/*
* Load the module.
* If it's VMMR0.r0 we need to install the IDTE.
*/
#ifdef VBOX_WITH_IDT_PATCHING
if ( RT_SUCCESS(rc)
{
rc = supInstallIDTE();
if (RT_FAILURE(rc))
}
#endif /* VBOX_WITH_IDT_PATCHING */
return rc;
}
#ifdef VBOX_WITH_IDT_PATCHING
/**
* Generates the code for calling the interrupt gate.
*
* @returns VBox status code.
* g_pfnCallVMMR0 is changed on success.
* @param u8Interrupt The interrupt number.
*/
{
/*
* Allocate memory.
*/
/*
* Generate the code.
*/
#ifdef RT_ARCH_AMD64
/*
* reg params:
* <GCC> <MSC> <argument>
* rdi rcx pVMR0
* esi edx uOperation
* rdx r8 pvArg
*
* eax eax [g_u32Gookie]
*/
*pb++ = u8Interrupt;
#else
/*
* x86 stack:
* 0 saved esi
* 0 4 ret
* 4 8 pVM
* 8 c uOperation
* c 10 pvArg
*/
*pb++ = 0x44;
*pb++ = 0x24;
*pb++ = 0x54;
*pb++ = 0x24;
*pb++ = 0x4c;
*pb++ = 0x24;
*pb++ = u8Interrupt;
#endif
return VINF_SUCCESS;
}
/**
* Installs the IDTE patch.
*
* @return VBox status code.
*/
static int supInstallIDTE(void)
{
/* already installed? */
return VINF_SUCCESS;
int rc = VINF_SUCCESS;
const unsigned cCpus = RTSystemProcessorGetCount();
if (cCpus <= 1)
{
/* UNI */
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
{
}
}
else
{
/* SMP */
unsigned cCpusPatched = 0;
for (int i = 0; i < 64; i++)
{
/* Skip absent and inactive processors. */
if (!(u64Mask & u64AffMaskPatched))
continue;
/* Change CPU */
if (RT_FAILURE(rc2))
{
u64AffMaskPatched &= ~u64Mask;
continue;
}
/* Patch the CPU. */
if (RT_SUCCESS(rc2))
if (RT_SUCCESS(rc2))
{
if (!cCpusPatched)
{
if (RT_FAILURE(rc2))
{
}
}
else
cCpusPatched++;
}
else
{
if (RT_SUCCESS(rc))
}
}
/* Fail if no CPUs was patched! */
/* Ignore failures if a CPU was patched. */
rc = VINF_SUCCESS;
if (RT_SUCCESS(rc))
{
}
else
{
}
}
return rc;
}
#endif /* VBOX_WITH_IDT_PATCHING */
/**
* Resolve an external symbol during RTLdrGetBits().
*
* @returns VBox status code.
* @param hLdrMod The loader module handle.
* @param pszModule Module name.
* @param pszSymbol Symbol name, NULL if uSymbol should be used.
* @param uSymbol Symbol ordinal, ~0 if pszSymbol should be used.
* @param pValue Where to store the symbol value (address).
* @param pvUser User argument.
*/
{
/*
* Only SUPR0 and VMMR0.r0
*/
if ( pszModule
&& *pszModule
{
AssertMsgFailed(("%s is importing from %s! (expected 'SUPR0.dll' or 'VMMR0.r0', case-sensitiv)\n", pvUser, pszModule));
return VERR_SYMBOL_NOT_FOUND;
}
/*
* No ordinals.
*/
if (pszSymbol < (const char*)0x10000)
{
return VERR_SYMBOL_NOT_FOUND;
}
/*
* Lookup symbol.
*/
/* skip the 64-bit ELF import prefix first. */
/*
* Check the VMMR0.r0 module if loaded.
*/
/** @todo call the SUPLoadModule caller.... */
/** @todo proper reference counting and such. */
if (g_pvVMMR0 != NIL_RTR0PTR)
{
void *pvValue;
{
return VINF_SUCCESS;
}
}
/* iterate the function table. */
while (c-- > 0)
{
{
return VINF_SUCCESS;
}
pFunc++;
}
/*
* The GIP.
*/
/** @todo R0 mapping? */
if ( pszSymbol
{
return VINF_SUCCESS;
}
/*
* Despair.
*/
while (c-- > 0)
{
pFunc++;
}
if (g_u32FakeMode)
{
*pValue = 0xdeadbeef;
return VINF_SUCCESS;
}
return VERR_SYMBOL_NOT_FOUND;
}
/** Argument package for supLoadModuleCalcSizeCB. */
typedef struct SUPLDRCALCSIZEARGS
{
/**
* Callback used to calculate the image size.
* @return VINF_SUCCESS
*/
static DECLCALLBACK(int) supLoadModuleCalcSizeCB(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
{
&& *pszSymbol
{
}
return VINF_SUCCESS;
}
/** Argument package for supLoadModuleCreateTabsCB. */
typedef struct SUPLDRCREATETABSARGS
{
char *pszBase;
char *psz;
/**
* Callback used to calculate the image size.
* @return VINF_SUCCESS
*/
static DECLCALLBACK(int) supLoadModuleCreateTabsCB(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
{
&& *pszSymbol
{
}
return VINF_SUCCESS;
}
/**
* Worker for SUPLoadModule().
*
* @returns VBox status code.
* @param pszFilename Name of the VMMR0 image file
*/
{
/*
* Validate input.
*/
*ppvImageBase = NULL;
/*
* Open image file and figure its size.
*/
if (!RT_SUCCESS(rc))
return rc;
if (RT_SUCCESS(rc))
{
/*
* Open the R0 image.
*/
if (!g_u32FakeMode)
{
if (RT_SUCCESS(rc))
}
else
{
}
if ( RT_SUCCESS(rc)
{
/*
* We need to load it.
* Allocate memory for the image bits.
*/
if (pLoadReq)
{
/*
* Get the image bits.
*/
supLoadModuleResolveImport, (void *)pszModule);
if (RT_SUCCESS(rc))
{
/*
* Get the entry points.
*/
RTUINTPTR VMMR0EntryInt = 0;
RTUINTPTR VMMR0EntryFast = 0;
RTUINTPTR VMMR0EntryEx = 0;
RTUINTPTR ModuleInit = 0;
RTUINTPTR ModuleTerm = 0;
if (fIsVMMR0)
{
rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "VMMR0EntryInt", &VMMR0EntryInt);
if (RT_SUCCESS(rc))
rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "VMMR0EntryFast", &VMMR0EntryFast);
if (RT_SUCCESS(rc))
rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "VMMR0EntryEx", &VMMR0EntryEx);
}
if (RT_SUCCESS(rc))
{
int rc2 = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "ModuleInit", &ModuleInit);
if (RT_FAILURE(rc2))
ModuleInit = 0;
rc2 = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "ModuleTerm", &ModuleTerm);
if (RT_FAILURE(rc2))
ModuleTerm = 0;
}
if (RT_SUCCESS(rc))
{
/*
* Create the symbol and string tables.
*/
if (RT_SUCCESS(rc))
{
AssertRelease((size_t)(CreateArgs.pSym - (PSUPLDRSYM)&pLoadReq->u.In.achImage[offSymTab]) <= CalcArgs.cSymbols);
/*
* Upload the image.
*/
if (fIsVMMR0)
{
}
else
if (!g_u32FakeMode)
{
if (RT_SUCCESS(rc))
}
else
rc = VINF_SUCCESS;
if ( RT_SUCCESS(rc)
)
{
LogRel(("SUP: Loaded %s (%s) at %#p - ModuleInit at %RTptr and ModuleTerm at %RTptr\n", pszModule, pszFilename,
if (fIsVMMR0)
{
LogRel(("SUP: VMMR0EntryEx located at %RTptr, VMMR0EntryFast at %RTptr and VMMR0EntryInt at %RTptr\n",
}
#ifdef RT_OS_WINDOWS
#endif
return VINF_SUCCESS;
}
}
}
}
}
else
{
AssertMsgFailed(("failed to allocated %d bytes for SUPLDRLOAD_IN structure!\n", SUP_IOCTL_LDR_LOAD_SIZE(cbImage)));
}
}
else if (RT_SUCCESS(rc))
{
if (fIsVMMR0)
#ifdef RT_OS_WINDOWS
#endif
}
}
return rc;
}
{
/* fake */
if (RT_UNLIKELY(g_u32FakeMode))
{
#ifdef VBOX_WITH_IDT_PATCHING
g_u8Interrupt = 3;
RTMemExecFree(*(void **)&g_pfnCallVMMR0);
#endif
return VINF_SUCCESS;
}
#ifdef VBOX_WITH_IDT_PATCHING
/*
* There is one special module. When this is freed we'll
* free the IDT entry that goes with it.
*
* Note that we don't keep count of VMMR0.r0 loads here, so the
* first unload will free it.
*/
&& g_u8Interrupt != 3)
{
if (RT_SUCCESS(rc))
g_u8Interrupt = 3;
RTMemExecFree(*(void **)&g_pfnCallVMMR0);
}
#endif /* VBOX_WITH_IDT_PATCHING */
/*
* Free the requested module.
*/
if (RT_SUCCESS(rc))
if ( RT_SUCCESS(rc)
return rc;
}
{
/* fake */
if (RT_UNLIKELY(g_u32FakeMode))
{
return VINF_SUCCESS;
}
/*
* Do ioctl.
*/
return VERR_SYMBOL_NOT_FOUND;
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
return rc;
}
{
void *pvImageBase;
}
SUPR3DECL(int) SUPUnloadVMM(void)
{
return SUPFreeModule((void*)g_pvVMMR0);
}
{
if (g_pSUPGlobalInfoPage)
{
return VINF_SUCCESS;
}
*pHCPhys = NIL_RTHCPHYS;
return VERR_WRONG_ORDER;
}