SUPLib.cpp revision 1b396f7f5a76d66e62fc9d8e66dcbe8e7bf72039
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * VirtualBox Support Library - Common code.
9496b6f77d66eb89f088668752b8838d578d6e10vboxsync * Copyright (C) 2006-2010 Oracle Corporation
9496b6f77d66eb89f088668752b8838d578d6e10vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
9496b6f77d66eb89f088668752b8838d578d6e10vboxsync * available from http://www.virtualbox.org. This file is free software;
9496b6f77d66eb89f088668752b8838d578d6e10vboxsync * you can redistribute it and/or modify it under the terms of the GNU
9496b6f77d66eb89f088668752b8838d578d6e10vboxsync * General Public License (GPL) as published by the Free Software
9496b6f77d66eb89f088668752b8838d578d6e10vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * The contents of this file may alternatively be used under the terms
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * of the Common Development and Distribution License Version 1.0
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
332d68e9666b04a5aa788a586d9f4c6b1f19c700vboxsync * VirtualBox OSE distribution, in which case the provisions of the
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * CDDL are applicable instead of those of the GPL.
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * You may elect to license modified versions of this file under the
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * terms and conditions of either the GPL or the CDDL or both.
e32fab83316e8fae9d8498539a3510320f610af6vboxsync/** @page pg_sup SUP - The Support Library
e32fab83316e8fae9d8498539a3510320f610af6vboxsync * The support library is responsible for providing facilities to load
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * VMM Host Ring-0 code, to call Host VMM Ring-0 code from Ring-3 Host
f4ccb18a71e0e531719734918583f84fbc72ebfevboxsync * code, to pin down physical memory, and more.
cfd41a3683178a30bac4417128b4673806653797vboxsync * The VMM Host Ring-0 code can be combined in the support driver if
cfd41a3683178a30bac4417128b4673806653797vboxsync * permitted by kernel module license policies. If it is not combined
cfd41a3683178a30bac4417128b4673806653797vboxsync * it will be externalized in a .r0 module that will be loaded using
cfd41a3683178a30bac4417128b4673806653797vboxsync * the IPRT loader.
cfd41a3683178a30bac4417128b4673806653797vboxsync * The Ring-0 calling is done thru a generic SUP interface which will
cfd41a3683178a30bac4417128b4673806653797vboxsync * transfer an argument set and call a predefined entry point in the Host
cfd41a3683178a30bac4417128b4673806653797vboxsync * VMM Ring-0 code.
cfd41a3683178a30bac4417128b4673806653797vboxsync * See @ref grp_sup "SUP - Support APIs" for API details.
f902ede7eb073d09a81c1d470c089c7b14921714vboxsync/*******************************************************************************
f902ede7eb073d09a81c1d470c089c7b14921714vboxsync* Header Files *
6e3cc82d5d5effda92c9fec18b870d54386f99favboxsync*******************************************************************************/
#include "SUPLibInternal.h"
#include "SUPDrvIOC.h"
static bool g_fPreInited = false;
#if defined(RT_OS_DARWIN)
, NULL
static bool g_fSupportsPageAllocNoKernel = true;
static int supLoadModule(const char *pszFilename, const char *pszModule, const char *pszSrvReqHandler, void **ppvImageBase);
static DECLCALLBACK(int) supLoadModuleResolveImport(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser);
while (cPages-- > 0)
return suplibOsInstall();
return suplibOsUninstall();
return VERR_INVALID_POINTER;
return VERR_WRONG_ORDER;
return VERR_INVALID_MAGIC;
return VERR_INVALID_HANDLE;
return VERR_INVALID_PARAMETER;
return rc;
/** @todo This may need some small restructuring later, it doesn't quite work with a root service flag... */
g_fPreInited = true;
return VINF_SUCCESS;
if (ppSession)
if (g_cInits++ > 0)
return VINF_SUCCESS;
if (g_u32FakeMode == ~0U)
PSUPQUERYFUNCS pFuncsReq = (PSUPQUERYFUNCS)RTMemAllocZ(SUP_IOCTL_QUERY_FUNCS_SIZE(CookieReq.u.Out.cFunctions));
if (pFuncsReq)
rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_QUERY_FUNCS(CookieReq.u.Out.cFunctions), pFuncsReq, SUP_IOCTL_QUERY_FUNCS_SIZE(CookieReq.u.Out.cFunctions));
ASMAtomicCmpXchgPtr((void * volatile *)&g_pSUPGlobalInfoPageR0, (void *)GipMapReq.u.Out.pGipR0, NULL);
if (ppSession)
return VINF_SUCCESS;
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));
LogRel(("Support driver version mismatch: DriverVersion=too-old ClientVersion=%#x\n", SUPDRV_IOC_VERSION));
g_cInits--;
return rc;
g_pFunctions = (PSUPQUERYFUNCS)RTMemAllocZ(SUP_IOCTL_QUERY_FUNCS_SIZE(RT_ELEMENTS(s_aFakeFunctions)));
if (g_pFunctions)
if (ppSession)
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;
g_cInits = 0;
g_cInits--;
#ifdef RT_ARCH_AMD64
return SUPPAGINGMODE_AMD64_GLOBAL_NX;
return SUPPAGINGMODE_32_BIT_GLOBAL;
int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_GET_PAGING_MODE, &Req, SUP_IOCTL_GET_PAGING_MODE_SIZE);
static int supCallVMMR0ExFake(PVMR0 pVMR0, unsigned uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
return VERR_NOT_SUPPORTED;
return VERR_INTERNAL_ERROR;
SUPR3DECL(int) SUPR3CallVMMR0Ex(PVMR0 pVMR0, VMCPUID idCpu, unsigned uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
int rc;
if (!pReqHdr)
rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_VMMR0(cbReq), pReq, SUP_IOCTL_CALL_VMMR0_SIZE(cbReq));
rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_VMMR0_BIG, pReq, SUP_IOCTL_CALL_VMMR0_BIG_SIZE(cbReq));
return rc;
return VINF_SUCCESS;
int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_SET_VM_FOR_FAST, &Req, SUP_IOCTL_SET_VM_FOR_FAST_SIZE);
return rc;
SUPR3DECL(int) SUPR3CallR0Service(const char *pszService, size_t cchService, uint32_t uOperation, uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr)
return VERR_NOT_SUPPORTED;
int rc;
if (!pReqHdr)
rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_SERVICE(cbReq), pReq, SUP_IOCTL_CALL_SERVICE_SIZE(cbReq));
return rc;
static int supR3LoggerSettings(SUPLOGGER enmWhich, uint32_t fWhat, const char *pszFlags, const char *pszGroups, const char *pszDest)
switch (enmWhich)
return VERR_INVALID_PARAMETER;
if (cchFlags)
if (cchGroups)
if (cchDest)
if (!off)
off++;
int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LOGGER_SETTINGS(cbStrTab), pReq, SUP_IOCTL_LOGGER_SETTINGS_SIZE(cbStrTab));
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)
AssertMsg(RT_ALIGN_P(pvStart, PAGE_SIZE) == pvStart, ("pvStart (%p) must be page aligned\n", pvStart));
while (iPage-- > 0)
return VINF_SUCCESS;
int rc;
return rc;
AssertMsg(RT_ALIGN_P(pvStart, PAGE_SIZE) == pvStart, ("pvStart (%p) must be page aligned\n", pvStart));
return VINF_SUCCESS;
return rc;
if (!paPages)
return rc;
SUPR3DECL(int) SUPR3PageAllocEx(size_t cPages, uint32_t fFlags, void **ppvPages, PRTR0PTR pR0Ptr, PSUPPAGE paPages)
if (pR0Ptr)
AssertMsgReturn(cPages > 0 && cPages <= VBOX_MAX_ALLOC_PAGE_COUNT, ("cPages=%zu\n", cPages), VERR_PAGE_COUNT_OUT_OF_RANGE);
if (!pv)
return VERR_NO_MEMORY;
if (pR0Ptr)
if (paPages)
return VINF_SUCCESS;
if ( !pR0Ptr
int rc;
if (pReq)
rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_ALLOC_EX, pReq, SUP_IOCTL_PAGE_ALLOC_EX_SIZE(cPages));
if (pR0Ptr)
if (paPages)
&& !pR0Ptr)
g_fSupportsPageAllocNoKernel = false;
return rc;
SUPR3DECL(int) SUPR3PageMapKernel(void *pvR3, uint32_t off, uint32_t cb, uint32_t fFlags, PRTR0PTR pR0Ptr)
return VERR_NOT_SUPPORTED;
int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_MAP_KERNEL, &Req, SUP_IOCTL_PAGE_MAP_KERNEL_SIZE);
return rc;
SUPR3DECL(int) SUPR3PageProtect(void *pvR3, RTR0PTR R0Ptr, uint32_t off, uint32_t cb, uint32_t fProt)
AssertReturn(!(fProt & ~(RTMEM_PROT_NONE | RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC)), VERR_INVALID_PARAMETER);
#if !defined(RT_OS_SOLARIS)
return rc;
return VINF_SUCCESS;
return rc;
if (pR0Ptr)
if (pR0Ptr)
if (pHCPhys)
return pv;
if (pR0Ptr)
return NULL;
if (!pv)
return VINF_SUCCESS;
return VINF_SUCCESS;
return rc;
AssertMsgReturn(cPages > 0 && cPages < 256, ("cPages=%d must be > 0 and < 256\n", cPages), VERR_PAGE_COUNT_OUT_OF_RANGE);
if (!*ppvPages)
return VERR_NO_LOW_MEMORY;
while (iPage-- > 0)
return VINF_SUCCESS;
int rc;
if (pReq)
if (ppvPagesR0)
if (paPages)
return rc;
if (!pv)
return VINF_SUCCESS;
return VINF_SUCCESS;
return rc;
AssertReturn(!phFile, VERR_NOT_IMPLEMENTED); /** @todo Implement this. The deal is that we make sure the
#ifdef VBOX_WITH_HARDENING
LogRel(("SUPR3HardenedVerifyFile: %s: Verification of \"%s\" failed, rc=%Rrc\n", pszMsg, pszFilename, rc));
return rc;
return VINF_SUCCESS;
int rc;
if (fInternal)
#ifdef VBOX_WITH_HARDENING
return rc;
return VINF_SUCCESS;
SUPR3DECL(int) SUPR3HardenedVerifyDir(const char *pszDirPath, bool fRecursive, bool fCheckFiles, PRTERRINFO pErrInfo)
#ifdef VBOX_WITH_HARDENING
return rc;
return VINF_SUCCESS;
#ifdef VBOX_WITH_HARDENING
return rc;
return VINF_SUCCESS;
SUPR3DECL(int) SUPR3LoadModule(const char *pszFilename, const char *pszModule, void **ppvImageBase, PRTERRINFO pErrInfo)
return rc;
#ifdef VBOX_WITH_HARDENING
return rc;
if ( pszModule
&& *pszModule
AssertMsgFailed(("%s is importing from %s! (expected 'SUPR0.dll' or 'VMMR0.r0', case-sensitive)\n", pvUser, pszModule));
return VERR_SYMBOL_NOT_FOUND;
return VERR_SYMBOL_NOT_FOUND;
void *pvValue;
return VINF_SUCCESS;
return VINF_SUCCESS;
pFunc++;
if ( pszSymbol
return VINF_SUCCESS;
pFunc++;
if (g_u32FakeMode)
return VINF_SUCCESS;
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;
static int supLoadModule(const char *pszFilename, const char *pszModule, const char *pszSrvReqHandler, void **ppvImageBase)
int rc;
return rc;
return rc;
if (!g_u32FakeMode)
if (pLoadReq)
if (fIsVMMR0)
rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "VMMR0EntryInt", &VMMR0EntryInt);
rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "VMMR0EntryFast", &VMMR0EntryFast);
rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "VMMR0EntryEx", &VMMR0EntryEx);
else if (pszSrvReqHandler)
rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, pszSrvReqHandler, &SrvReqHandler);
int rc2 = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "ModuleInit", &ModuleInit);
ModuleInit = 0;
rc2 = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "ModuleTerm", &ModuleTerm);
ModuleTerm = 0;
AssertRelease((size_t)(CreateArgs.pSym - (PSUPLDRSYM)&pLoadReq->u.In.abImage[offSymTab]) <= CalcArgs.cSymbols);
if (fIsVMMR0)
else if (pszSrvReqHandler)
if (!g_u32FakeMode)
rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_LOAD, pLoadReq, SUP_IOCTL_LDR_LOAD_SIZE(cbImageWithTabs));
if (fIsVMMR0)
LogRel(("SUP: VMMR0EntryEx located at %RTptr, VMMR0EntryFast at %RTptr and VMMR0EntryInt at %RTptr\n",
#ifdef RT_OS_WINDOWS
return VINF_SUCCESS;
AssertMsgFailed(("failed to allocated %u bytes for SUPLDRLOAD_IN structure!\n", SUP_IOCTL_LDR_LOAD_SIZE(cbImageWithTabs)));
if (fIsVMMR0)
#ifdef RT_OS_WINDOWS
return rc;
return VINF_SUCCESS;
return rc;
return VINF_SUCCESS;
return VERR_SYMBOL_NOT_FOUND;
int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_GET_SYMBOL, &Req, SUP_IOCTL_LDR_GET_SYMBOL_SIZE);
return rc;
void *pvImageBase;
if (g_pSUPGlobalInfoPage)
return VINF_SUCCESS;
return VERR_WRONG_ORDER;
static int supR3HardenedLdrLoadIt(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fFlags, PRTERRINFO pErrInfo)
#ifdef VBOX_WITH_HARDENING
SUPR3DECL(int) SUPR3HardenedLdrLoad(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fFlags, PRTERRINFO pErrInfo)
SUPR3DECL(int) SUPR3HardenedLdrLoadAppPriv(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fFlags, PRTERRINFO pErrInfo)
LogFlow(("SUPR3HardenedLdrLoadAppPriv: pszFilename=%p:{%s} phLdrMod=%p fFlags=%08x pErrInfo=%p\n", pszFilename, pszFilename, phLdrMod, fFlags, pErrInfo));
AssertMsgReturn(cchFilename < (RTPATH_MAX / 4) * 3, ("%zu\n", cchFilename), VERR_INVALID_PARAMETER);
return VERR_FILE_NOT_FOUND;
return rc;
SUPR3DECL(int) SUPR3HardenedLdrLoadPlugIn(const char *pszFilename, PRTLDRMOD phLdrMod, PRTERRINFO pErrInfo)
int rc;
#ifdef VBOX_WITH_HARDENING
return rc;
#ifdef RT_OS_LINUX
return suplibOsQueryVTxSupported();
return VINF_SUCCESS;
*pfCaps = 0;
return VINF_SUCCESS;
return rc;