PDMDriver.cpp revision c98fb3e16fcd571a790eab772c0c66173d225205
15617cf4cb5fa181f4d6f55f987a883cf298cce6vboxsync * PDM - Pluggable Device and Driver Manager, Driver parts.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Copyright (C) 2006-2007 innotek GmbH
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * available from http://www.virtualbox.org. This file is free software;
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License as published by the Free Software Foundation,
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * distribution. VirtualBox OSE is distributed in the hope that it will
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsync * be useful, but WITHOUT ANY WARRANTY of any kind.
0162ce58ecb597543f776cbc7a05fad399db033fvboxsync/*******************************************************************************
b4915d0cee39500bb2f42e15c25e176619929150vboxsync* Header Files *
0162ce58ecb597543f776cbc7a05fad399db033fvboxsync*******************************************************************************/
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsync/*******************************************************************************
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsync* Structures and Typedefs *
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsync*******************************************************************************/
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsync * Internal callback structure pointer.
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsync * The main purpose is to define the extra data we associate
ae5af5aa3e87e134919787abd96b8ebfb1a19d62vboxsync * with PDMDRVREGCB so we can find the VM instance and so on.
7da1c316d25649f85e7590b66a1713c02e69d814vboxsync /** The callback structure. */
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsync /** A bit of padding. */
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsync /** VM Handle. */
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsync/*******************************************************************************
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsync* Internal Functions *
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsync*******************************************************************************/
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsync/** @name Driver Helpers
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsyncstatic DECLCALLBACK(int) pdmR3DrvHlp_Attach(PPDMDRVINS pDrvIns, PPDMIBASE *ppBaseInterface);
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsyncstatic DECLCALLBACK(int) pdmR3DrvHlp_Detach(PPDMDRVINS pDrvIns);
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsyncstatic DECLCALLBACK(int) pdmR3DrvHlp_DetachSelf(PPDMDRVINS pDrvIns);
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsyncstatic DECLCALLBACK(int) pdmR3DrvHlp_MountPrepare(PPDMDRVINS pDrvIns, const char *pszFilename, const char *pszCoreDriver);
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsyncstatic DECLCALLBACK(int) pdmR3DrvHlp_VMSetError(PPDMDRVINS pDrvIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...);
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsyncstatic DECLCALLBACK(int) pdmR3DrvHlp_VMSetErrorV(PPDMDRVINS pDrvIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va);
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsyncstatic DECLCALLBACK(int) pdmR3DrvHlp_VMSetRuntimeError(PPDMDRVINS pDrvIns, bool fFatal, const char *pszErrorID, const char *pszFormat, ...);
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsyncstatic DECLCALLBACK(int) pdmR3DrvHlp_VMSetRuntimeErrorV(PPDMDRVINS pDrvIns, bool fFatal, const char *pszErrorID, const char *pszFormat, va_list va);
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsyncstatic DECLCALLBACK(bool) pdmR3DrvHlp_AssertEMT(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction);
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsyncstatic DECLCALLBACK(bool) pdmR3DrvHlp_AssertOther(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction);
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsyncstatic DECLCALLBACK(int) pdmR3DrvHlp_PDMQueueCreate(PPDMDRVINS pDrvIns, RTUINT cbItem, RTUINT cItems, uint32_t cMilliesInterval, PFNPDMQUEUEDRV pfnCallback, PPDMQUEUE *ppQueue);
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsyncstatic DECLCALLBACK(int) pdmR3DrvHlp_PDMPollerRegister(PPDMDRVINS pDrvIns, PFNPDMDRVPOLLER pfnPoller);
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsyncstatic DECLCALLBACK(uint64_t) pdmR3DrvHlp_TMGetVirtualFreq(PPDMDRVINS pDrvIns);
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsyncstatic DECLCALLBACK(uint64_t) pdmR3DrvHlp_TMGetVirtualTime(PPDMDRVINS pDrvIns);
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsyncstatic DECLCALLBACK(int) pdmR3DrvHlp_TMTimerCreate(PPDMDRVINS pDrvIns, TMCLOCK enmClock, PFNTMTIMERDRV pfnCallback, const char *pszDesc, PPTMTIMERHC ppTimer);
a664fa5a4c93cf89efebe6c071cc89e9d3d3cd61vboxsyncstatic DECLCALLBACK(int) pdmR3DrvHlp_SSMRegister(PPDMDRVINS pDrvIns, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess,
a664fa5a4c93cf89efebe6c071cc89e9d3d3cd61vboxsync PFNSSMDRVSAVEPREP pfnSavePrep, PFNSSMDRVSAVEEXEC pfnSaveExec, PFNSSMDRVSAVEDONE pfnSaveDone,
a664fa5a4c93cf89efebe6c071cc89e9d3d3cd61vboxsync PFNSSMDRVLOADPREP pfnLoadPrep, PFNSSMDRVLOADEXEC pfnLoadExec, PFNSSMDRVLOADDONE pfnLoadDone);
a664fa5a4c93cf89efebe6c071cc89e9d3d3cd61vboxsyncstatic DECLCALLBACK(int) pdmR3DrvHlp_SSMDeregister(PPDMDRVINS pDrvIns, const char *pszName, uint32_t u32Instance);
a664fa5a4c93cf89efebe6c071cc89e9d3d3cd61vboxsyncstatic DECLCALLBACK(void) pdmR3DrvHlp_STAMRegister(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, const char *pszName, STAMUNIT enmUnit, const char *pszDesc);
a664fa5a4c93cf89efebe6c071cc89e9d3d3cd61vboxsyncstatic DECLCALLBACK(void) pdmR3DrvHlp_STAMRegisterF(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, const char *pszDesc, const char *pszName, ...);
a664fa5a4c93cf89efebe6c071cc89e9d3d3cd61vboxsyncstatic DECLCALLBACK(void) pdmR3DrvHlp_STAMRegisterV(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, const char *pszDesc, const char *pszName, va_list args);
a664fa5a4c93cf89efebe6c071cc89e9d3d3cd61vboxsyncstatic DECLCALLBACK(int) pdmR3DrvHlp_SUPCallVMMR0Ex(PPDMDRVINS pDrvIns, unsigned uOperation, void *pvArg, unsigned cbArg);
a664fa5a4c93cf89efebe6c071cc89e9d3d3cd61vboxsyncstatic DECLCALLBACK(int) pdmR3DrvHlp_USBRegisterHub(PPDMDRVINS pDrvIns, void *pvReservedIn, void **ppvReservedHlp);
a664fa5a4c93cf89efebe6c071cc89e9d3d3cd61vboxsyncstatic DECLCALLBACK(int) pdmR3DrvHlp_PDMThreadCreate(PPDMDRVINS pDrvIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADDRV pfnThread,
a664fa5a4c93cf89efebe6c071cc89e9d3d3cd61vboxsync PFNPDMTHREADWAKEUPDRV pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName);
15617cf4cb5fa181f4d6f55f987a883cf298cce6vboxsync/** @def PDMDRV_ASSERT_DRVINS
c3cd0366348bcd10e42bd7be9ea05d194394f389vboxsync * Asserts the validity of the driver instance.
15617cf4cb5fa181f4d6f55f987a883cf298cce6vboxsync# define PDMDRV_ASSERT_DRVINS(pDrvIns) do { Assert(pDrvIns); Assert(pDrvIns->u32Version == PDM_DRVINS_VERSION); Assert(pDrvIns->pvInstanceData == (void *)&pDrvIns->achInstanceData[0]); } while (0)
a664fa5a4c93cf89efebe6c071cc89e9d3d3cd61vboxsync# define PDMDRV_ASSERT_DRVINS(pDrvIns) do { } while (0)
15617cf4cb5fa181f4d6f55f987a883cf298cce6vboxsyncstatic DECLCALLBACK(int) pdmR3DrvRegister(PCPDMDRVREGCB pCallbacks, PCPDMDRVREG pDrvReg);
15617cf4cb5fa181f4d6f55f987a883cf298cce6vboxsyncstatic int pdmR3DrvLoad(PVM pVM, PPDMDRVREGCBINT pRegCB, const char *pszFilename, const char *pszName);
ebd3c63c626c8039fdb7b95570390699333a7072vboxsync/*******************************************************************************
a664fa5a4c93cf89efebe6c071cc89e9d3d3cd61vboxsync* Global Variables *
ebd3c63c626c8039fdb7b95570390699333a7072vboxsync*******************************************************************************/
a664fa5a4c93cf89efebe6c071cc89e9d3d3cd61vboxsync * The driver helper structure.
return rc;
bool fLoadBuiltin;
fLoadBuiltin = true;
return rc;
if (fLoadBuiltin)
if (!pszFilename)
return VERR_NO_TMP_MEMORY;
return rc;
AssertMsgFailed(("configuration error: The module name is too long, cchName=%d.\n", CFGMR3GetNameLen(pCur)));
return VERR_PDM_MODULE_NAME_TOO_LONG;
return rc;
return rc;
if (!psz)
return VERR_NO_TMP_MEMORY;
return VERR_FILENAME_TOO_LONG;
return rc;
return VINF_SUCCESS;
static int pdmR3DrvLoad(PVM pVM, PPDMDRVREGCBINT pRegCB, const char *pszFilename, const char *pszName)
Log(("PDM: Calling VBoxDriversRegister (%p) of %s (%s)\n", pfnVBoxDriversRegister, pszName, pszFilename));
AssertMsgFailed(("Failed to locate 'VBoxDriversRegister' in %s (%s) rc=%Vrc\n", pszName, pszFilename, rc));
return rc;
return VERR_PDM_UNKNOWN_DRVREG_VERSION;
AssertMsgFailed(("Invalid host bits flags! fFlags=%#x (Driver %s)\n", pDrvReg->fFlags, pDrvReg->szDriverName));
AssertMsgFailed(("Max instances %u! (Driver %s)\n", pDrvReg->cMaxInstances, pDrvReg->szDriverName));
AssertMsgFailed(("Instance size above 1MB, %d bytes! (Driver %s)\n", pDrvReg->cbInstance, pDrvReg->szDriverName));
return VERR_PDM_DRIVER_NAME_CLASH;
if (pDrv)
if (pDrvPrev)
return VINF_SUCCESS;
return VERR_NO_MEMORY;
return pDrv;
return NULL;
LogFlow(("pdmR3DrvDetach: pDrvIns=%p '%s'/%d\n", pDrvIns, pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance));
AssertMsgFailed(("Recursive detach! '%s'/%d\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance));
return VINF_SUCCESS;
AssertMsgFailed(("Cannot detach driver instance because the driver/device above doesn't support it!\n"));
return VINF_SUCCESS;
int rc;
if (pNode)
char *pszName;
if (pDrv)
if (!pConfigNode)
if (pNew)
pNew->pUpBase = &pDrvIns->IBase; /* This ain't safe, you can calc the pDrvIns of the up/down driver! */
Log(("PDM: Constructing driver '%s' instance %d...\n", pNew->pDrvReg->szDriverName, pNew->iInstance));
return rc;
int rc;
return rc;
return rc;
static DECLCALLBACK(int) pdmR3DrvHlp_MountPrepare(PPDMDRVINS pDrvIns, const char *pszFilename, const char *pszCoreDriver)
pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pszFilename, pszFilename, pszCoreDriver, pszCoreDriver));
return VERR_PDM_DRIVER_ALREADY_ATTACHED;
if (pNode)
if (!pszCoreDriver)
return VERR_NOT_IMPLEMENTED;
return rc;
return rc;
static DECLCALLBACK(bool) pdmR3DrvHlp_AssertEMT(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)
RTStrPrintf(szMsg, sizeof(szMsg), "AssertEMT '%s'/%d\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance);
static DECLCALLBACK(bool) pdmR3DrvHlp_AssertOther(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)
RTStrPrintf(szMsg, sizeof(szMsg), "AssertOther '%s'/%d\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance);
static DECLCALLBACK(int) pdmR3DrvHlp_VMSetError(PPDMDRVINS pDrvIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)
int rc2 = VMSetErrorV(pDrvIns->Internal.s.pVM, rc, RT_SRC_POS_ARGS, pszFormat, args); Assert(rc2 == rc); NOREF(rc2);
return rc;
static DECLCALLBACK(int) pdmR3DrvHlp_VMSetErrorV(PPDMDRVINS pDrvIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
int rc2 = VMSetErrorV(pDrvIns->Internal.s.pVM, rc, RT_SRC_POS_ARGS, pszFormat, va); Assert(rc2 == rc); NOREF(rc2);
return rc;
static DECLCALLBACK(int) pdmR3DrvHlp_VMSetRuntimeError(PPDMDRVINS pDrvIns, bool fFatal, const char *pszErrorID, const char *pszFormat, ...)
return rc;
static DECLCALLBACK(int) pdmR3DrvHlp_VMSetRuntimeErrorV(PPDMDRVINS pDrvIns, bool fFatal, const char *pszErrorID, const char *pszFormat, va_list va)
return rc;
static DECLCALLBACK(int) pdmR3DrvHlp_PDMQueueCreate(PPDMDRVINS pDrvIns, RTUINT cbItem, RTUINT cItems, uint32_t cMilliesInterval, PFNPDMQUEUEDRV pfnCallback, PPDMQUEUE *ppQueue)
LogFlow(("pdmR3DrvHlp_PDMQueueCreate: caller='%s'/%d: cbItem=%d cItems=%d cMilliesInterval=%d pfnCallback=%p ppQueue=%p\n",
pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, cbItem, cItems, cMilliesInterval, pfnCallback, ppQueue, ppQueue));
int rc = PDMR3QueueCreateDriver(pDrvIns->Internal.s.pVM, pDrvIns, cbItem, cItems, cMilliesInterval, pfnCallback, ppQueue);
LogFlow(("pdmR3DrvHlp_PDMQueueCreate: caller='%s'/%d: returns %Vrc *ppQueue=%p\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, rc, *ppQueue));
return rc;
static DECLCALLBACK(int) pdmR3DrvHlp_PDMPollerRegister(PPDMDRVINS pDrvIns, PFNPDMDRVPOLLER pfnPoller)
LogFlow(("pdmR3DrvHlp_PDMPollerRegister: caller='%s'/%d: returns %Vrc\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, rc));
return rc;
static DECLCALLBACK(int) pdmR3DrvHlp_TMTimerCreate(PPDMDRVINS pDrvIns, TMCLOCK enmClock, PFNTMTIMERDRV pfnCallback, const char *pszDesc, PPTMTIMERHC ppTimer)
LogFlow(("pdmR3DrvHlp_TMTimerCreate: caller='%s'/%d: enmClock=%d pfnCallback=%p pszDesc=%p:{%s} ppTimer=%p\n",
pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, enmClock, pfnCallback, pszDesc, pszDesc, ppTimer));
int rc = TMR3TimerCreateDriver(pDrvIns->Internal.s.pVM, pDrvIns, enmClock, pfnCallback, pszDesc, ppTimer);
LogFlow(("pdmR3DrvHlp_TMTimerCreate: caller='%s'/%d: returns %Vrc *ppTimer=%p\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, rc, *ppTimer));
return rc;
static DECLCALLBACK(int) pdmR3DrvHlp_SSMRegister(PPDMDRVINS pDrvIns, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess,
LogFlow(("pdmR3DrvHlp_SSMRegister: caller='%s'/%d: pszName=%p:{%s} u32Instance=%#x u32Version=#x cbGuess=%#x pfnSavePrep=%p pfnSaveExec=%p pfnSaveDone=%p pszLoadPrep=%p pfnLoadExec=%p pfnLoaddone=%p\n",
pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pszName, pszName, u32Instance, u32Version, cbGuess, pfnSavePrep, pfnSaveExec, pfnSaveDone, pfnLoadPrep, pfnLoadExec, pfnLoadDone));
int rc = SSMR3RegisterDriver(pDrvIns->Internal.s.pVM, pDrvIns, pszName, u32Instance, u32Version, cbGuess,
LogFlow(("pdmR3DrvHlp_SSMRegister: caller='%s'/%d: returns %Vrc\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, rc));
return rc;
static DECLCALLBACK(int) pdmR3DrvHlp_SSMDeregister(PPDMDRVINS pDrvIns, const char *pszName, uint32_t u32Instance)
LogFlow(("pdmR3DrvHlp_SSMDeregister: caller='%s'/%d: returns %Vrc\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, rc));
return rc;
static DECLCALLBACK(void) pdmR3DrvHlp_STAMRegister(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, const char *pszName, STAMUNIT enmUnit, const char *pszDesc)
/** @todo track the samples so they can be dumped & deregistered when the driver instance is destroyed.
static DECLCALLBACK(void) pdmR3DrvHlp_STAMRegisterF(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
int rc = STAMR3RegisterV(pDrvIns->Internal.s.pVM, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, args);
static DECLCALLBACK(void) pdmR3DrvHlp_STAMRegisterV(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
int rc = STAMR3RegisterV(pDrvIns->Internal.s.pVM, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, args);
static DECLCALLBACK(int) pdmR3DrvHlp_SUPCallVMMR0Ex(PPDMDRVINS pDrvIns, unsigned uOperation, void *pvArg, unsigned cbArg)
int rc;
LogFlow(("pdmR3DrvHlp_SUPCallVMMR0Ex: caller='%s'/%d: returns %Vrc\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, rc));
return rc;
static DECLCALLBACK(int) pdmR3DrvHlp_USBRegisterHub(PPDMDRVINS pDrvIns, void *pvReservedIn, void **ppvReservedHlp)
/// @todo int rc = PDMUSBRegisterHub(pDrvIns->Internal.s.pVM, pvReservedIn, ppvReservedHlp);
LogFlow(("pdmR3DrvHlp_USBRegisterHub: caller='%s'/%d: returns %Vrc\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, rc));
return rc;
static DECLCALLBACK(int) pdmR3DrvHlp_PDMThreadCreate(PPDMDRVINS pDrvIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADDRV pfnThread,
LogFlow(("pdmR3DrvHlp_PDMThreadCreate: caller='%s'/%d: ppThread=%p pvUser=%p pfnThread=%p pfnWakeup=%p cbStack=%#zx enmType=%d pszName=%p:{%s}\n",
pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName, pszName));
int rc = pdmR3ThreadCreateDriver(pDrvIns->Internal.s.pVM, pDrvIns, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName);
LogFlow(("pdmR3DrvHlp_PDMThreadCreate: caller='%s'/%d: returns %Vrc *ppThread=%RTthrd\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance,
return rc;