diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 03:01:46 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 03:01:46 +0000 |
commit | f8fe689a81f906d1b91bb3220acde2a4ecb14c5b (patch) | |
tree | 26484e9d7e2c67806c2d1760196ff01aaa858e8c /src/VBox/Devices/Samples | |
parent | Initial commit. (diff) | |
download | virtualbox-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.cpp | 364 | ||||
-rw-r--r-- | src/VBox/Devices/Samples/DrvStorageFilter.cpp | 590 | ||||
-rw-r--r-- | src/VBox/Devices/Samples/Makefile.kmk | 105 | ||||
-rw-r--r-- | src/VBox/Devices/Samples/VBoxSampleDevice.cpp | 162 |
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); +} + |