summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/Samples
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 03:01:46 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 03:01:46 +0000
commitf8fe689a81f906d1b91bb3220acde2a4ecb14c5b (patch)
tree26484e9d7e2c67806c2d1760196ff01aaa858e8c /src/VBox/Devices/Samples
parentInitial commit. (diff)
downloadvirtualbox-f8fe689a81f906d1b91bb3220acde2a4ecb14c5b.tar.xz
virtualbox-f8fe689a81f906d1b91bb3220acde2a4ecb14c5b.zip
Adding upstream version 6.0.4-dfsg.upstream/6.0.4-dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Devices/Samples')
-rw-r--r--src/VBox/Devices/Samples/DevPlayground.cpp364
-rw-r--r--src/VBox/Devices/Samples/DrvStorageFilter.cpp590
-rw-r--r--src/VBox/Devices/Samples/Makefile.kmk105
-rw-r--r--src/VBox/Devices/Samples/VBoxSampleDevice.cpp162
4 files changed, 1221 insertions, 0 deletions
diff --git a/src/VBox/Devices/Samples/DevPlayground.cpp b/src/VBox/Devices/Samples/DevPlayground.cpp
new file mode 100644
index 00000000..74f9b5ad
--- /dev/null
+++ b/src/VBox/Devices/Samples/DevPlayground.cpp
@@ -0,0 +1,364 @@
+/* $Id: DevPlayground.cpp $ */
+/** @file
+ * DevPlayground - Device for making PDM/PCI/... experiments.
+ *
+ * This device uses big PCI BAR64 resources, which needs the ICH9 chipset.
+ * The device works without any PCI config (because the default setup with the
+ * ICH9 chipset doesn't have anything at bus=0, device=0, function=0.
+ *
+ * To enable this device for a particular VM:
+ * VBoxManage setextradata vmname VBoxInternal/PDM/Devices/playground/Path .../obj/VBoxPlaygroundDevice/VBoxPlaygroundDevice
+ * VBoxManage setextradata vmname VBoxInternal/Devices/playground/0/Config/Whatever1 0
+ */
+
+/*
+ * Copyright (C) 2009-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_MISC
+#include <VBox/vmm/pdmdev.h>
+#include <VBox/version.h>
+#include <VBox/err.h>
+#include <VBox/log.h>
+
+#include <VBox/com/assert.h>
+#include <VBox/com/defs.h>
+#include <VBox/com/string.h>
+#include <VBox/com/Guid.h>
+#include <VBox/com/VirtualBox.h>
+
+#include <iprt/assert.h>
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Playground device per function (sub-device) data.
+ */
+typedef struct VBOXPLAYGROUNDDEVICEFUNCTION
+{
+ /** The PCI devices. */
+ PDMPCIDEV PciDev;
+ /** The function number. */
+ uint8_t iFun;
+ /** Device function name. */
+ char szName[31];
+} VBOXPLAYGROUNDDEVICEFUNCTION;
+/** Pointer to a PCI function of the playground device. */
+typedef VBOXPLAYGROUNDDEVICEFUNCTION *PVBOXPLAYGROUNDDEVICEFUNCTION;
+
+/**
+ * Playground device instance data.
+ */
+typedef struct VBOXPLAYGROUNDDEVICE
+{
+ /** PCI device functions. */
+ VBOXPLAYGROUNDDEVICEFUNCTION aPciFuns[8];
+} VBOXPLAYGROUNDDEVICE;
+/** Pointer to the instance data of a playground device instance. */
+typedef VBOXPLAYGROUNDDEVICE *PVBOXPLAYGROUNDDEVICE;
+
+
+#define PLAYGROUND_SSM_VERSION 3
+
+
+/*********************************************************************************************************************************
+* Device Functions *
+*********************************************************************************************************************************/
+
+PDMBOTHCBDECL(int) devPlaygroundMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
+{
+ NOREF(pDevIns);
+ NOREF(pvUser);
+ NOREF(GCPhysAddr);
+ NOREF(pv);
+ NOREF(cb);
+ return VINF_SUCCESS;
+}
+
+
+PDMBOTHCBDECL(int) devPlaygroundMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
+{
+ NOREF(pDevIns);
+ NOREF(pvUser);
+ NOREF(GCPhysAddr);
+ NOREF(pv);
+ NOREF(cb);
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * @callback_method_impl{FNPCIIOREGIONMAP}
+ */
+static DECLCALLBACK(int) devPlaygroundMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
+ RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
+{
+ RT_NOREF(pPciDev, enmType, cb);
+
+ switch (iRegion)
+ {
+ case 0:
+ case 2:
+ Assert( enmType == (PCIADDRESSSPACE)(PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_BAR64)
+ || enmType == (PCIADDRESSSPACE)(PCI_ADDRESS_SPACE_MEM_PREFETCH | PCI_ADDRESS_SPACE_BAR64));
+ if (GCPhysAddress == NIL_RTGCPHYS)
+ return VINF_SUCCESS; /* We ignore the unmap notification. */
+ return PDMDevHlpMMIOExMap(pDevIns, pPciDev, iRegion, GCPhysAddress);
+
+ default:
+ /* We should never get here */
+ AssertMsgFailedReturn(("Invalid PCI region param in map callback"), VERR_INTERNAL_ERROR);
+ }
+}
+
+
+/**
+ * @callback_method_impl{FNSSMDEVSAVEEXEC}
+ */
+static DECLCALLBACK(int) devPlaygroundSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
+{
+ PVBOXPLAYGROUNDDEVICE pThis = PDMINS_2_DATA(pDevIns, PVBOXPLAYGROUNDDEVICE);
+
+ /* dummy (real devices would need to save their state here) */
+ RT_NOREF(pThis);
+
+ /* Demo of some API stuff - very unusual, think twice if there's no better
+ * solution which doesn't need API interaction. */
+ HRESULT hrc = S_OK;
+ com::Bstr bstrSnapName;
+ com::Guid uuid(COM_IIDOF(ISnapshot));
+ ISnapshot *pSnap = (ISnapshot *)PDMDevHlpQueryGenericUserObject(pDevIns, uuid.raw());
+ if (pSnap)
+ {
+ hrc = pSnap->COMGETTER(Name)(bstrSnapName.asOutParam());
+ AssertComRCReturn(hrc, VERR_INVALID_STATE);
+ }
+ com::Utf8Str strSnapName(bstrSnapName);
+ SSMR3PutStrZ(pSSM, strSnapName.c_str());
+ LogRel(("Playground: saving state of snapshot '%s', hrc=%Rhrc\n", strSnapName.c_str(), hrc));
+
+ return VINF_SUCCESS;
+}
+
+/**
+ * @callback_method_impl{FNSSMDEVLOADEXEC}
+ */
+static DECLCALLBACK(int) devPlaygroundLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
+{
+ PVBOXPLAYGROUNDDEVICE pThis = PDMINS_2_DATA(pDevIns, PVBOXPLAYGROUNDDEVICE);
+
+ if (uVersion > PLAYGROUND_SSM_VERSION)
+ return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
+ Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
+
+ /* dummy (real devices would need to load their state here) */
+ RT_NOREF(pThis);
+
+ /* Reading the stuff written to saved state, just a demo. */
+ char szSnapName[256];
+ int rc = SSMR3GetStrZ(pSSM, szSnapName, sizeof(szSnapName));
+ AssertRCReturn(rc, rc);
+ LogRel(("Playground: loading state of snapshot '%s'\n", szSnapName));
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * @interface_method_impl{PDMDEVREG,pfnConstruct}
+ */
+static DECLCALLBACK(int) devPlaygroundConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
+{
+ RT_NOREF(iInstance, pCfg);
+ int rc = VINF_SUCCESS;
+
+ /*
+ * Check that the device instance and device helper structures are compatible.
+ */
+ PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
+
+ /*
+ * Initialize the instance data so that the destructor won't mess up.
+ */
+ PVBOXPLAYGROUNDDEVICE pThis = PDMINS_2_DATA(pDevIns, PVBOXPLAYGROUNDDEVICE);
+
+ /*
+ * Validate and read the configuration.
+ */
+ PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "Whatever1|Whatever2", "");
+
+ /*
+ * PCI device setup.
+ */
+ uint32_t iPciDevNo = PDMPCIDEVREG_DEV_NO_FIRST_UNUSED;
+ for (uint32_t iPciFun = 0; iPciFun < RT_ELEMENTS(pThis->aPciFuns); iPciFun++)
+ {
+ PVBOXPLAYGROUNDDEVICEFUNCTION pFun = &pThis->aPciFuns[iPciFun];
+ RTStrPrintf(pFun->szName, sizeof(pThis->aPciFuns[iPciFun].PciDev), "playground%u", iPciFun);
+ pFun->iFun = iPciFun;
+
+ PCIDevSetVendorId( &pFun->PciDev, 0x80ee);
+ PCIDevSetDeviceId( &pFun->PciDev, 0xde4e);
+ PCIDevSetClassBase(&pFun->PciDev, 0x07); /* communications device */
+ PCIDevSetClassSub( &pFun->PciDev, 0x80); /* other communications device */
+ if (iPciFun == 0) /* only for the primary function */
+ PCIDevSetHeaderType(&pFun->PciDev, 0x80); /* normal, multifunction device */
+
+ rc = PDMDevHlpPCIRegisterEx(pDevIns, &pFun->PciDev, iPciFun, 0 /*fFlags*/, iPciDevNo, iPciFun,
+ pThis->aPciFuns[iPciFun].szName);
+ AssertLogRelRCReturn(rc, rc);
+
+ /* First region. */
+ RTGCPHYS const cbFirst = iPciFun == 0 ? 8*_1M : iPciFun * _4K;
+ rc = PDMDevHlpPCIIORegionRegisterEx(pDevIns, &pFun->PciDev, 0, cbFirst,
+ (PCIADDRESSSPACE)( PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_BAR64
+ | (iPciFun == 0 ? PCI_ADDRESS_SPACE_MEM_PREFETCH : 0)),
+ devPlaygroundMap);
+ AssertLogRelRCReturn(rc, rc);
+ char *pszRegionName = NULL;
+ RTStrAPrintf(&pszRegionName, "PG-F%d-BAR0", iPciFun);
+ Assert(pszRegionName);
+ rc = PDMDevHlpMMIOExPreRegister(pDevIns, &pFun->PciDev, 0, cbFirst,
+ IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU, pszRegionName,
+ NULL /*pvUser*/, devPlaygroundMMIOWrite, devPlaygroundMMIORead, NULL /*pfnFill*/,
+ NIL_RTR0PTR /*pvUserR0*/, NULL /*pszWriteR0*/, NULL /*pszReadR0*/, NULL /*pszFillR0*/,
+ NIL_RTRCPTR /*pvUserRC*/, NULL /*pszWriteRC*/, NULL /*pszReadRC*/, NULL /*pszFillRC*/);
+ AssertLogRelRCReturn(rc, rc);
+
+ /* Second region. */
+ RTGCPHYS const cbSecond = iPciFun == 0 ? 32*_1M : iPciFun * _32K;
+ rc = PDMDevHlpPCIIORegionRegisterEx(pDevIns, &pFun->PciDev, 2, cbSecond,
+ (PCIADDRESSSPACE)( PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_BAR64
+ | (iPciFun == 0 ? PCI_ADDRESS_SPACE_MEM_PREFETCH : 0)),
+ devPlaygroundMap);
+ AssertLogRelRCReturn(rc, rc);
+ pszRegionName = NULL;
+ RTStrAPrintf(&pszRegionName, "PG-F%d-BAR2", iPciFun);
+ Assert(pszRegionName);
+ rc = PDMDevHlpMMIOExPreRegister(pDevIns, &pFun->PciDev, 2, cbSecond,
+ IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU, pszRegionName,
+ NULL /*pvUser*/, devPlaygroundMMIOWrite, devPlaygroundMMIORead, NULL /*pfnFill*/,
+ NIL_RTR0PTR /*pvUserR0*/, NULL /*pszWriteR0*/, NULL /*pszReadR0*/, NULL /*pszFillR0*/,
+ NIL_RTRCPTR /*pvUserRC*/, NULL /*pszWriteRC*/, NULL /*pszReadRC*/, NULL /*pszFillRC*/);
+ AssertLogRelRCReturn(rc, rc);
+
+ /* Subsequent function should use the same major as the previous one. */
+ iPciDevNo = PDMPCIDEVREG_DEV_NO_SAME_AS_PREV;
+ }
+
+ /*
+ * Save state handling.
+ */
+ rc = PDMDevHlpSSMRegister(pDevIns, PLAYGROUND_SSM_VERSION, sizeof(*pThis), devPlaygroundSaveExec, devPlaygroundLoadExec);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * @interface_method_impl{PDMDEVREG,pfnDestruct}
+ */
+static DECLCALLBACK(int) devPlaygroundDestruct(PPDMDEVINS pDevIns)
+{
+ /*
+ * Check the versions here as well since the destructor is *always* called.
+ */
+ PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * The device registration structure.
+ */
+static const PDMDEVREG g_DevicePlayground =
+{
+ /* u32Version */
+ PDM_DEVREG_VERSION,
+ /* szName */
+ "playground",
+ /* szRCMod */
+ "",
+ /* szR0Mod */
+ "",
+ /* pszDescription */
+ "VBox Playground Device.",
+ /* fFlags */
+ PDM_DEVREG_FLAGS_DEFAULT_BITS,
+ /* fClass */
+ PDM_DEVREG_CLASS_MISC,
+ /* cMaxInstances */
+ 1,
+ /* cbInstance */
+ sizeof(VBOXPLAYGROUNDDEVICE),
+ /* pfnConstruct */
+ devPlaygroundConstruct,
+ /* pfnDestruct */
+ devPlaygroundDestruct,
+ /* pfnRelocate */
+ NULL,
+ /* pfnMemSetup */
+ NULL,
+ /* pfnPowerOn */
+ NULL,
+ /* pfnReset */
+ NULL,
+ /* pfnSuspend */
+ NULL,
+ /* pfnResume */
+ NULL,
+ /* pfnAttach */
+ NULL,
+ /* pfnDetach */
+ NULL,
+ /* pfnQueryInterface */
+ NULL,
+ /* pfnInitComplete */
+ NULL,
+ /* pfnPowerOff */
+ NULL,
+ /* pfnSoftReset */
+ NULL,
+ /* u32VersionEnd */
+ PDM_DEVREG_VERSION
+};
+
+
+/**
+ * Register devices provided by the plugin.
+ *
+ * @returns VBox status code.
+ * @param pCallbacks Pointer to the callback table.
+ * @param u32Version VBox version number.
+ */
+extern "C" DECLEXPORT(int) VBoxDevicesRegister(PPDMDEVREGCB pCallbacks, uint32_t u32Version)
+{
+ LogFlow(("VBoxPlaygroundDevice::VBoxDevicesRegister: u32Version=%#x pCallbacks->u32Version=%#x\n", u32Version, pCallbacks->u32Version));
+
+ AssertLogRelMsgReturn(u32Version >= VBOX_VERSION,
+ ("VirtualBox version %#x, expected %#x or higher\n", u32Version, VBOX_VERSION),
+ VERR_VERSION_MISMATCH);
+ AssertLogRelMsgReturn(pCallbacks->u32Version == PDM_DEVREG_CB_VERSION,
+ ("callback version %#x, expected %#x\n", pCallbacks->u32Version, PDM_DEVREG_CB_VERSION),
+ VERR_VERSION_MISMATCH);
+
+ return pCallbacks->pfnRegister(pCallbacks, &g_DevicePlayground);
+}
+
diff --git a/src/VBox/Devices/Samples/DrvStorageFilter.cpp b/src/VBox/Devices/Samples/DrvStorageFilter.cpp
new file mode 100644
index 00000000..f038d5f9
--- /dev/null
+++ b/src/VBox/Devices/Samples/DrvStorageFilter.cpp
@@ -0,0 +1,590 @@
+/* $Id: DrvStorageFilter.cpp $ */
+/** @file
+ * VBox storage filter driver sample.
+ */
+
+/*
+ * Copyright (C) 2012-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_MISC
+#include <VBox/vmm/pdmdrv.h>
+#include <VBox/vmm/pdmstorageifs.h>
+#include <VBox/err.h>
+#include <VBox/log.h>
+#include <VBox/version.h>
+
+#include <iprt/uuid.h>
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Storage Filter Driver Instance Data.
+ */
+typedef struct DRVSTORAGEFILTER
+{
+ /** @name Interfaces exposed by this driver.
+ * @{ */
+ PDMIMEDIA IMedia;
+ PDMIMEDIAPORT IMediaPort;
+ PDMIMEDIAEX IMediaEx;
+ PDMIMEDIAEXPORT IMediaExPort;
+ /** @} */
+
+ /** @name Interfaces exposed by the driver below us.
+ * @{ */
+ PPDMIMEDIA pIMediaBelow;
+ PPDMIMEDIAEX pIMediaExBelow;
+ /** @} */
+
+ /** @name Interfaces exposed by the driver/device above us.
+ * @{ */
+ PPDMIMEDIAPORT pIMediaPortAbove;
+ PPDMIMEDIAEXPORT pIMediaExPortAbove;
+ /** @} */
+
+ /** If clear, then suppress Async support. */
+ bool fAsyncIOSupported;
+
+ /** @todo implement memfrob. */
+} DRVSTORAGEFILTER;
+/** Pointer to a storage filter driver instance. */
+typedef DRVSTORAGEFILTER *PDRVSTORAGEFILTER;
+
+
+
+/*
+ *
+ * IMediaPort Implementation.
+ *
+ */
+
+/** @interface_method_impl{PDMIMEDIAPORT,pfnQueryDeviceLocation} */
+static DECLCALLBACK(int) drvStorageFltIMediaPort_QueryDeviceLocation(PPDMIMEDIAPORT pInterface, const char **ppcszController,
+ uint32_t *piInstance, uint32_t *piLUN)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMediaPort);
+ int rc = pThis->pIMediaPortAbove->pfnQueryDeviceLocation(pThis->pIMediaPortAbove, ppcszController, piInstance, piLUN);
+ return rc;
+}
+
+
+/*
+ *
+ * IMedia Implementation.
+ *
+ */
+
+/** @interface_method_impl{PDMIMEDIA,pfnRead} */
+static DECLCALLBACK(int) drvStorageFltIMedia_Read(PPDMIMEDIA pInterface, uint64_t off, void *pvBuf, size_t cbRead)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMedia);
+ int rc = pThis->pIMediaBelow->pfnRead(pThis->pIMediaBelow, off, pvBuf, cbRead);
+ return rc;
+}
+
+/** @interface_method_impl{PDMIMEDIA,pfnWrite} */
+static DECLCALLBACK(int) drvStorageFltIMedia_Write(PPDMIMEDIA pInterface, uint64_t off, const void *pvBuf, size_t cbWrite)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMedia);
+ int rc = pThis->pIMediaBelow->pfnWrite(pThis->pIMediaBelow, off, pvBuf, cbWrite);
+ return rc;
+}
+
+/** @interface_method_impl{PDMIMEDIA,pfnFlush} */
+static DECLCALLBACK(int) drvStorageFltIMedia_Flush(PPDMIMEDIA pInterface)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMedia);
+ int rc = pThis->pIMediaBelow->pfnFlush(pThis->pIMediaBelow);
+ return rc;
+}
+
+/** @interface_method_impl{PDMIMEDIA,pfnMerge} */
+static DECLCALLBACK(int) drvStorageFltIMedia_Merge(PPDMIMEDIA pInterface, PFNSIMPLEPROGRESS pfnProgress, void *pvUser)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMedia);
+ int rc = pThis->pIMediaBelow->pfnMerge(pThis->pIMediaBelow, pfnProgress, pvUser);
+ return rc;
+}
+
+/** @interface_method_impl{PDMIMEDIA,pfnGetSize} */
+static DECLCALLBACK(uint64_t) drvStorageFltIMedia_GetSize(PPDMIMEDIA pInterface)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMedia);
+ uint64_t cb = pThis->pIMediaBelow->pfnGetSize(pThis->pIMediaBelow);
+ return cb;
+}
+
+/** @interface_method_impl{PDMIMEDIA,pfnIsReadOnly} */
+static DECLCALLBACK(bool) drvStorageFltIMedia_IsReadOnly(PPDMIMEDIA pInterface)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMedia);
+ bool fRc = pThis->pIMediaBelow->pfnIsReadOnly(pThis->pIMediaBelow);
+ return fRc;
+}
+
+/** @interface_method_impl{PDMIMEDIA,pfnBiosGetPCHSGeometry} */
+static DECLCALLBACK(int) drvStorageFltIMedia_BiosGetPCHSGeometry(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pPCHSGeometry)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMedia);
+ int rc = pThis->pIMediaBelow->pfnBiosGetPCHSGeometry(pThis->pIMediaBelow, pPCHSGeometry);
+ return rc;
+}
+
+/** @interface_method_impl{PDMIMEDIA,pfnBiosSetPCHSGeometry} */
+static DECLCALLBACK(int) drvStorageFltIMedia_BiosSetPCHSGeometry(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pPCHSGeometry)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMedia);
+ int rc = pThis->pIMediaBelow->pfnBiosSetPCHSGeometry(pThis->pIMediaBelow, pPCHSGeometry);
+ return rc;
+}
+
+/** @interface_method_impl{PDMIMEDIA,pfnBiosGetLCHSGeometry} */
+static DECLCALLBACK(int) drvStorageFltIMedia_BiosGetLCHSGeometry(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pLCHSGeometry)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMedia);
+ int rc = pThis->pIMediaBelow->pfnBiosGetLCHSGeometry(pThis->pIMediaBelow, pLCHSGeometry);
+ return rc;
+}
+
+/** @interface_method_impl{PDMIMEDIA,pfnBiosSetLCHSGeometry} */
+static DECLCALLBACK(int) drvStorageFltIMedia_BiosSetLCHSGeometry(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pLCHSGeometry)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMedia);
+ int rc = pThis->pIMediaBelow->pfnBiosSetLCHSGeometry(pThis->pIMediaBelow, pLCHSGeometry);
+ return rc;
+}
+
+/** @interface_method_impl{PDMIMEDIA,pfnGetUuid} */
+static DECLCALLBACK(int) drvStorageFltIMedia_GetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMedia);
+ int rc = pThis->pIMediaBelow->pfnGetUuid(pThis->pIMediaBelow, pUuid);
+ return rc;
+}
+
+/** @interface_method_impl{PDMIMEDIA,pfnDiscard} */
+static DECLCALLBACK(int) drvStorageFltIMedia_Discard(PPDMIMEDIA pInterface, PCRTRANGE paRanges, unsigned cRanges)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMedia);
+ int rc = pThis->pIMediaBelow->pfnDiscard(pThis->pIMediaBelow, paRanges, cRanges);
+ return rc;
+}
+
+
+/*
+ *
+ * IMediaExPort Implementation.
+ *
+ */
+
+/** @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCompleteNotify} */
+static DECLCALLBACK(int) drvStorageFltIMedia_IoReqCompleteNotify(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
+ void *pvIoReqAlloc, int rcReq)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMediaExPort);
+ return pThis->pIMediaExPortAbove->pfnIoReqCompleteNotify(pThis->pIMediaExPortAbove, hIoReq, pvIoReqAlloc, rcReq);
+}
+
+
+/** @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyFromBuf} */
+static DECLCALLBACK(int) drvStorageFltIMedia_IoReqCopyFromBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
+ void *pvIoReqAlloc, uint32_t offDst, PRTSGBUF pSgBuf,
+ size_t cbCopy)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMediaExPort);
+ return pThis->pIMediaExPortAbove->pfnIoReqCopyFromBuf(pThis->pIMediaExPortAbove, hIoReq, pvIoReqAlloc,
+ offDst, pSgBuf, cbCopy);
+}
+
+/** @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyToBuf} */
+static DECLCALLBACK(int) drvStorageFltIMedia_IoReqCopyToBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
+ void *pvIoReqAlloc, uint32_t offSrc, PRTSGBUF pSgBuf,
+ size_t cbCopy)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMediaExPort);
+ return pThis->pIMediaExPortAbove->pfnIoReqCopyToBuf(pThis->pIMediaExPortAbove, hIoReq, pvIoReqAlloc,
+ offSrc, pSgBuf, cbCopy);
+}
+
+/** @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqQueryDiscardRanges} */
+static DECLCALLBACK(int) drvStorageFltIMedia_IoReqQueryDiscardRanges(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
+ void *pvIoReqAlloc, uint32_t idxRangeStart,
+ uint32_t cRanges, PRTRANGE paRanges,
+ uint32_t *pcRanges)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMediaExPort);
+ return pThis->pIMediaExPortAbove->pfnIoReqQueryDiscardRanges(pThis->pIMediaExPortAbove, hIoReq, pvIoReqAlloc,
+ idxRangeStart, cRanges, paRanges, pcRanges);
+}
+
+/** @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqStateChanged} */
+static DECLCALLBACK(void) drvStorageFltIMedia_IoReqStateChanged(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
+ void *pvIoReqAlloc, PDMMEDIAEXIOREQSTATE enmState)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMediaExPort);
+ return pThis->pIMediaExPortAbove->pfnIoReqStateChanged(pThis->pIMediaExPortAbove, hIoReq, pvIoReqAlloc, enmState);
+}
+
+
+/*
+ *
+ * IMediaEx Implementation.
+ *
+ */
+
+/** @interface_method_impl{PDMIMEDIAEX,pfnQueryFeatures} */
+static DECLCALLBACK(int) drvStorageFltIMedia_QueryFeatures(PPDMIMEDIAEX pInterface, uint32_t *pfFeatures)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMediaEx);
+
+ int rc = pThis->pIMediaExBelow->pfnQueryFeatures(pThis->pIMediaExBelow, pfFeatures);
+ if (RT_SUCCESS(rc) && !pThis->fAsyncIOSupported)
+ *pfFeatures &= ~PDMIMEDIAEX_FEATURE_F_ASYNC;
+
+ return rc;
+}
+
+/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqAllocSizeSet} */
+static DECLCALLBACK(int) drvStorageFltIMedia_IoReqAllocSizeSet(PPDMIMEDIAEX pInterface, size_t cbIoReqAlloc)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMediaEx);
+ return pThis->pIMediaExBelow->pfnIoReqAllocSizeSet(pThis->pIMediaExBelow, cbIoReqAlloc);
+}
+
+/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqAlloc} */
+static DECLCALLBACK(int) drvStorageFltIMedia_IoReqAlloc(PPDMIMEDIAEX pInterface, PPDMMEDIAEXIOREQ phIoReq, void **ppvIoReqAlloc,
+ PDMMEDIAEXIOREQID uIoReqId, uint32_t fFlags)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMediaEx);
+
+ if (!pThis->fAsyncIOSupported)
+ fFlags |= PDMIMEDIAEX_F_SYNC;
+ return pThis->pIMediaExBelow->pfnIoReqAlloc(pThis->pIMediaExBelow, phIoReq, ppvIoReqAlloc, uIoReqId, fFlags);
+}
+
+/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqFree} */
+static DECLCALLBACK(int) drvStorageFltIMedia_IoReqFree(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMediaEx);
+ return pThis->pIMediaExBelow->pfnIoReqFree(pThis->pIMediaExBelow, hIoReq);
+}
+
+/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqQueryResidual} */
+static DECLCALLBACK(int) drvStorageFltIMedia_IoReqQueryResidual(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, size_t *pcbResidual)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMediaEx);
+ return pThis->pIMediaExBelow->pfnIoReqQueryResidual(pThis->pIMediaExBelow, hIoReq, pcbResidual);
+}
+
+/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqCancelAll} */
+static DECLCALLBACK(int) drvStorageFltIMedia_IoReqCancelAll(PPDMIMEDIAEX pInterface)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMediaEx);
+ return pThis->pIMediaExBelow->pfnIoReqCancelAll(pThis->pIMediaExBelow);
+}
+
+/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqCancel} */
+static DECLCALLBACK(int) drvStorageFltIMedia_IoReqCancel(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQID uIoReqId)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMediaEx);
+ return pThis->pIMediaExBelow->pfnIoReqCancel(pThis->pIMediaExBelow, uIoReqId);
+}
+
+/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqRead} */
+static DECLCALLBACK(int) drvStorageFltIMedia_IoReqRead(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, uint64_t off, size_t cbRead)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMediaEx);
+ return pThis->pIMediaExBelow->pfnIoReqRead(pThis->pIMediaExBelow, hIoReq, off, cbRead);
+}
+
+/**
+ * @interface_method_impl{PDMIMEDIAEX,pfnIoReqWrite}
+ */
+static DECLCALLBACK(int) drvStorageFltIMedia_IoReqWrite(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, uint64_t off, size_t cbWrite)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMediaEx);
+ return pThis->pIMediaExBelow->pfnIoReqWrite(pThis->pIMediaExBelow, hIoReq, off, cbWrite);
+}
+
+/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqFlush} */
+static DECLCALLBACK(int) drvStorageFltIMedia_IoReqFlush(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMediaEx);
+ return pThis->pIMediaExBelow->pfnIoReqFlush(pThis->pIMediaExBelow, hIoReq);
+}
+
+/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqDiscard} */
+static DECLCALLBACK(int) drvStorageFltIMedia_IoReqDiscard(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, unsigned cRangesMax)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMediaEx);
+ return pThis->pIMediaExBelow->pfnIoReqDiscard(pThis->pIMediaExBelow, hIoReq, cRangesMax);
+}
+
+/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqSendScsiCmd} */
+static DECLCALLBACK(int) drvStorageFltIMedia_IoReqSendScsiCmd(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, uint32_t uLun,
+ const uint8_t *pbCdb, size_t cbCdb, PDMMEDIAEXIOREQSCSITXDIR enmTxDir,
+ size_t cbBuf, uint8_t *pabSense, size_t cbSense, uint8_t *pu8ScsiSts,
+ uint32_t cTimeoutMillies)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMediaEx);
+ return pThis->pIMediaExBelow->pfnIoReqSendScsiCmd(pThis->pIMediaExBelow, hIoReq, uLun, pbCdb, cbCdb,
+ enmTxDir, cbBuf, pabSense, cbSense, pu8ScsiSts,
+ cTimeoutMillies);
+}
+
+/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqGetActiveCount} */
+static DECLCALLBACK(uint32_t) drvStorageFltIMedia_IoReqGetActiveCount(PPDMIMEDIAEX pInterface)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMediaEx);
+ return pThis->pIMediaExBelow->pfnIoReqGetActiveCount(pThis->pIMediaExBelow);
+}
+
+/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqGetSuspendedCount} */
+static DECLCALLBACK(uint32_t) drvStorageFltIMedia_IoReqGetSuspendedCount(PPDMIMEDIAEX pInterface)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMediaEx);
+ return pThis->pIMediaExBelow->pfnIoReqGetSuspendedCount(pThis->pIMediaExBelow);
+}
+
+/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqQuerySuspendedFirst} */
+static DECLCALLBACK(int) drvStorageFltIMedia_IoReqQuerySuspendedStart(PPDMIMEDIAEX pInterface, PPDMMEDIAEXIOREQ phIoReq,
+ void **ppvIoReqAlloc)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMediaEx);
+ return pThis->pIMediaExBelow->pfnIoReqQuerySuspendedStart(pThis->pIMediaExBelow, phIoReq, ppvIoReqAlloc);
+}
+
+/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqQuerySuspendedNext} */
+static DECLCALLBACK(int) drvStorageFltIMedia_IoReqQuerySuspendedNext(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq,
+ PPDMMEDIAEXIOREQ phIoReqNext, void **ppvIoReqAllocNext)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMediaEx);
+ return pThis->pIMediaExBelow->pfnIoReqQuerySuspendedNext(pThis->pIMediaExBelow, hIoReq, phIoReqNext, ppvIoReqAllocNext);
+}
+
+/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqSuspendedSave} */
+static DECLCALLBACK(int) drvStorageFltIMedia_IoReqSuspendedSave(PPDMIMEDIAEX pInterface, PSSMHANDLE pSSM, PDMMEDIAEXIOREQ hIoReq)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMediaEx);
+ return pThis->pIMediaExBelow->pfnIoReqSuspendedSave(pThis->pIMediaExBelow, pSSM, hIoReq);
+}
+
+/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqSuspendedLoad} */
+static DECLCALLBACK(int) drvStorageFltIMedia_IoReqSuspendedLoad(PPDMIMEDIAEX pInterface, PSSMHANDLE pSSM, PDMMEDIAEXIOREQ hIoReq)
+{
+ PDRVSTORAGEFILTER pThis = RT_FROM_MEMBER(pInterface, DRVSTORAGEFILTER, IMediaEx);
+ return pThis->pIMediaExBelow->pfnIoReqSuspendedLoad(pThis->pIMediaExBelow, pSSM, hIoReq);
+}
+
+
+/*
+ *
+ * IBase Implementation.
+ *
+ */
+
+
+static DECLCALLBACK(void *) drvStorageFltIBase_QueryInterface(PPDMIBASE pInterface, const char *pszIID)
+{
+ PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+ PDRVSTORAGEFILTER pThis = PDMINS_2_DATA(pDrvIns, PDRVSTORAGEFILTER);
+
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
+ if (pThis->pIMediaBelow)
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIA, &pThis->IMedia);
+ if (pThis->pIMediaPortAbove)
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAPORT, &pThis->IMediaPort);
+ if (pThis->pIMediaExBelow)
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAEX, &pThis->IMediaEx);
+ if (pThis->pIMediaExPortAbove)
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAEXPORT, &pThis->IMediaExPort);
+
+ return NULL;
+}
+
+
+/*
+ *
+ * PDMDRVREG Methods
+ *
+ */
+
+
+/**
+ * Construct a storage filter driver.
+ *
+ * @copydoc FNPDMDRVCONSTRUCT
+ */
+static DECLCALLBACK(int) drvStorageFlt_Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
+{
+ PDRVSTORAGEFILTER pThis = PDMINS_2_DATA(pDrvIns, PDRVSTORAGEFILTER);
+
+ PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
+
+ /*
+ * Initialize the instance data.
+ */
+ pDrvIns->IBase.pfnQueryInterface = drvStorageFltIBase_QueryInterface;
+
+ pThis->IMedia.pfnRead = drvStorageFltIMedia_Read;
+ pThis->IMedia.pfnWrite = drvStorageFltIMedia_Write;
+ pThis->IMedia.pfnFlush = drvStorageFltIMedia_Flush;
+ pThis->IMedia.pfnMerge = drvStorageFltIMedia_Merge;
+ pThis->IMedia.pfnGetSize = drvStorageFltIMedia_GetSize;
+ pThis->IMedia.pfnIsReadOnly = drvStorageFltIMedia_IsReadOnly;
+ pThis->IMedia.pfnBiosGetPCHSGeometry = drvStorageFltIMedia_BiosGetPCHSGeometry;
+ pThis->IMedia.pfnBiosSetPCHSGeometry = drvStorageFltIMedia_BiosSetPCHSGeometry;
+ pThis->IMedia.pfnBiosGetLCHSGeometry = drvStorageFltIMedia_BiosGetLCHSGeometry;
+ pThis->IMedia.pfnBiosSetLCHSGeometry = drvStorageFltIMedia_BiosSetLCHSGeometry;
+ pThis->IMedia.pfnGetUuid = drvStorageFltIMedia_GetUuid;
+ pThis->IMedia.pfnDiscard = drvStorageFltIMedia_Discard;
+
+ pThis->IMediaEx.pfnQueryFeatures = drvStorageFltIMedia_QueryFeatures;
+ pThis->IMediaEx.pfnIoReqAllocSizeSet = drvStorageFltIMedia_IoReqAllocSizeSet;
+ pThis->IMediaEx.pfnIoReqAlloc = drvStorageFltIMedia_IoReqAlloc;
+ pThis->IMediaEx.pfnIoReqFree = drvStorageFltIMedia_IoReqFree;
+ pThis->IMediaEx.pfnIoReqQueryResidual = drvStorageFltIMedia_IoReqQueryResidual;
+ pThis->IMediaEx.pfnIoReqCancelAll = drvStorageFltIMedia_IoReqCancelAll;
+ pThis->IMediaEx.pfnIoReqCancel = drvStorageFltIMedia_IoReqCancel;
+ pThis->IMediaEx.pfnIoReqRead = drvStorageFltIMedia_IoReqRead;
+ pThis->IMediaEx.pfnIoReqWrite = drvStorageFltIMedia_IoReqWrite;
+ pThis->IMediaEx.pfnIoReqFlush = drvStorageFltIMedia_IoReqFlush;
+ pThis->IMediaEx.pfnIoReqDiscard = drvStorageFltIMedia_IoReqDiscard;
+ pThis->IMediaEx.pfnIoReqSendScsiCmd = drvStorageFltIMedia_IoReqSendScsiCmd;
+ pThis->IMediaEx.pfnIoReqGetActiveCount = drvStorageFltIMedia_IoReqGetActiveCount;
+ pThis->IMediaEx.pfnIoReqGetSuspendedCount = drvStorageFltIMedia_IoReqGetSuspendedCount;
+ pThis->IMediaEx.pfnIoReqQuerySuspendedStart = drvStorageFltIMedia_IoReqQuerySuspendedStart;
+ pThis->IMediaEx.pfnIoReqQuerySuspendedNext = drvStorageFltIMedia_IoReqQuerySuspendedNext;
+ pThis->IMediaEx.pfnIoReqSuspendedSave = drvStorageFltIMedia_IoReqSuspendedSave;
+ pThis->IMediaEx.pfnIoReqSuspendedLoad = drvStorageFltIMedia_IoReqSuspendedLoad;
+
+ pThis->IMediaPort.pfnQueryDeviceLocation = drvStorageFltIMediaPort_QueryDeviceLocation;
+
+ pThis->IMediaExPort.pfnIoReqCompleteNotify = drvStorageFltIMedia_IoReqCompleteNotify;
+ pThis->IMediaExPort.pfnIoReqCopyFromBuf = drvStorageFltIMedia_IoReqCopyFromBuf;
+ pThis->IMediaExPort.pfnIoReqCopyToBuf = drvStorageFltIMedia_IoReqCopyToBuf;
+ pThis->IMediaExPort.pfnIoReqQueryDiscardRanges = drvStorageFltIMedia_IoReqQueryDiscardRanges;
+ pThis->IMediaExPort.pfnIoReqStateChanged = drvStorageFltIMedia_IoReqStateChanged;
+
+ /*
+ * Validate and read config.
+ */
+ PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "AsyncIOSupported|", "");
+
+ int rc = CFGMR3QueryBoolDef(pCfg, "AsyncIOSupported", &pThis->fAsyncIOSupported, true);
+ AssertLogRelRCReturn(rc, rc);
+
+ /*
+ * Query interfaces from the driver/device above us.
+ */
+ pThis->pIMediaPortAbove = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAPORT);
+ pThis->pIMediaExPortAbove = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAEXPORT);
+
+ /*
+ * Attach driver below us.
+ */
+ PPDMIBASE pIBaseBelow;
+ rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pIBaseBelow);
+ AssertLogRelRCReturn(rc, rc);
+
+ pThis->pIMediaBelow = PDMIBASE_QUERY_INTERFACE(pIBaseBelow, PDMIMEDIA);
+ pThis->pIMediaExBelow = PDMIBASE_QUERY_INTERFACE(pIBaseBelow, PDMIMEDIAEX);
+
+ AssertLogRelReturn(pThis->pIMediaBelow, VERR_PDM_MISSING_INTERFACE_BELOW);
+
+ if (!pThis->pIMediaBelow->pfnDiscard)
+ pThis->IMedia.pfnDiscard = NULL;
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Storage filter driver registration record.
+ */
+static const PDMDRVREG g_DrvStorageFilter =
+{
+ /* u32Version */
+ PDM_DRVREG_VERSION,
+ /* szName */
+ "StorageFilter",
+ /* szRCMod */
+ "",
+ /* szR0Mod */
+ "",
+ /* pszDescription */
+ "Storage Filter Driver Sample",
+ /* fFlags */
+ PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
+ /* fClass. */
+ PDM_DRVREG_CLASS_MEDIA,
+ /* cMaxInstances */
+ ~0U,
+ /* cbInstance */
+ sizeof(DRVSTORAGEFILTER),
+ /* pfnConstruct */
+ drvStorageFlt_Construct,
+ /* pfnDestruct */
+ NULL,
+ /* pfnRelocate */
+ NULL,
+ /* pfnIOCtl */
+ NULL,
+ /* pfnPowerOn */
+ NULL,
+ /* pfnReset */
+ NULL,
+ /* pfnSuspend */
+ NULL,
+ /* pfnResume */
+ NULL,
+ /* pfnAttach */
+ NULL,
+ /* pfnDetach */
+ NULL,
+ /* pfnPowerOff */
+ NULL,
+ /* pfnSoftReset */
+ NULL,
+ /* u32EndVersion */
+ PDM_DRVREG_VERSION
+};
+
+
+/**
+ * Register builtin devices.
+ *
+ * @returns VBox status code.
+ * @param pCallbacks Pointer to the callback table.
+ * @param u32Version VBox version number.
+ */
+extern "C" DECLEXPORT(int) VBoxDriversRegister(PPDMDRVREGCB pCallbacks, uint32_t u32Version)
+{
+ LogFlow(("VBoxSampleDriver::VBoxDriversRegister: u32Version=%#x pCallbacks->u32Version=%#x\n",
+ u32Version, pCallbacks->u32Version));
+
+ AssertLogRelMsgReturn(u32Version >= VBOX_VERSION,
+ ("VirtualBox version %#x, expected %#x or higher\n", u32Version, VBOX_VERSION),
+ VERR_VERSION_MISMATCH);
+ AssertLogRelMsgReturn(pCallbacks->u32Version == PDM_DRVREG_CB_VERSION,
+ ("callback version %#x, expected %#x\n", pCallbacks->u32Version, PDM_DRVREG_CB_VERSION),
+ VERR_VERSION_MISMATCH);
+
+ return pCallbacks->pfnRegister(pCallbacks, &g_DrvStorageFilter);
+}
+
diff --git a/src/VBox/Devices/Samples/Makefile.kmk b/src/VBox/Devices/Samples/Makefile.kmk
new file mode 100644
index 00000000..5bf0afd2
--- /dev/null
+++ b/src/VBox/Devices/Samples/Makefile.kmk
@@ -0,0 +1,105 @@
+# $Id: Makefile.kmk $
+## @file
+# Makefile for the device and driver samples.
+#
+
+#
+# Copyright (C) 2009-2019 Oracle Corporation
+#
+# This file is part of VirtualBox Open Source Edition (OSE), as
+# available from http://www.virtualbox.org. This file is free software;
+# you can redistribute it and/or modify it under the terms of the GNU
+# General Public License (GPL) as published by the Free Software
+# Foundation, in version 2 as it comes in the "COPYING" file of the
+# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+#
+
+SUB_DEPTH = ../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+
+#
+# VBoxSampleDevice - A sample device module.
+#
+DLLS += VBoxSampleDevice
+VBoxSampleDevice_TEMPLATE = VBOXR3
+VBoxSampleDevice_SOURCES = \
+ VBoxSampleDevice.cpp
+VBoxSampleDevice_LIBS = \
+ $(LIB_RUNTIME) \
+ $(LIB_VMM)
+
+#
+# VBoxSampleDriver - A sample driver module.
+#
+DLLS += VBoxSampleDriver
+VBoxSampleDriver_TEMPLATE = VBOXR3
+VBoxSampleDriver_SOURCES = \
+ DrvStorageFilter.cpp
+VBoxSampleDriver_LIBS = \
+ $(LIB_RUNTIME) \
+ $(LIB_VMM)
+
+
+#
+# VBoxPlaygroundDevice - A device module demonstrating some unusual features.
+#
+DLLS += VBoxPlaygroundDevice
+VBoxPlaygroundDevice_TEMPLATE = VBOXR3
+VBoxPlaygroundDevice_SOURCES = \
+ DevPlayground.cpp
+VBoxPlaygroundDevice_LIBS = \
+ $(PATH_STAGE_LIB)/VBoxCOM$(VBOX_SUFF_LIB) \
+ $(LIB_RUNTIME) \
+ $(LIB_VMM)
+
+ifdef VBOX_WITH_XPCOM
+ ## @todo may be worth creating the VBOX_XPCOM SDK def, or just a SDK_VBOXXPCOM.
+ VBoxPlaygroundDevice_DEFS += VBOX_WITH_XPCOM
+ ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP
+ VBoxPlaygroundDevice_DEFS += VBOX_WITH_XPCOM_NAMESPACE_CLEANUP
+ endif
+ VBoxPlaygroundDevice_INCS += \
+ $(VBOX_XPCOM_INCS)
+ VBoxPlaygroundDevice_INTERMEDIATES += \
+ $(VBOX_PATH_SDK)/bindings/xpcom/include/VirtualBox_XPCOM.h
+ VBoxPlaygroundDevice_LIBS += \
+ $(LIB_XPCOM)
+else # COM
+ VBoxPlaygroundDevice_INCS += \
+ $(VBOX_PATH_SDK)/bindings/mscom/include
+ VBoxPlaygroundDevice_INTERMEDIATES += \
+ $(VBOX_PATH_SDK)/bindings/mscom/include/VirtualBox.h
+endif # COM
+
+
+include $(FILE_KBUILD_SUB_FOOTER)
+
+
+#
+# Installs the filter.
+#
+install-filter:
+ $(if-expr "$(VBOX_MANAGE)" == "",$(error VBOX_MANAGE is not defined,))
+ $(if-expr "$(VBOX_VMNAME)" == "",$(error VBOX_VMNAME is not defined,))
+# Make VBox load the driver
+ $(VBOX_MANAGE) setextradata "$(VBOX_VMNAME)" "VBoxInternal/PDM/Drivers/VBoxSampleDriver/Path" \
+ "$(if $(VBoxSampleDriver_1_INST_TARGET),$(VBoxSampleDriver_1_INST_TARGET),$(VBoxSampleDriver_1_TARGET))"
+# Configure the matching.
+ $(VBOX_MANAGE) setextradata "$(VBOX_VMNAME)" "VBoxInternal/PDM/DriverTransformations/StorageFilter/AboveDriver" \
+ "VD"
+# The config of the injected driver.
+ $(VBOX_MANAGE) setextradata "$(VBOX_VMNAME)" "VBoxInternal/PDM/DriverTransformations/StorageFilter/AttachedDriver/Driver" \
+ "StorageFilter"
+ $(VBOX_MANAGE) setextradata "$(VBOX_VMNAME)" "VBoxInternal/PDM/DriverTransformations/StorageFilter/AttachedDriver/Config/AsyncIOSupported" \
+ "1"
+
+uninstall-filter:
+ $(if-expr "$(VBOX_MANAGE)" == "",$(error VBOX_MANAGE is not defined,))
+ $(if-expr "$(VBOX_VMNAME)" == "",$(error VBOX_VMNAME is not defined,))
+ $(VBOX_MANAGE) showvminfo "$(VBOX_VMNAME)"
+ $(VBOX_MANAGE) setextradata "$(VBOX_VMNAME)" "VBoxInternal/PDM/Drivers/VBoxSampleDriver/Path"
+ $(VBOX_MANAGE) setextradata "$(VBOX_VMNAME)" "VBoxInternal/PDM/DriverTransformations/StorageFilter/AboveDriver"
+ $(VBOX_MANAGE) setextradata "$(VBOX_VMNAME)" "VBoxInternal/PDM/DriverTransformations/StorageFilter/AttachedDriver/Config/AsyncIOSupported"
+
diff --git a/src/VBox/Devices/Samples/VBoxSampleDevice.cpp b/src/VBox/Devices/Samples/VBoxSampleDevice.cpp
new file mode 100644
index 00000000..35dcf70d
--- /dev/null
+++ b/src/VBox/Devices/Samples/VBoxSampleDevice.cpp
@@ -0,0 +1,162 @@
+/* $Id: VBoxSampleDevice.cpp $ */
+/** @file
+ * VBox Sample Device.
+ */
+
+/*
+ * Copyright (C) 2009-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_MISC
+#include <VBox/vmm/pdmdev.h>
+#include <VBox/version.h>
+#include <iprt/errcore.h>
+#include <VBox/log.h>
+
+#include <iprt/assert.h>
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Device Instance Data.
+ */
+typedef struct VBOXSAMPLEDEVICE
+{
+ uint32_t Whatever;
+} VBOXSAMPLEDEVICE;
+typedef VBOXSAMPLEDEVICE *PVBOXSAMPLEDEVICE;
+
+
+
+static DECLCALLBACK(int) devSampleDestruct(PPDMDEVINS pDevIns)
+{
+ /*
+ * Check the versions here as well since the destructor is *always* called.
+ */
+ PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
+
+ return VINF_SUCCESS;
+}
+
+
+static DECLCALLBACK(int) devSampleConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
+{
+
+ /*
+ * Check that the device instance and device helper structures are compatible.
+ */
+ PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
+ NOREF(pCfg);
+
+ /*
+ * Initialize the instance data so that the destructor won't mess up.
+ */
+ PVBOXSAMPLEDEVICE pThis = PDMINS_2_DATA(pDevIns, PVBOXSAMPLEDEVICE);
+ pThis->Whatever = 0;
+
+ /*
+ * Validate and read the configuration.
+ */
+ PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "Whatever1|Whatever2", "");
+
+ /*
+ * Use the instance number if necessary (not for this device, which in
+ * g_DeviceSample below declares a maximum instance count of 1).
+ */
+ NOREF(iInstance);
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * The device registration structure.
+ */
+static const PDMDEVREG g_DeviceSample =
+{
+ /* u32Version */
+ PDM_DEVREG_VERSION,
+ /* szName */
+ "sample",
+ /* szRCMod */
+ "",
+ /* szR0Mod */
+ "",
+ /* pszDescription */
+ "VBox Sample Device.",
+ /* fFlags */
+ PDM_DEVREG_FLAGS_DEFAULT_BITS,
+ /* fClass */
+ PDM_DEVREG_CLASS_MISC,
+ /* cMaxInstances */
+ 1,
+ /* cbInstance */
+ sizeof(VBOXSAMPLEDEVICE),
+ /* pfnConstruct */
+ devSampleConstruct,
+ /* pfnDestruct */
+ devSampleDestruct,
+ /* pfnRelocate */
+ NULL,
+ /* pfnMemSetup */
+ NULL,
+ /* pfnPowerOn */
+ NULL,
+ /* pfnReset */
+ NULL,
+ /* pfnSuspend */
+ NULL,
+ /* pfnResume */
+ NULL,
+ /* pfnAttach */
+ NULL,
+ /* pfnDetach */
+ NULL,
+ /* pfnQueryInterface */
+ NULL,
+ /* pfnInitComplete */
+ NULL,
+ /* pfnPowerOff */
+ NULL,
+ /* pfnSoftReset */
+ NULL,
+ /* u32VersionEnd */
+ PDM_DEVREG_VERSION
+};
+
+
+/**
+ * Register devices provided by the plugin.
+ *
+ * @returns VBox status code.
+ * @param pCallbacks Pointer to the callback table.
+ * @param u32Version VBox version number.
+ */
+extern "C" DECLEXPORT(int) VBoxDevicesRegister(PPDMDEVREGCB pCallbacks, uint32_t u32Version)
+{
+ LogFlow(("VBoxSampleDevice::VBoxDevicesRegister: u32Version=%#x pCallbacks->u32Version=%#x\n", u32Version, pCallbacks->u32Version));
+
+ AssertLogRelMsgReturn(u32Version >= VBOX_VERSION,
+ ("VirtualBox version %#x, expected %#x or higher\n", u32Version, VBOX_VERSION),
+ VERR_VERSION_MISMATCH);
+ AssertLogRelMsgReturn(pCallbacks->u32Version == PDM_DEVREG_CB_VERSION,
+ ("callback version %#x, expected %#x\n", pCallbacks->u32Version, PDM_DEVREG_CB_VERSION),
+ VERR_VERSION_MISMATCH);
+
+ return pCallbacks->pfnRegister(pCallbacks, &g_DeviceSample);
+}
+