PDM.cpp revision 683371bbf37760161d1b8454ce978acf89bbb04f
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * PDM - Pluggable Device Manager.
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * Copyright (C) 2006-2007 Oracle Corporation
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * available from http://www.virtualbox.org. This file is free software;
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * you can redistribute it and/or modify it under the terms of the GNU
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * General Public License (GPL) as published by the Free Software
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync/** @page pg_pdm PDM - The Pluggable Device & Driver Manager
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * VirtualBox is designed to be very configurable, i.e. the ability to select
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * virtual devices and configure them uniquely for a VM. For this reason
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * virtual devices are not statically linked with the VMM but loaded, linked and
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * instantiated at runtime by PDM using the information found in the
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * Configuration Manager (CFGM).
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * While the chief purpose of PDM is to manager of devices their drivers, it
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * also serves as somewhere to put usful things like cross context queues, cross
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * context synchronization (like critsect), VM centric thread management,
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * asynchronous I/O framework, and so on.
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * @see grp_pdm
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * @section sec_pdm_dev The Pluggable Devices
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * Devices register themselves when the module containing them is loaded. PDM
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * will call the entry point 'VBoxDevicesRegister' when loading a device module.
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * The device module will then use the supplied callback table to check the VMM
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * version and to register its devices. Each device have an unique (for the
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * configured VM) name. The name is not only used in PDM but also in CFGM (to
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * organize device and device instance settings) and by anyone who wants to talk
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * to a specific device instance.
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * When all device modules have been successfully loaded PDM will instantiate
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * those devices which are configured for the VM. Note that a device may have
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * more than one instance, see network adaptors for instance. When
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * instantiating a device PDM provides device instance memory and a callback
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * table (aka Device Helpers / DevHlp) with the VM APIs which the device
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * instance is trusted with.
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * Some devices are trusted devices, most are not. The trusted devices are an
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * integrated part of the VM and can obtain the VM handle from their device
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * instance handles, thus enabling them to call any VM api. Untrusted devices
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * can only use the callbacks provided during device instantiation.
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * The main purpose in having DevHlps rather than just giving all the devices
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * the VM handle and let them call the internal VM APIs directly, is both to
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * create a binary interface that can be supported across releases and to
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * create a barrier between devices and the VM. (The trusted / untrusted bit
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * hasn't turned out to be of much use btw., but it's easy to maintain so there
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * isn't any point in removing it.)
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * A device can provide a ring-0 and/or a raw-mode context extension to improve
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * the VM performance by handling exits and traps (respectively) without
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * requiring context switches (to ring-3). Callbacks for MMIO and I/O ports can
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * needs to be registered specifically for the additional contexts for this to
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * make sense. Also, the device has to be trusted to be loaded into R0/RC
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * because of the extra privilege it entails. Note that raw-mode code and data
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * will be subject to relocation.
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * @section sec_pdm_special_devs Special Devices
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * Several kinds of devices interacts with the VMM and/or other device and PDM
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * will work like a mediator for these. The typical pattern is that the device
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * calls a special registration device helper with a set of callbacks, PDM
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * responds by copying this and providing a pointer to a set helper callbacks
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * for that particular kind of device. Unlike interfaces where the callback
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * table pointer is used a 'this' pointer, these arrangements will use the
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * device instance pointer (PPDMDEVINS) as a kind of 'this' pointer.
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * For an example of this kind of setup, see the PIC. The PIC registers itself
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * by calling PDMDEVHLPR3::pfnPICRegister. PDM saves the device instance,
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * copies the callback tables (PDMPICREG), resolving the ring-0 and raw-mode
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * addresses in the process, and hands back the pointer to a set of helper
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * methods (PDMPICHLPR3). The PCI device then queries the ring-0 and raw-mode
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * helpers using PDMPICHLPR3::pfnGetR0Helpers and PDMPICHLPR3::pfnGetRCHelpers.
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * The PCI device repeats ths pfnGetRCHelpers call in it's relocation method
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * since the address changes when RC is relocated.
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * @see grp_pdm_device
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * @section sec_pdm_usbdev The Pluggable USB Devices
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * USB devices are handled a little bit differently than other devices. The
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * general concepts wrt. pluggability are mostly the same, but the details
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * varies. The registration entry point is 'VBoxUsbRegister', the device
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * instance is PDMUSBINS and the callbacks helpers are different. Also, USB
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * device are restricted to ring-3 and cannot have any ring-0 or raw-mode
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * extensions (at least not yet).
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * The way USB devices work differs greatly from other devices though since they
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * aren't attaches directly to the PCI/ISA/whatever system buses but via a
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * USB host control (OHCI, UHCI or EHCI). USB devices handles USB requests
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * (URBs) and does not register I/O ports, MMIO ranges or PCI bus
b8e299dddd091ae24e0c08c45d91b8f937bd14d2vboxsync * @see grp_pdm_usbdev
#include "PDMInternal.h"
typedef struct PDMNOTIFYASYNCSTATS
const char *pszOp;
static DECLCALLBACK(int) pdmR3LoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
return rc;
return rc;
while (pDrvIns)
return VINF_SUCCESS;
uint32_t i = 0;
for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3, i++)
return VINF_SSM_DONT_CALL_AGAIN;
return VINF_SUCCESS;
#ifdef LOG_ENABLED
return VINF_SUCCESS;
int rc;
return rc;
if (fInterruptPending)
fInterruptPending = 0;
return rc;
if (fInterruptPending)
fInterruptPending = 0;
return rc;
if (fInterruptPending)
fInterruptPending = 0;
return rc;
if (fInterruptPending)
return rc;
if (fDMAPending)
for (uint32_t i = 0; ; i++)
return rc;
if (u32Sep != i)
AssertMsgFailedReturn(("Out of sequence. u32Sep=%#x i=%#x\n", u32Sep, i), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
return rc;
return rc;
if (!pDevIns)
return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device '%s'/%d not found in current config"), szName, iInstance);
LogRel(("Device '%s'/%d not found in the saved state\n", pDevIns->pReg->szName, pDevIns->iInstance));
return VINF_SUCCESS;
DECLINLINE(int) pdmR3PowerOnDrv(PPDMDRVINS pDrvIns, const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
return rc;
return VINF_SUCCESS;
return rc;
return VINF_SUCCESS;
return rc;
return VINF_SUCCESS;
for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns && RT_SUCCESS(rc); pDevIns = pDevIns->Internal.s.pNextR3)
for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
#ifdef VBOX_WITH_USB
for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns && RT_SUCCESS(rc); pUsbIns = pUsbIns->Internal.s.pNext)
for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
static void pdmR3NotifyAsyncAdd(PPDMNOTIFYASYNCSTATS pThis, const char *pszName, uint32_t iInstance)
pThis->offList += RTStrPrintf(&pThis->szList[pThis->offList], sizeof(pThis->szList) - pThis->offList,
static void pdmR3NotifyAsyncAddDrv(PPDMNOTIFYASYNCSTATS pThis, const char *pszDrvName, uint32_t iDrvInstance,
pThis->offList += RTStrPrintf(&pThis->szList[pThis->offList], sizeof(pThis->szList) - pThis->offList,
LogFlow(("PDMR3Reset: Async notification started - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
LogFlow(("PDMR3Reset: Async notification completed - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
LogFlow(("PDMR3Reset: Async notification started - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
LogFlow(("PDMR3Reset: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
#ifdef VBOX_WITH_USB
#ifdef VBOX_WITH_USB
LogFlow(("PDMR3Suspend: Async notification completed - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
pdmR3NotifyAsyncAddDrv(pAsync, pDrvIns->Internal.s.pDrv->pReg->szName, pDrvIns->iInstance, pszDevName, iDevInstance, iLun);
LogFlow(("PDMR3Suspend: Notifying - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
LogFlow(("PDMR3Suspend: Async notification started - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
LogFlow(("PDMR3Suspend: Async notification completed - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
LogFlow(("PDMR3Suspend: Async notification started - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
LogFlow(("PDMR3Suspend: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
#ifdef VBOX_WITH_USB
DECLINLINE(int) pdmR3ResumeDrv(PPDMDRVINS pDrvIns, const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
return rc;
return VINF_SUCCESS;
return rc;
return VINF_SUCCESS;
return rc;
return VINF_SUCCESS;
for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns && RT_SUCCESS(rc); pDevIns = pDevIns->Internal.s.pNextR3)
for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
#ifdef VBOX_WITH_USB
for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns && RT_SUCCESS(rc); pUsbIns = pUsbIns->Internal.s.pNext)
for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
LogFlow(("PDMR3PowerOff: Async notification started - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
LogFlow(("PDMR3PowerOff: Async notification completed - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
LogFlow(("PDMR3PowerOff: Notifying - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
LogFlow(("PDMR3PowerOff: Async notification started - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
LogFlow(("PDMR3PowerOff: Async notification completed - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
LogFlow(("PDMR3PowerOff: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
LogFlow(("PDMR3PowerOff: Async notification started - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
LogFlow(("PDMR3PowerOff: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
#ifdef VBOX_WITH_USB
VMMR3DECL(int) PDMR3QueryDevice(PVM pVM, const char *pszDevice, unsigned iInstance, PPDMIBASE *ppBase)
LogFlow(("PDMR3DeviceQuery: pszDevice=%p:{%s} iInstance=%u ppBase=%p\n", pszDevice, pszDevice, iInstance, ppBase));
for (PPDMDEVINS pDevIns = pDev->pInstances; pDevIns; pDevIns = pDevIns->Internal.s.pPerDeviceNextR3)
return VINF_SUCCESS;
return VERR_PDM_DEVICE_NOT_FOUND;
VMMR3DECL(int) PDMR3QueryDeviceLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
return VINF_SUCCESS;
return rc;
VMMR3DECL(int) PDMR3QueryLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
return VINF_SUCCESS;
return rc;
VMMR3DECL(int) PDMR3QueryDriverOnLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, const char *pszDriver, PPPDMIBASE ppBase)
LogFlow(("PDMR3QueryDriverOnLun: pszDevice=%p:{%s} iInstance=%u iLun=%u pszDriver=%p:{%s} ppBase=%p\n",
return VINF_SUCCESS;
return rc;
if (fMore)
return VINF_SUCCESS;
return VINF_SUCCESS;
#ifdef DEBUG_bird
return VERR_NO_MEMORY;
return VINF_SUCCESS;
return VINF_SUCCESS;