SUPLib.cpp revision 637f7ac058e8c4d9c93165c533a9441e397051b1
2c5ce90c334a2d0f18474e85c93b424b6ec9daaaAdam Moore * VBox host drivers - Ring-0 support drivers - Shared code:
4778ff543a041ac356d6e661cc9b66c3fafa2092Adam Moore * Support library that implements the basic lowlevel OS interfaces
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore * Copyright (C) 2006 InnoTek Systemberatung GmbH
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore * This file is part of VirtualBox Open Source Edition (OSE), as
87d6b0a14cce52c4faa4b78fc9878eb553dab0d5Adam Moore * available from http://www.virtualbox.org. This file is free software;
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore * you can redistribute it and/or modify it under the terms of the GNU
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore * General Public License as published by the Free Software Foundation,
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore * distribution. VirtualBox OSE is distributed in the hope that it will
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore * be useful, but WITHOUT ANY WARRANTY of any kind.
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore * If you received this file as part of a commercial VirtualBox
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore * distribution, then only the terms of your commercial VirtualBox
87d6b0a14cce52c4faa4b78fc9878eb553dab0d5Adam Moore * license agreement apply instead of the previous paragraph.
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore/** @page pg_sup SUP - The Support Library
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore * The support library is responsible for providing facilities to load
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore * VMM Host Ring-0 code, to call Host VMM Ring-0 code from Ring-3 Host
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore * code, and to pin down physical memory.
d4dbc3afb5bb9cfd13490b358dc37bf951104ca7Adam Moore * The VMM Host Ring-0 code can be combined in the support driver if
9fb523cf517ad4d6a53ae9f461d672cba63835d2Adam Moore * permitted by kernel module license policies. If it is not combined
9fb523cf517ad4d6a53ae9f461d672cba63835d2Adam Moore * it will be externalized in a Win32 PE binary and will use the PDM
91ff24e65531ce8bf171340d9384182f8c168af3Adam Moore * PE loader to load it into memory.
91ff24e65531ce8bf171340d9384182f8c168af3Adam Moore * The Ring-0 calling is done thru a generic SUP interface which will
91ff24e65531ce8bf171340d9384182f8c168af3Adam Moore * tranfer an argument set and call a predefined entry point in the Host
91ff24e65531ce8bf171340d9384182f8c168af3Adam Moore * VMM Ring-0 code.
91ff24e65531ce8bf171340d9384182f8c168af3Adam Moore * See @ref grp_sup "SUP - Support APIs" for API details.
91ff24e65531ce8bf171340d9384182f8c168af3Adam Moore/*******************************************************************************
91ff24e65531ce8bf171340d9384182f8c168af3Adam Moore* Header Files *
d4dbc3afb5bb9cfd13490b358dc37bf951104ca7Adam Moore*******************************************************************************/
d4dbc3afb5bb9cfd13490b358dc37bf951104ca7Adam Moore/*******************************************************************************
d4dbc3afb5bb9cfd13490b358dc37bf951104ca7Adam Moore* Defined Constants And Macros *
d4dbc3afb5bb9cfd13490b358dc37bf951104ca7Adam Moore*******************************************************************************/
87d6b0a14cce52c4faa4b78fc9878eb553dab0d5Adam Moore/** R0 VMM module name. */
d4dbc3afb5bb9cfd13490b358dc37bf951104ca7Adam Moore/*******************************************************************************
d4dbc3afb5bb9cfd13490b358dc37bf951104ca7Adam Moore* Structures and Typedefs *
d4dbc3afb5bb9cfd13490b358dc37bf951104ca7Adam Moore*******************************************************************************/
d4dbc3afb5bb9cfd13490b358dc37bf951104ca7Adam Mooretypedef DECLCALLBACK(int) FNCALLVMMR0(PVMR0 pVMR0, unsigned uOperation, void *pvArg);
d4dbc3afb5bb9cfd13490b358dc37bf951104ca7Adam Moore/*******************************************************************************
87d6b0a14cce52c4faa4b78fc9878eb553dab0d5Adam Moore* Global Variables *
d4dbc3afb5bb9cfd13490b358dc37bf951104ca7Adam Moore*******************************************************************************/
d4dbc3afb5bb9cfd13490b358dc37bf951104ca7Adam Moore/** Pointer to the Global Information Page.
d4dbc3afb5bb9cfd13490b358dc37bf951104ca7Adam Moore * This pointer is valid as long as SUPLib has a open session. Anyone using
d4dbc3afb5bb9cfd13490b358dc37bf951104ca7Adam Moore * the page must treat this pointer as higly volatile and not trust it beyond
d4dbc3afb5bb9cfd13490b358dc37bf951104ca7Adam Moore * one transaction.
d4dbc3afb5bb9cfd13490b358dc37bf951104ca7Adam Moore * @todo This will probably deserve it's own session or some other good solution...
d4dbc3afb5bb9cfd13490b358dc37bf951104ca7Adam MooreDECLEXPORT(PCSUPGLOBALINFOPAGE) g_pSUPGlobalInfoPage;
87d6b0a14cce52c4faa4b78fc9878eb553dab0d5Adam Moore/** Address of the ring-0 mapping of the GIP. */
d4dbc3afb5bb9cfd13490b358dc37bf951104ca7Adam Moorestatic PCSUPGLOBALINFOPAGE g_pSUPGlobalInfoPageR0;
d4dbc3afb5bb9cfd13490b358dc37bf951104ca7Adam Moore/** The physical address of the GIP. */
d4dbc3afb5bb9cfd13490b358dc37bf951104ca7Adam Moorestatic RTHCPHYS g_HCPhysSUPGlobalInfoPage = NIL_RTHCPHYS;
d4dbc3afb5bb9cfd13490b358dc37bf951104ca7Adam Moore/** The negotiated cookie. */
4390434761f176b0f8d7a71c00a6e0141aa1752cAdam Moore/** The negotiated session cookie. */
d4dbc3afb5bb9cfd13490b358dc37bf951104ca7Adam Moore/** Session handle. */
d4dbc3afb5bb9cfd13490b358dc37bf951104ca7Adam Moore/** R0 SUP Functions used for resolving referenced to the SUPR0 module. */
d4dbc3afb5bb9cfd13490b358dc37bf951104ca7Adam Moore/** The negotiated interrupt number. */
d4dbc3afb5bb9cfd13490b358dc37bf951104ca7Adam Moore/** Pointer to the generated code fore calling VMMR0. */
d4dbc3afb5bb9cfd13490b358dc37bf951104ca7Adam Moore/** VMMR0 Load Address. */
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore/** Init counter. */
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moorestatic unsigned g_cInits = 0;
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore/** Fake mode indicator. (~0 at first, 0 or 1 after first test) */
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore/*******************************************************************************
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore* Internal Functions *
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore*******************************************************************************/
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moorestatic int supInitFake(PSUPDRVSESSION *ppSession);
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moorestatic int supLoadModule(const char *pszFilename, const char *pszModule, void **ppvImageBase);
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moorestatic int supInstallIDTE(void);
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moorestatic DECLCALLBACK(int) supLoadModuleResolveImport(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser);
efa57736d44cf446f1661497a8645bd388b493fbAdam MooreSUPR3DECL(int) SUPInit(PSUPDRVSESSION *ppSession /* NULL */, size_t cbReserve /* 0 */)
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore * Perform some sanity checks.
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore * (Got some trouble with compile time member alignment assertions.)
ba2701ee03e94104edf19911ee0989f8cee11088Adam Moore Assert(!(RT_OFFSETOF(SUPGLOBALINFOPAGE, u64NanoTSLastUpdateHz) & 0x7));
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore Assert(!(RT_OFFSETOF(SUPGLOBALINFOPAGE, aCPUs) & 0x1f));
ba2701ee03e94104edf19911ee0989f8cee11088Adam Moore Assert(!(RT_OFFSETOF(SUPGLOBALINFOPAGE, aCPUs[1]) & 0x1f));
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore Assert(!(RT_OFFSETOF(SUPGLOBALINFOPAGE, aCPUs[0].u64NanoTS) & 0x7));
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore Assert(!(RT_OFFSETOF(SUPGLOBALINFOPAGE, aCPUs[0].u64TSC) & 0x7));
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore Assert(!(RT_OFFSETOF(SUPGLOBALINFOPAGE, aCPUs[0].u64CpuHz) & 0x7));
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore * Check if already initialized.
23209f57fce338501bc1dc828a991d103732b92fAdam Moore * Check for fake mode.
23209f57fce338501bc1dc828a991d103732b92fAdam Moore * Fake mode is used when we're doing smoke testing and debugging.
23209f57fce338501bc1dc828a991d103732b92fAdam Moore * It's also useful on platforms where we haven't root access or which
23209f57fce338501bc1dc828a991d103732b92fAdam Moore * we haven't ported the support driver to.
e0a1d83ad86620d8fd4e2bfa3c4ec5c0944a002aAdam Moore * Open the support driver.
3395e5fc071521d4e6b258ef4c7c0ef38601b94eAdam Moore * Negotiate the cookie.
3395e5fc071521d4e6b258ef4c7c0ef38601b94eAdam Moore In.u32MinVersion = SUPDRVIOC_VERSION & 0xffff0000;
0dca577a07715960da42d47787eecc25b285182fAdam Moore rc = suplibOsIOCtl(SUP_IOCTL_COOKIE, &In, sizeof(In), &Out, sizeof(Out));
0dca577a07715960da42d47787eecc25b285182fAdam Moore if ( (Out.u32SessionVersion & 0xffff0000) == (SUPDRVIOC_VERSION & 0xffff0000)
3395e5fc071521d4e6b258ef4c7c0ef38601b94eAdam Moore * Query the functions.
3395e5fc071521d4e6b258ef4c7c0ef38601b94eAdam Moore unsigned cbFuncsOut = RT_OFFSETOF(SUPQUERYFUNCS_OUT, aFunctions[Out.cFunctions]);
3395e5fc071521d4e6b258ef4c7c0ef38601b94eAdam Moore PSUPQUERYFUNCS_OUT pFuncsOut = (PSUPQUERYFUNCS_OUT)RTMemAllocZ(cbFuncsOut);
3395e5fc071521d4e6b258ef4c7c0ef38601b94eAdam Moore rc = suplibOsIOCtl(SUP_IOCTL_QUERY_FUNCS, &FuncsIn, sizeof(FuncsIn), pFuncsOut, cbFuncsOut);
3395e5fc071521d4e6b258ef4c7c0ef38601b94eAdam Moore * Map the GIP into userspace.
3395e5fc071521d4e6b258ef4c7c0ef38601b94eAdam Moore * This is an optional feature, so we will ignore any failures here.
3395e5fc071521d4e6b258ef4c7c0ef38601b94eAdam Moore rc = suplibOsIOCtl(SUP_IOCTL_GIP_MAP, &GipIn, sizeof(GipIn), &GipOut, sizeof(GipOut));
3395e5fc071521d4e6b258ef4c7c0ef38601b94eAdam Moore AssertRelease(GipOut.pGipR3->u32Magic == SUPGLOBALINFOPAGE_MAGIC);
3395e5fc071521d4e6b258ef4c7c0ef38601b94eAdam Moore AssertRelease(GipOut.pGipR3->u32Version >= SUPGLOBALINFOPAGE_VERSION);
3395e5fc071521d4e6b258ef4c7c0ef38601b94eAdam Moore ASMAtomicXchgSize(&g_HCPhysSUPGlobalInfoPage, GipOut.HCPhysGip);
3395e5fc071521d4e6b258ef4c7c0ef38601b94eAdam Moore ASMAtomicCmpXchgPtr((void * volatile *)&g_pSUPGlobalInfoPage, (void *)GipOut.pGipR3, NULL);
3395e5fc071521d4e6b258ef4c7c0ef38601b94eAdam Moore ASMAtomicCmpXchgPtr((void * volatile *)&g_pSUPGlobalInfoPageR0, (void *)GipOut.pGipR0, NULL);
return rc;
LogRel(("Support driver version mismatch: SessionVersion=%#x DriverVersion=%#x ClientVersion=%#x\n",
suplibOsTerm();
g_cInits--;
return rc;
g_pFunctions = (PSUPQUERYFUNCS_OUT)RTMemAllocZ(RT_OFFSETOF(SUPQUERYFUNCS_OUT, aFunctions[RT_ELEMENTS(s_aFakeFunctions)]));
if (g_pFunctions)
if (ppSession)
#ifndef VBOX_WITHOUT_IDT_PATCHING
if (g_pSUPGlobalInfoPage)
return VINF_SUCCESS;
return VERR_NO_MEMORY;
if (g_cInits == 0)
return VERR_WRONG_ORDER;
if (g_pSUPGlobalInfoPage)
if (rc)
return rc;
g_u32Cookie = 0;
g_u32SessionCookie = 0;
#ifndef VBOX_WITHOUT_IDT_PATCHING
g_cInits = 0;
g_cInits--;
int rc;
if (!g_u32FakeMode)
return rc;
#ifndef VBOX_WITHOUT_IDT_PATCHING
int rc;
return rc;
AssertMsg(RT_ALIGN_P(pvStart, PAGE_SIZE) == pvStart, ("pvStart (%p) must be page aligned\n", pvStart));
AssertMsg(RT_ALIGN_Z(cbMemory, PAGE_SIZE) == cbMemory, ("cbMemory (%#zx) must be page aligned\n", cbMemory));
int rc;
if (!g_u32FakeMode)
if (!pOut)
return VERR_NO_TMP_MEMORY;
rc = suplibOsIOCtl(SUP_IOCTL_PINPAGES, &In, sizeof(In), pOut, RT_OFFSETOF(SUPPINPAGES_OUT, aPages[cbMemory >> PAGE_SHIFT]));
while (iPage-- > 0)
return rc;
AssertMsg(RT_ALIGN_P(pvStart, PAGE_SIZE) == pvStart, ("pvStart (%p) must be page aligned\n", pvStart));
int rc;
if (!g_u32FakeMode)
return rc;
AssertMsg(cb > 64 && cb < PAGE_SIZE * 256, ("cb=%d must be > 64 and < %d (256 pages)\n", cb, PAGE_SIZE * 256));
if (pR0Ptr)
int rc;
if (!g_u32FakeMode)
if (pR0Ptr)
return NULL;
if (!pv)
return VINF_SUCCESS;
int rc;
if (!g_u32FakeMode)
return rc;
int rc;
if (!g_u32FakeMode)
if (pOut)
if (ppvPagesR0)
#ifdef VBOX_STRICT
for (unsigned i = 0; i < cPages; i++)
while (iPage-- > 0)
return rc;
if (!pv)
return VINF_SUCCESS;
int rc;
if (!g_u32FakeMode)
return rc;
if (cPages == 0)
return VERR_INVALID_PARAMETER;
if (!ppvPages)
return VERR_INVALID_PARAMETER;
if (!pvPages)
return VINF_SUCCESS;
#ifndef VBOX_WITHOUT_IDT_PATCHING
return rc;
#ifndef VBOX_WITHOUT_IDT_PATCHING
#ifdef __AMD64__
return VINF_SUCCESS;
static int supInstallIDTE(void)
return VINF_SUCCESS;
unsigned cCpusPatched = 0;
if (!cCpusPatched)
cCpusPatched++;
return rc;
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;
return VERR_SYMBOL_NOT_FOUND;
return VINF_SUCCESS;
pFunc++;
void *pvValue;
return VINF_SUCCESS;
if ( pszSymbol
return VINF_SUCCESS;
pFunc++;
return VERR_SYMBOL_NOT_FOUND;
typedef struct SUPLDRCALCSIZEARGS
static DECLCALLBACK(int) supLoadModuleCalcSizeCB(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
&& *pszSymbol
return VINF_SUCCESS;
typedef struct SUPLDRCREATETABSARGS
char *pszBase;
char *psz;
static DECLCALLBACK(int) supLoadModuleCreateTabsCB(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
&& *pszSymbol
return VINF_SUCCESS;
return rc;
if (!g_u32FakeMode)
if (pIn)
rc = RTLdrGetSymbolEx(hLdrMod, &pIn->achImage[0], (uintptr_t)OpenOut.pvImageBase, "VMMR0Entry", &VMMR0Entry);
rc = RTLdrGetSymbolEx(hLdrMod, &pIn->achImage[0], (uintptr_t)OpenOut.pvImageBase, "ModuleInit", &ModuleInit);
ModuleInit = 0;
rc = RTLdrGetSymbolEx(hLdrMod, &pIn->achImage[0], (uintptr_t)OpenOut.pvImageBase, "ModuleTerm", &ModuleTerm);
ModuleTerm = 0;
AssertRelease((size_t)(CreateArgs.pSym - (PSUPLDRSYM)&pIn->achImage[offSymTab]) <= CalcArgs.cSymbols);
if (fIsVMMR0)
if (!g_u32FakeMode)
if (fIsVMMR0)
return VINF_SUCCESS;
return rc;
if (g_u32FakeMode)
#ifndef VBOX_WITHOUT_IDT_PATCHING
return VINF_SUCCESS;
#ifndef VBOX_WITHOUT_IDT_PATCHING
int rc = 0;
if (!g_u32FakeMode)
return rc;
int rc;
return rc;
void *pvImageBase;
if (g_pSUPGlobalInfoPage)
return VINF_SUCCESS;
return VERR_WRONG_ORDER;