PDMLdr.cpp revision 4a0a575bd689b8b9e341365709a345ccaa58d543
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * PDM - Pluggable Device Manager, module loader.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * available from http://www.virtualbox.org. This file is free software;
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * you can redistribute it and/or modify it under the terms of the GNU
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * General Public License (GPL) as published by the Free Software
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * additional information or have any questions.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync//#define PDMLDR_FAKE_MODE
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync/*******************************************************************************
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync* Header Files *
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync*******************************************************************************/
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync/*******************************************************************************
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync* Structures and Typedefs *
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync*******************************************************************************/
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * Structure which the user argument of the RTLdrGetBits() callback points to.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * @internal
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync/*******************************************************************************
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync* Internal Functions *
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync*******************************************************************************/
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsyncstatic DECLCALLBACK(int) pdmR3GetImportRC(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser);
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsyncstatic int pdmR3LoadR0U(PUVM pUVM, const char *pszFilename, const char *pszName);
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsyncstatic char * pdmR3File(const char *pszFile, const char *pszDefaultExt, bool fShared);
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsyncstatic DECLCALLBACK(int) pdmR3QueryModFromEIPEnumSymbols(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser);
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * Loads the VMMR0.r0 module early in the init process.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * @returns VBox status code.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * @param pUVM Pointer to the user mode VM structure.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync return pdmR3LoadR0U(pUVM, NULL, VMMR0_MAIN_MODULE_NAME);
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * Init the module loader part of PDM.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * This routine will load the Host Context Ring-0 and Guest
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * Context VMM modules.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * @returns VBox stutus code.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * @param pUVM Pointer to the user mode VM structure.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * @param pvVMMR0Mod The opqaue returned by PDMR3LdrLoadVMMR0.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * Load the mandatory GC module, the VMMR0.r0 is loaded before VM creation.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync return PDMR3LdrLoadRC(pUVM->pVM, NULL, VMMGC_MAIN_MODULE_NAME);
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * Terminate the module loader part of PDM.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * This will unload and free all modules.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * @param pVM The VM handle.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * @remarks This is normally called twice during termination.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * Free the modules.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync /* free loader item. */
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync /* free bits. */
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync int rc2 = SUPFreeModule((void *)(uintptr_t)pModule->ImageBase);
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync /* MM will free this memory for us - it's alloc only memory. :-) */
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * Applies relocations to GC modules.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * This must be done very early in the relocation
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * process so that components can resolve GC symbols during relocation.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * @param pUVM Pointer to the user mode VM structure.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * @param offDelta Relocation delta relative to old location.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsyncPDMR3DECL(void) PDMR3LdrRelocateU(PUVM pUVM, RTGCINTPTR offDelta)
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync LogFlow(("PDMR3LdrRelocate: offDelta=%VGv\n", offDelta));
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * GC Modules.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * The relocation have to be done in two passes so imports
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * can be correctely resolved. The first pass will update
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * the ImageBase saving the current value in OldImageBase.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * The second pass will do the actual relocation.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync /* pass 1 */
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync for (pCur = pUVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync pCur->ImageBase = MMHyperR3ToRC(pUVM->pVM, pCur->pvBits);
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync /* pass 2 */
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync for (pCur = pUVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync int rc = RTLdrRelocate(pCur->hLdrMod, pCur->pvBits, pCur->ImageBase, pCur->OldImageBase,
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync AssertFatalMsgRC(rc, ("RTLdrRelocate failed, rc=%d\n", rc));
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync DBGFR3ModuleRelocate(pUVM->pVM, pCur->OldImageBase, pCur->ImageBase, RTLdrSize(pCur->hLdrMod),
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * Loads a module into the host context ring-3.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * This is used by the driver and device init functions to load modules
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * containing the drivers and devices. The function can be extended to
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * load modules which are not native to the environment we're running in,
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * but at the moment this is not required.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * No reference counting is kept, since we don't implement any facilities
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * for unloading the module. But the module will naturally be released
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * when the VM terminates.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * @returns VBox status code.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * @param pUVM Pointer to the user mode VM structure.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * @param pszFilename Filename of the module binary.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * @param pszName Module name. Case sensitive and the length is limited!
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsyncint pdmR3LoadR3U(PUVM pUVM, const char *pszFilename, const char *pszName)
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * Validate input.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync AssertMsg(pUVM->pVM->pdm.s.offVM, ("bad init order!\n"));
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync AssertMsgFailed(("Name is too long, cchName=%d pszName='%s'\n", cchName, pszName));
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * Try lookup the name and see if the module exists.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync for (pCur = pUVM->pdm.s.pModules; pCur; pCur = pCur->pNext)
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync AssertMsgFailed(("We've already got a module '%s' loaded!\n", pszName));
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * Allocate the module list node and initialize it.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync size_t cchSuff = RTPathHaveExt(pszFilename) ? 0 : strlen(pszSuff);
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync PPDMMOD pModule = (PPDMMOD)RTMemAllocZ(RT_OFFSETOF(PDMMOD, szFilename[cchFilename + cchSuff + 1]));
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync memcpy(pModule->szName, pszName, cchName); /* memory is zero'ed, no need to copy terminator :-) */
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync memcpy(pModule->szFilename, pszFilename, cchFilename);
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync memcpy(&pModule->szFilename[cchFilename], pszSuff, cchSuff);
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * Load the loader item.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync int rc = SUPR3HardenedVerifyFile(pModule->szFilename, "pdmR3LoadR3U", NULL);
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync rc = RTLdrLoad(pModule->szFilename, &pModule->hLdrMod);
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync /* Something went wrong, most likely module not found. Don't consider other unlikely errors */
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync rc = VMSetError(pUVM->pVM, rc, RT_SRC_POS, N_("Unable to load R3 module %s (%s)"), pModule->szFilename, pszName);
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * Resolve an external symbol during RTLdrGetBits() of a RC module.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * @returns VBox status code.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * @param hLdrMod The loader module handle.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * @param pszModule Module name.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * @param pszSymbol Symbol name, NULL if uSymbol should be used.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * @param uSymbol Symbol ordinal, ~0 if pszSymbol should be used.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * @param pValue Where to store the symbol value (address).
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * @param pvUser User argument.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsyncstatic DECLCALLBACK(int) pdmR3GetImportRC(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser)
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync PPDMMOD pModule = ((PPDMGETIMPORTARGS)pvUser)->pModule;
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * Adjust input.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync * Builtin module.
65a755c25b49d32c914e2d569fcdfb766e1ee879vboxsync if (!pszModule || !strcmp(pszModule, "VMMGCBuiltin.gc"))
AssertMsg(!pszModule, ("Unknown builtin symbol '%s' for module '%s'!\n", pszSymbol, pModule->szName)); NOREF(pModule);
return rc;
while (pCur)
&& ( !pszModule
return rc;
if (pszModule)
return VERR_SYMBOL_NOT_FOUND;
return VERR_SYMBOL_NOT_FOUND;
while (pCur)
return VERR_PDM_MODULE_NAME_CLASH;
if (!pszFilename)
if (!pModule)
return VERR_NO_MEMORY;
("pazName is too long (%d chars) max is %d chars.\n", strlen(pszName), sizeof(pModule->szName) - 1));
return VINF_SUCCESS;
/* Don't consider VERR_PDM_MODULE_NAME_CLASH and VERR_NO_MEMORY above as these are very unlikely. */
return rc;
while (pCur)
return VERR_PDM_MODULE_NAME_CLASH;
if (!pszFilename)
if (!pModule)
return VERR_NO_MEMORY;
("pazName is too long (%d chars) max is %d chars.\n", strlen(pszName), sizeof(pModule->szName) - 1));
void *pvImageBase;
return VINF_SUCCESS;
/* Don't consider VERR_PDM_MODULE_NAME_CLASH and VERR_NO_MEMORY above as these are very unlikely. */
return rc;
PDMR3DECL(int) PDMR3LdrGetSymbolR3(PVM pVM, const char *pszModule, const char *pszSymbol, void **ppvValue)
int rc = RTLdrGetSymbolEx(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, pszSymbol, &Value);
AssertMsg(rc, ("Couldn't symbol '%u' in module '%s'\n", (unsigned)(uintptr_t)pszSymbol, pszModule));
return rc;
return VERR_SYMBOL_NOT_FOUND;
PDMR3DECL(int) PDMR3LdrGetSymbolR0(PVM pVM, const char *pszModule, const char *pszSymbol, PRTR0PTR ppvValue)
#ifdef PDMLDR_FAKE_MODE
return VINF_SUCCESS;
if (!pszModule)
return rc;
return VERR_SYMBOL_NOT_FOUND;
PDMR3DECL(int) PDMR3LdrGetSymbolR0Lazy(PVM pVM, const char *pszModule, const char *pszSymbol, PRTR0PTR ppvValue)
#ifdef PDMLDR_FAKE_MODE
return VINF_SUCCESS;
if (pszModule)
AssertMsgReturn(!strpbrk(pszModule, "/\\:\n\r\t"), ("pszModule=%s\n", pszModule), VERR_INVALID_PARAMETER);
if (!pModule)
PDMR3DECL(int) PDMR3LdrGetSymbolRC(PVM pVM, const char *pszModule, const char *pszSymbol, PRTGCPTR32 pRCPtrValue)
#ifdef PDMLDR_FAKE_MODE
return VINF_SUCCESS;
if (!pszModule)
int rc = RTLdrGetSymbolEx(pModule->hLdrMod, pModule->pvBits, pModule->ImageBase, pszSymbol, &Value);
AssertMsg(rc, ("Couldn't symbol '%u' in module '%s'\n", (unsigned)(uintptr_t)pszSymbol, pszModule));
return rc;
return VERR_SYMBOL_NOT_FOUND;
PDMR3DECL(int) PDMR3LdrGetSymbolRCLazy(PVM pVM, const char *pszModule, const char *pszSymbol, PRTGCPTR32 pRCPtrValue)
#ifdef PDMLDR_FAKE_MODE
return VINF_SUCCESS;
if (pszModule)
AssertMsgReturn(!strpbrk(pszModule, "/\\:\n\r\t"), ("pszModule=%s\n", pszModule), VERR_INVALID_PARAMETER);
if (!pModule)
unsigned cchDefaultExt;
cchDefaultExt = 0;
return NULL;
if (!pszRet)
return NULL;
if (cchDefaultExt)
return pszRet;
* search in the private directory (/usr/lib/virtualbox on Unix).
int rc;
return NULL;
typedef struct QMFEIPARG
char *pszNearSym1;
unsigned cchNearSym1;
char *pszNearSym2;
unsigned cchNearSym2;
if (pMod)
return rc;
static DECLCALLBACK(int) pdmR3QueryModFromEIPEnumSymbols(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
if (pszSymbol)
if (pszSymbol)
return VINF_SUCCESS;
return rc;
return VINF_SUCCESS;