Index: trunk/src/VBox/Devices/testcase/tstDevice.cpp
===================================================================
--- trunk/src/VBox/Devices/testcase/tstDevice.cpp	(revision 69162)
+++ trunk/src/VBox/Devices/testcase/tstDevice.cpp	(revision 69162)
@@ -0,0 +1,900 @@
+/* $Id$ */
+/** @file
+ * tstDevice - Test framework for PDM devices/drivers
+ */
+
+/*
+ * Copyright (C) 2017 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_DEFAULT /** @todo */
+#include <VBox/types.h>
+#include <VBox/version.h>
+#include <iprt/assert.h>
+#include <iprt/ctype.h>
+#include <iprt/getopt.h>
+#include <iprt/initterm.h>
+#include <iprt/ldr.h>
+#include <iprt/log.h>
+#include <iprt/list.h>
+#include <iprt/mem.h>
+#include <iprt/once.h>
+#include <iprt/path.h>
+#include <iprt/string.h>
+#include <iprt/stream.h>
+#include <iprt/trace.h>
+
+#include "tstDeviceInternal.h"
+
+/*********************************************************************************************************************************
+*   Defined Constants And Macros                                                                                                 *
+*********************************************************************************************************************************/
+
+
+/*********************************************************************************************************************************
+*   Structures and Typedefs                                                                                                      *
+*********************************************************************************************************************************/
+
+
+/**
+ * Testcase plugin descriptor.
+ */
+typedef struct TSTDEVPLUGIN
+{
+    /** Node for the plugin list. */
+    RTLISTNODE                      NdPlugins;
+    /** Copy of the filename. */
+    char                            *pszFilename;
+    /** Loader handle. */
+    RTLDRMOD                        hMod;
+    /** Number of references to this plugin. */
+    volatile uint32_t               cRefs;
+} TSTDEVPLUGIN;
+/** Pointer to a device plugin descriptor. */
+typedef TSTDEVPLUGIN *PTSTDEVPLUGIN;
+/** Pointer to a const plugin descriptor. */
+typedef const TSTDEVPLUGIN *PCTSTDEVPLUGIN;
+
+
+/**
+ * Testcase descriptor.
+ */
+typedef struct TSTDEVTESTCASE
+{
+    /** Node for the list of registered testcases. */
+    RTLISTNODE                      NdTestcases;
+    /** Pointer to the plugin the testcase belongs to. */
+    PCTSTDEVPLUGIN                  pPlugin;
+    /** Pointer to the testcase descriptor. */
+    PCTSTDEVTESTCASEREG             pTestcaseReg;
+} TSTDEVTESTCASE;
+/** Pointer to a testcase descriptor. */
+typedef TSTDEVTESTCASE *PTSTDEVTESTCASE;
+/** Pointer to a constant testcase descriptor. */
+typedef const TSTDEVTESTCASE *PCTSTDEVTESTCASE;
+
+
+/**
+ * PDM R0/RC module trampoline descriptor.
+ */
+#pragma pack(1)
+typedef struct TSTDEVPDMMODTRAMPOLINE
+{
+    /** Jump instruction. */
+    uint8_t                         abJmp[6];
+    /** Address to jump to. */
+    uintptr_t                       AddrTarget;
+    /** Padding to get a 16byte aligned structure. */
+    uint8_t                         abPadding[HC_ARCH_BITS == 64 ? 2 : 5];
+} TSTDEVPDMMODTRAMPOLINE;
+#pragma pack()
+AssertCompileSize(TSTDEVPDMMODTRAMPOLINE, 16);
+/** Pointer to a trampoline descriptor. */
+typedef TSTDEVPDMMODTRAMPOLINE *PTSTDEVPDMMODTRAMPOLINE;
+
+/**
+ * PDM module descriptor.
+ */
+typedef struct TSTDEVPDMMOD
+{
+    /** Node for the module list. */
+    RTLISTNODE                      NdPdmMods;
+    /** Type of module (R3/R0/RC). */
+    TSTDEVPDMMODTYPE                enmType;
+    /** Copy of the filename. */
+    char                            *pszFilename;
+    /** Loader handle. */
+    RTLDRMOD                        hLdrMod;
+    /** Number of references to this plugin. */
+    volatile uint32_t               cRefs;
+    /** R0/RC Module type dependent data. */
+    struct
+    {
+        /** The exectuable image bits. */
+        void                        *pvBits;
+        /** Size of the memory buffer. */
+        size_t                      cbBits;
+        /** Pointer to the executable memory containing the trampoline code. */
+        uint8_t                     *pbTrampoline;
+        /** Number of trampoline entries supported. */
+        uint32_t                    cTrampolinesMax;
+        /** Number of trampoline entries used. */
+        uint32_t                    cTrampolines;
+        /** Pointer to the next unused trampoline entry. */
+        PTSTDEVPDMMODTRAMPOLINE     pTrampolineNext;
+    } R0Rc;
+} TSTDEVPDMMOD;
+/** Pointer to a PDM module descriptor. */
+typedef TSTDEVPDMMOD *PTSTDEVPDMMOD;
+/** Pointer to a const PDM module descriptor. */
+typedef const TSTDEVPDMMOD *PCTSTDEVPDMMOD;
+
+/**
+ * PDM device descriptor.
+ */
+typedef struct TSTDEVPDMDEV
+{
+    /** Node for the known device list. */
+    RTLISTNODE                      NdPdmDevs;
+    /** Pointer to the PDM module containing the device. */
+    PCTSTDEVPDMMOD                  pPdmMod;
+    /** Device registration structure. */
+    const struct PDMDEVREG          *pReg;
+} TSTDEVPDMDEV;
+/** Pointer to a PDM device descriptor .*/
+typedef TSTDEVPDMDEV *PTSTDEVPDMDEV;
+/** Pointer to a constant PDM device descriptor .*/
+typedef const TSTDEVPDMDEV *PCTSTDEVPDMDEV;
+
+
+/**
+ * Internal callback structure pointer.
+ * The main purpose is to define the extra data we associate
+ * with PDMDEVREGCB so we can find the plugin the device is associated with etc.
+ */
+typedef struct TSTDEVPDMDEVREGCBINT
+{
+    /** The callback structure. */
+    PDMDEVREGCB       Core;
+    /** A bit of padding. */
+    uint32_t          u32[4];
+    /** Pointer to plugin. */
+    PTSTDEVPDMMOD     pMod;
+} TSTDEVPDMDEVREGCBINT;
+/** Pointer to a PDMDEVREGCBINT structure. */
+typedef TSTDEVPDMDEVREGCBINT *PTSTDEVPDMDEVREGCBINT;
+/** Pointer to a const PDMDEVREGCBINT structure. */
+typedef const TSTDEVPDMDEVREGCBINT *PCTSTDEVPDMDEVREGCBINT;
+
+
+typedef struct TSTDEVPDMR0IMPORTS
+{
+    /** The symbol name. */
+    const char                      *pszSymbol;
+    /** The pointer. */
+    PFNRT                           pfn;
+} TSTDEVPDMR0IMPORTS;
+typedef const TSTDEVPDMR0IMPORTS *PCTSTDEVPDMR0IMPORTS;
+
+/*********************************************************************************************************************************
+*   Global Variables                                                                                                             *
+*********************************************************************************************************************************/
+/** List of registered testcase plugins. */
+RTLISTANCHOR g_LstPlugins;
+/** List of registered testcases. */
+RTLISTANCHOR g_LstTestcases;
+/** List of registered PDM modules. */
+RTLISTANCHOR g_LstPdmMods;
+/** List of registered PDM devices. */
+RTLISTANCHOR g_LstPdmDevs;
+
+extern const TSTDEVVMMCALLBACKS g_tstDevVmmCallbacks;
+
+/**
+ * PDM R0 imports we implement.
+ */
+static const TSTDEVPDMR0IMPORTS g_aPdmR0Imports[] =
+{
+    {"IOMMMIOMapMMIO2Page",            (PFNRT)IOMMMIOMapMMIO2Page},
+    {"IOMMMIOResetRegion",             (PFNRT)IOMMMIOResetRegion},
+    {"IntNetR0IfSend",                 (PFNRT)/*IntNetR0IfSend*/NULL},
+    {"IntNetR0IfSetPromiscuousMode",   (PFNRT)/*IntNetR0IfSetPromiscuousMode*/NULL},
+    {"PDMCritSectEnterDebug",          (PFNRT)PDMCritSectEnterDebug},
+    {"PDMCritSectIsOwner",             (PFNRT)PDMCritSectIsOwner},
+    {"PDMCritSectLeave",               (PFNRT)PDMCritSectLeave},
+    {"PDMCritSectTryEnterDebug",       (PFNRT)PDMCritSectTryEnterDebug},
+    {"PDMHCCritSectScheduleExitEvent", (PFNRT)PDMHCCritSectScheduleExitEvent},
+    {"PDMNsAllocateBandwidth",         (PFNRT)PDMNsAllocateBandwidth},
+    {"PDMQueueAlloc",                  (PFNRT)PDMQueueAlloc},
+    {"PDMQueueInsert",                 (PFNRT)PDMQueueInsert},
+    {"PGMHandlerPhysicalPageTempOff",  (PFNRT)PGMHandlerPhysicalPageTempOff},
+    {"PGMShwMakePageWritable",         (PFNRT)PGMShwMakePageWritable},
+    {"RTAssertMsg1Weak",               (PFNRT)RTAssertMsg1Weak},
+    {"RTAssertMsg2Weak",               (PFNRT)RTAssertMsg2Weak},
+    {"RTAssertShouldPanic",            (PFNRT)RTAssertShouldPanic},
+    {"RTLogDefaultInstanceEx",         (PFNRT)RTLogDefaultInstanceEx},
+    {"RTLogLoggerEx",                  (PFNRT)RTLogLoggerEx},
+    {"RTLogRelGetDefaultInstanceEx",   (PFNRT)RTLogRelGetDefaultInstanceEx},
+    {"RTOnceSlow",                     (PFNRT)RTOnceSlow},
+    {"RTR0AssertPanicSystem",          (PFNRT)0x10101010},
+    {"RTThreadSleep",                  (PFNRT)RTThreadSleep},
+    {"RTTimeMilliTS",                  (PFNRT)RTTimeMilliTS},
+    {"RTTimeNanoTS",                   (PFNRT)RTTimeNanoTS},
+    {"RTTraceBufAddMsgF",              (PFNRT)RTTraceBufAddMsgF},
+    {"SUPSemEventSignal",              (PFNRT)SUPSemEventSignal},
+    {"TMTimerGet",                     (PFNRT)TMTimerGet},
+    {"TMTimerGetFreq",                 (PFNRT)TMTimerGetFreq},
+    {"TMTimerIsActive",                (PFNRT)TMTimerIsActive},
+    {"TMTimerIsLockOwner",             (PFNRT)TMTimerIsLockOwner},
+    {"TMTimerLock",                    (PFNRT)TMTimerLock},
+    {"TMTimerSet",                     (PFNRT)TMTimerSet},
+    {"TMTimerSetFrequencyHint",        (PFNRT)TMTimerSetFrequencyHint},
+    {"TMTimerSetMicro",                (PFNRT)TMTimerSetMicro},
+    {"TMTimerSetMillies",              (PFNRT)TMTimerSetMillies},
+    {"TMTimerSetNano",                 (PFNRT)TMTimerSetNano},
+    {"TMTimerStop",                    (PFNRT)TMTimerStop},
+    {"TMTimerUnlock",                  (PFNRT)TMTimerUnlock},
+    {"nocrt_memcmp",                   (PFNRT)memcmp},
+    {"nocrt_memcpy",                   (PFNRT)memcpy},
+    {"nocrt_memmove",                  (PFNRT)memmove},
+    {"nocrt_memset",                   (PFNRT)memset},
+    {"nocrt_strlen",                   (PFNRT)strlen},
+};
+
+
+/*********************************************************************************************************************************
+*   Internal Functions                                                                                                           *
+*********************************************************************************************************************************/
+
+#if 0
+/**
+ * Parses the options given to the testcase.
+ *
+ * @returns Process status code.
+ * @param   cArgs       Number of arguments given.
+ * @param   paszArgs    Pointer to the argument vector.
+ */
+static RTEXITCODE tstDevParseOptions(int cArgs, char *paszArgs[])
+{
+    static RTGETOPTDEF const s_aOptions[] =
+    {
+    };
+
+
+    int ch;
+    RTGETOPTUNION Value;
+    RTGETOPTSTATE GetState;
+    RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0 /* fFlags */);
+    while ((ch = RTGetOpt(&GetState, &Value)))
+    {
+        switch (ch)
+        {
+            default:
+                return RTGetOptPrintError(ch, &Value);
+        }
+    }
+}
+#endif
+
+
+/**
+ * Checks whether the given testcase name is already existing.
+ *
+ * @returns Pointer to existing testcase, NULL if not found.
+ * @param   pszFilename    The filename to check.
+ */
+static PCTSTDEVTESTCASE tstDevTestcaseFind(const char *pszName)
+{
+    PCTSTDEVTESTCASE pIt;
+    RTListForEach(&g_LstTestcases, pIt, TSTDEVTESTCASE, NdTestcases)
+    {
+        if (!RTStrCmp(pIt->pTestcaseReg->szName, pszName))
+            return pIt;
+    }
+
+    return NULL;
+}
+
+
+/**
+ * @interface_method_impl{TSTDEVPLUGINREGISTER,pfnRegisterTestcase}
+ */
+static DECLCALLBACK(int) tstDevRegisterTestcase(void *pvUser, PCTSTDEVTESTCASEREG pTestcaseReg)
+{
+    int rc = VINF_SUCCESS;
+    PTSTDEVPLUGIN pPlugin = (PTSTDEVPLUGIN)pvUser;
+
+    /* Try to find a testcase with the name first. */
+    if (!tstDevTestcaseFind(pTestcaseReg->szName))
+    {
+        PTSTDEVTESTCASE pTestcase = (PTSTDEVTESTCASE)RTMemAllocZ(sizeof(TSTDEVPLUGIN));
+        if (RT_LIKELY(pTestcase))
+        {
+            pTestcase->pPlugin = pPlugin;
+            pPlugin->cRefs++;
+            pTestcase->pTestcaseReg = pTestcaseReg;
+            RTListAppend(&g_LstTestcases, &pTestcase->NdTestcases);
+            return VINF_SUCCESS;
+        }
+        else
+            rc = VERR_NO_MEMORY;
+    }
+    else
+        rc = VERR_ALREADY_EXISTS;
+
+    return rc;
+}
+
+
+/**
+ * Checks whether the given plugin filename was already loaded.
+ *
+ * @returns Pointer to already loaded plugin, NULL if not found.
+ * @param   pszFilename    The filename to check.
+ */
+static PCTSTDEVPLUGIN tstDevPluginFind(const char *pszFilename)
+{
+    PCTSTDEVPLUGIN pIt;
+    RTListForEach(&g_LstPlugins, pIt, TSTDEVPLUGIN, NdPlugins)
+    {
+        if (!RTStrCmp(pIt->pszFilename, pszFilename))
+            return pIt;
+    }
+
+    return NULL;
+}
+
+
+/**
+ * Tries to loads the given plugin.
+ *
+ * @returns VBox status code.
+ * @param   pszFilename    The filename to load.
+ */
+static int tstDevLoadPlugin(const char *pszFilename)
+{
+    int rc = VINF_SUCCESS;
+
+    /* Check whether the plugin is loaded first. */
+    if (!tstDevPluginFind(pszFilename))
+    {
+        PTSTDEVPLUGIN pPlugin = (PTSTDEVPLUGIN)RTMemAllocZ(sizeof(TSTDEVPLUGIN));
+        if (RT_LIKELY(pPlugin))
+        {
+            pPlugin->pszFilename = RTStrDup(pszFilename);
+            pPlugin->cRefs       = 1;
+            rc = RTLdrLoad(pszFilename, &pPlugin->hMod);
+            if (RT_SUCCESS(rc))
+            {
+                TSTDEVPLUGINREGISTER TestcaseRegister;
+                PFNTSTDEVPLUGINLOAD pfnPluginLoad = NULL;
+
+                TestcaseRegister.pfnRegisterTestcase = tstDevRegisterTestcase;
+
+                rc = RTLdrGetSymbol(pPlugin->hMod, TSTDEV_PLUGIN_LOAD_NAME, (void**)&pfnPluginLoad);
+                if (RT_FAILURE(rc) || !pfnPluginLoad)
+                {
+                    LogFunc(("error resolving the entry point %s in plugin %s, rc=%Rrc, pfnPluginLoad=%#p\n",
+                             TSTDEV_PLUGIN_LOAD_NAME, pszFilename, rc, pfnPluginLoad));
+                    if (RT_SUCCESS(rc))
+                        rc = VERR_SYMBOL_NOT_FOUND;
+                }
+
+                if (RT_SUCCESS(rc))
+                {
+                    /* Get the function table. */
+                    rc = pfnPluginLoad(pPlugin, &TestcaseRegister);
+                }
+                else
+                    LogFunc(("ignored plugin '%s': rc=%Rrc\n", pszFilename, rc));
+
+                /* Create a plugin entry on success. */
+                if (RT_SUCCESS(rc))
+                {
+                    RTListAppend(&g_LstPlugins, &pPlugin->NdPlugins);
+                    return VINF_SUCCESS;
+                }
+                else
+                    RTLdrClose(pPlugin->hMod);
+            }
+
+            RTMemFree(pPlugin);
+        }
+        else
+            rc = VERR_NO_MEMORY;
+    }
+
+    return rc;
+}
+
+
+/**
+ * Checks whether the given testcase name is already existing.
+ *
+ * @returns Pointer to already loaded plugin, NULL if not found.
+ * @param   pszFilename    The filename to check.
+ */
+static PCTSTDEVPDMDEV tstDevPdmDeviceFind(const char *pszName)
+{
+    PCTSTDEVPDMDEV pIt;
+    RTListForEach(&g_LstPdmDevs, pIt, TSTDEVPDMDEV, NdPdmDevs)
+    {
+        if (!RTStrCmp(pIt->pReg->szName, pszName))
+            return pIt;
+    }
+
+    return NULL;
+}
+
+
+/**
+ * Checks that a PDMDRVREG::szName, PDMDEVREG::szName or PDMUSBREG::szName
+ * field contains only a limited set of ASCII characters.
+ *
+ * @returns true / false.
+ * @param   pszName             The name to validate.
+ */
+bool tstDevPdmR3IsValidName(const char *pszName)
+{
+    char ch;
+    while (   (ch = *pszName) != '\0'
+           && (   RT_C_IS_ALNUM(ch)
+               || ch == '-'
+               || ch == ' ' /** @todo disallow this! */
+               || ch == '_') )
+        pszName++;
+    return ch == '\0';
+}
+
+
+/**
+ * @interface_method_impl{PDMDEVREGCB,pfnRegister}
+ */
+static DECLCALLBACK(int) tstDevPdmR3DevReg_Register(PPDMDEVREGCB pCallbacks, PCPDMDEVREG pReg)
+{
+    /*
+     * Validate the registration structure (mostly copy and paste from PDMDevice.cpp).
+     */
+    Assert(pReg);
+    AssertMsgReturn(pReg->u32Version == PDM_DEVREG_VERSION,
+                    ("Unknown struct version %#x!\n", pReg->u32Version),
+                    VERR_PDM_UNKNOWN_DEVREG_VERSION);
+
+    AssertMsgReturn(    pReg->szName[0]
+                    &&  strlen(pReg->szName) < sizeof(pReg->szName)
+                    &&  tstDevPdmR3IsValidName(pReg->szName),
+                    ("Invalid name '%.*s'\n", sizeof(pReg->szName), pReg->szName),
+                    VERR_PDM_INVALID_DEVICE_REGISTRATION);
+    AssertMsgReturn(   !(pReg->fFlags & PDM_DEVREG_FLAGS_RC)
+                    || (   pReg->szRCMod[0]
+                        && strlen(pReg->szRCMod) < sizeof(pReg->szRCMod)),
+                    ("Invalid GC module name '%s' - (Device %s)\n", pReg->szRCMod, pReg->szName),
+                    VERR_PDM_INVALID_DEVICE_REGISTRATION);
+    AssertMsgReturn(   !(pReg->fFlags & PDM_DEVREG_FLAGS_R0)
+                    || (   pReg->szR0Mod[0]
+                        && strlen(pReg->szR0Mod) < sizeof(pReg->szR0Mod)),
+                    ("Invalid R0 module name '%s' - (Device %s)\n", pReg->szR0Mod, pReg->szName),
+                    VERR_PDM_INVALID_DEVICE_REGISTRATION);
+    AssertMsgReturn((pReg->fFlags & PDM_DEVREG_FLAGS_HOST_BITS_MASK) == PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT,
+                    ("Invalid host bits flags! fFlags=%#x (Device %s)\n", pReg->fFlags, pReg->szName),
+                    VERR_PDM_INVALID_DEVICE_HOST_BITS);
+    AssertMsgReturn((pReg->fFlags & PDM_DEVREG_FLAGS_GUEST_BITS_MASK),
+                    ("Invalid guest bits flags! fFlags=%#x (Device %s)\n", pReg->fFlags, pReg->szName),
+                    VERR_PDM_INVALID_DEVICE_REGISTRATION);
+    AssertMsgReturn(pReg->fClass,
+                    ("No class! (Device %s)\n", pReg->szName),
+                    VERR_PDM_INVALID_DEVICE_REGISTRATION);
+    AssertMsgReturn(pReg->cMaxInstances > 0,
+                    ("Max instances %u! (Device %s)\n", pReg->cMaxInstances, pReg->szName),
+                    VERR_PDM_INVALID_DEVICE_REGISTRATION);
+    AssertMsgReturn(pReg->cbInstance <= (uint32_t)(pReg->fFlags & (PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0)  ? 96 * _1K : _1M),
+                    ("Instance size %d bytes! (Device %s)\n", pReg->cbInstance, pReg->szName),
+                    VERR_PDM_INVALID_DEVICE_REGISTRATION);
+    AssertMsgReturn(pReg->pfnConstruct,
+                    ("No constructor! (Device %s)\n", pReg->szName),
+                    VERR_PDM_INVALID_DEVICE_REGISTRATION);
+    AssertLogRelMsgReturn((pReg->fFlags & PDM_DEVREG_FLAGS_GUEST_BITS_MASK) == PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT,
+                          ("PDM: Rejected device '%s' because it didn't match the guest bits.\n", pReg->szName),
+                          VERR_PDM_INVALID_DEVICE_GUEST_BITS);
+    AssertLogRelMsg(pReg->u32VersionEnd == PDM_DEVREG_VERSION,
+                    ("u32VersionEnd=%#x, expected %#x. (szName=%s)\n",
+                     pReg->u32VersionEnd, PDM_DEVREG_VERSION, pReg->szName));
+
+    /*
+     * Check for duplicates.
+     */
+    int rc = VINF_SUCCESS;
+    PCTSTDEVPDMDEVREGCBINT pRegCB = (PCTSTDEVPDMDEVREGCBINT)pCallbacks;
+    if (!tstDevPdmDeviceFind(pReg->szName))
+    {
+        PTSTDEVPDMDEV pPdmDev = (PTSTDEVPDMDEV)RTMemAllocZ(sizeof(TSTDEVPDMDEV));
+        if (RT_LIKELY(pPdmDev))
+        {
+            pPdmDev->pPdmMod = pRegCB->pMod;
+            pRegCB->pMod->cRefs++;
+            pPdmDev->pReg = pReg;
+            RTListAppend(&g_LstPdmDevs, &pPdmDev->NdPdmDevs);
+            return VINF_SUCCESS;
+        }
+        else
+            rc = VERR_NO_MEMORY;
+    }
+    else
+        rc = VERR_PDM_DEVICE_NAME_CLASH;
+
+    return rc;
+}
+
+
+/**
+ * Checks whether the given PDM module filename was already loaded.
+ *
+ * @returns Pointer to already loaded plugin, NULL if not found.
+ * @param   pszFilename    The filename to check.
+ */
+static PCTSTDEVPDMMOD tstDevPdmModFind(const char *pszFilename)
+{
+    PCTSTDEVPDMMOD pIt;
+    RTListForEach(&g_LstPdmMods, pIt, TSTDEVPDMMOD, NdPdmMods)
+    {
+        if (!RTStrCmp(pIt->pszFilename, pszFilename))
+            return pIt;
+    }
+
+    return NULL;
+}
+
+
+/**
+ * Resolve an external symbol during RTLdrGetBits().
+ *
+ * @returns iprt status code.
+ * @param   hLdrMod         The loader module handle.
+ * @param   pszModule       Module name.
+ * @param   pszSymbol       Symbol name, NULL if uSymbol should be used.
+ * @param   uSymbol         Symbol ordinal, ~0 if pszSymbol should be used.
+ * @param   pValue          Where to store the symbol value (address).
+ * @param   pvUser          User argument.
+ */
+static DECLCALLBACK(int) tstDevPdmLoadR0RcModGetImport(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol,
+                                                       unsigned uSymbol, RTUINTPTR *pValue, void *pvUser)
+{
+    RT_NOREF(hLdrMod, uSymbol, pszModule);
+    PTSTDEVPDMMOD pMod = (PTSTDEVPDMMOD)pvUser;
+
+    /* Resolve the import. */
+    PCTSTDEVPDMR0IMPORTS pImpDesc = NULL;
+    bool fFound = false;
+    for (uint32_t i = 0; i < RT_ELEMENTS(g_aPdmR0Imports); i++)
+    {
+        pImpDesc = &g_aPdmR0Imports[i];
+        if (!strcmp(pszSymbol, pImpDesc->pszSymbol))
+        {
+            fFound = true;
+            break;
+        }
+    }
+
+    int rc = VERR_SYMBOL_NOT_FOUND;
+    if (fFound)
+    {
+        /* Check whether the symbol has a trampoline already. */
+        PTSTDEVPDMMODTRAMPOLINE pTrampoline = (PTSTDEVPDMMODTRAMPOLINE)pMod->R0Rc.pbTrampoline;
+        for (uint32_t i = 0; i < pMod->R0Rc.cTrampolines; i++)
+        {
+            if (pTrampoline->AddrTarget == (uintptr_t)pImpDesc->pfn)
+                break;
+            pTrampoline++;
+        }
+
+        /* Create new trampoline if not found. */
+        if (pTrampoline->AddrTarget != (uintptr_t)pImpDesc->pfn)
+        {
+            if (pMod->R0Rc.cTrampolines < pMod->R0Rc.cTrampolinesMax)
+            {
+                pTrampoline = pMod->R0Rc.pTrampolineNext;
+                pMod->R0Rc.pTrampolineNext++;
+                pMod->R0Rc.cTrampolines++;
+                pTrampoline->abJmp[0]   = 0xff; /* jmp */
+                pTrampoline->abJmp[1]   = 0x25; /* rip */
+                pTrampoline->abJmp[2]   = 0x00; /* offset */
+                pTrampoline->abJmp[3]   = 0x00;
+                pTrampoline->abJmp[4]   = 0x00;
+                pTrampoline->abJmp[5]   = 0x00;
+                pTrampoline->AddrTarget = (uintptr_t)pImpDesc->pfn;
+                rc = VINF_SUCCESS;
+            }
+            else
+            {
+                rc = VERR_SYMBOL_NOT_FOUND;
+                AssertFailed();
+            }
+        }
+        else
+            rc = VINF_SUCCESS;
+
+        if (RT_SUCCESS(rc))
+            *pValue = (RTUINTPTR)pTrampoline;
+    }
+    else
+        AssertFailed();
+
+    return rc;
+}
+
+
+/**
+ * Loads a new R0 modules given by the filename.
+ *
+ * @returns VBox status code.
+ * @param   pMod                    Pointer to module structure.
+ */
+static int tstDevPdmLoadR0RcMod(PTSTDEVPDMMOD pMod)
+{
+    int rc = VINF_SUCCESS;
+    const char *pszFile = RTPathFilename(pMod->pszFilename);
+
+    /* Check whether the plugin is loaded first. */
+    if (!tstDevPdmModFind(pszFile))
+    {
+        /*
+         * R0 modules need special treatment as these are relocatable images
+         * which are supposed to run in ring 0.
+         */
+        rc = RTLdrOpen(pMod->pszFilename, 0, RTLDRARCH_HOST, &pMod->hLdrMod);
+        if (RT_SUCCESS(rc))
+        {
+            size_t cb = RTLdrSize(pMod->hLdrMod) + 1024 * sizeof(TSTDEVPDMMODTRAMPOLINE);
+
+            /* Allocate bits. */
+            uint32_t fFlags = RTMEMALLOCEX_FLAGS_EXEC;
+#ifdef RT_OS_LINUX
+            /*
+             * amd64 ELF binaries support only a 2GB code segment everything must be in
+             * (X86_64_PC32 relocation) so we have to use a trampoline to the final destination
+             * which is kept close to the imported module.
+             */
+            fFlags |= RTMEMALLOCEX_FLAGS_32BIT_REACH;
+#endif
+            rc = RTMemAllocEx(cb, 0, fFlags, (void **)&pMod->R0Rc.pbTrampoline);
+            pMod->R0Rc.cbBits = cb;
+            if (RT_SUCCESS(rc))
+            {
+                pMod->R0Rc.pvBits          = pMod->R0Rc.pbTrampoline + 1024 * sizeof(TSTDEVPDMMODTRAMPOLINE);
+                pMod->R0Rc.cTrampolinesMax = 1024;
+                pMod->R0Rc.cTrampolines    = 0;
+                pMod->R0Rc.pTrampolineNext = (PTSTDEVPDMMODTRAMPOLINE)pMod->R0Rc.pbTrampoline;
+                /* Get the bits. */
+                rc = RTLdrGetBits(pMod->hLdrMod, pMod->R0Rc.pvBits, (uintptr_t)pMod->R0Rc.pvBits,
+                                  tstDevPdmLoadR0RcModGetImport, pMod);
+                if (RT_FAILURE(rc))
+                    RTMemFreeEx(pMod->R0Rc.pbTrampoline, pMod->R0Rc.cbBits);
+            }
+
+            if (RT_FAILURE(rc))
+                RTLdrClose(pMod->hLdrMod);
+        }
+    }
+
+    return rc;
+}
+
+
+/**
+ * Loads the given 
+ */
+static int tstDevPdmLoadR3Mod(PTSTDEVPDMMOD pMod)
+{
+    int rc = RTLdrLoad(pMod->pszFilename, &pMod->hLdrMod);
+    if (RT_SUCCESS(rc))
+    {
+        FNPDMVBOXDEVICESREGISTER *pfnVBoxDevicesRegister;
+        rc = RTLdrGetSymbol(pMod->hLdrMod, "VBoxDevicesRegister", (void**)&pfnVBoxDevicesRegister);
+        if (RT_FAILURE(rc) || !pfnVBoxDevicesRegister)
+        {
+            LogFunc(("error resolving the entry point %s in plugin %s, rc=%Rrc, pfnPluginLoad=%#p\n",
+                     "VBoxDevicesRegister", pMod->pszFilename, rc, pfnVBoxDevicesRegister));
+            if (RT_SUCCESS(rc))
+                rc = VERR_SYMBOL_NOT_FOUND;
+        }
+
+        if (RT_SUCCESS(rc))
+        {
+            TSTDEVPDMDEVREGCBINT RegCB;
+            RegCB.Core.u32Version  = PDM_DEVREG_CB_VERSION;
+            RegCB.Core.pfnRegister = tstDevPdmR3DevReg_Register;
+            RegCB.pMod             = pMod;
+            rc = pfnVBoxDevicesRegister(&RegCB.Core, VBOX_VERSION);
+        }
+        else
+            LogFunc(("ignored plugin '%s': rc=%Rrc\n", pMod->pszFilename, rc));
+
+        if (RT_FAILURE(rc))
+            RTLdrClose(pMod->hLdrMod);
+    }
+
+    return rc;
+}
+
+
+/**
+ * Tries to loads the given PDM module.
+ *
+ * @returns VBox status code.
+ * @param   pszFilename    The filename to load.
+ * @param   enmModType     The module type.
+ */
+static int tstDevPdmLoadMod(const char *pszFilename, TSTDEVPDMMODTYPE enmModType)
+{
+    int rc = VINF_SUCCESS;
+
+    /* Check whether the plugin is loaded first. */
+    if (!tstDevPdmModFind(pszFilename))
+    {
+        PTSTDEVPDMMOD pMod = (PTSTDEVPDMMOD)RTMemAllocZ(sizeof(TSTDEVPDMMOD));
+        if (RT_LIKELY(pMod))
+        {
+            pMod->pszFilename = RTStrDup(pszFilename);
+            pMod->cRefs       = 1;
+            pMod->enmType     = enmModType;
+
+            if (enmModType == TSTDEVPDMMODTYPE_R3)
+                rc = tstDevPdmLoadR3Mod(pMod);
+            else if (enmModType == TSTDEVPDMMODTYPE_RC || enmModType == TSTDEVPDMMODTYPE_R0)
+                rc = tstDevPdmLoadR0RcMod(pMod);
+
+            if (RT_SUCCESS(rc))
+                RTListAppend(&g_LstPdmMods, &pMod->NdPdmMods);
+            else
+                RTMemFree(pMod);
+        }
+        else
+            rc = VERR_NO_MEMORY;
+    }
+
+    return rc;
+}
+
+
+/**
+ * Tries to resolve the given symbol from the module given.
+ *
+ * @returns VBox status code.
+ * @param   pThis                   The device under test instance.
+ * @param   pszR0Mod                The R0 module.
+ * @param   pszSymbol               The symbol to resolve.
+ * @param   ppfn                    Where to store the value on success.
+ */
+DECLHIDDEN(int) tstDevPdmLdrGetSymbol(PDEVDUTINT pThis, const char *pszMod, TSTDEVPDMMODTYPE enmModType,
+                                      const char *pszSymbol, PFNRT *ppfn)
+{
+    RT_NOREF(pThis);
+
+    int rc = VINF_SUCCESS;
+    PCTSTDEVPDMMOD pMod = tstDevPdmModFind(pszMod);
+    if (!pMod)
+    {
+        /* Try to load the module. */
+        rc = tstDevPdmLoadMod(pszMod, enmModType);
+        if (RT_SUCCESS(rc))
+        {
+            pMod = tstDevPdmModFind(pszMod);
+            AssertPtr(pMod);
+        }
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        if (pMod->enmType == TSTDEVPDMMODTYPE_R0 || pMod->enmType == TSTDEVPDMMODTYPE_RC)
+            rc = RTLdrGetSymbolEx(pMod->hLdrMod, pMod->R0Rc.pvBits, (uintptr_t)pMod->R0Rc.pvBits,
+                                  UINT32_MAX, pszSymbol, (PRTLDRADDR)ppfn);
+        else
+            rc = RTLdrGetSymbol(pMod->hLdrMod, pszSymbol, (void **)ppfn);
+    }
+
+    return rc;
+}
+
+
+static TSTDEVTESTCASEREG s_TestcaseDef =
+{
+    "test",
+    "Testcase during implementation",
+    "serial",
+    0,
+    NULL,
+    NULL,
+};
+
+/**
+ * Create a new PDM device with default config.
+ *
+ * @returns VBox status code.
+ * @param   pszName                 Name of the device to create.
+ */
+static int tstDevPdmDevCreate(const char *pszName)
+{
+    int rc = VINF_SUCCESS;
+    PCTSTDEVPDMDEV pPdmDev = tstDevPdmDeviceFind(pszName);
+    if (RT_LIKELY(pPdmDev))
+    {
+        TSTDEVDUTINT Dut;
+        Dut.pTestcaseReg = &s_TestcaseDef;
+        Dut.enmCtx       = TSTDEVDUTCTX_R3;
+        RTListInit(&Dut.LstIoPorts);
+        RTListInit(&Dut.LstTimers);
+        CFGMNODE Cfg;
+        Cfg.pVmmCallbacks = &g_tstDevVmmCallbacks;
+        Cfg.pDut = &Dut;
+
+        PPDMDEVINS pDevIns = (PPDMDEVINS)RTMemAllocZ(RT_OFFSETOF(PDMDEVINS, achInstanceData[pPdmDev->pReg->cbInstance]));
+        pDevIns->u32Version               = PDM_DEVINS_VERSION;
+        pDevIns->iInstance                = 0;
+        pDevIns->pReg                     = pPdmDev->pReg;
+        pDevIns->pvInstanceDataR3         = &pDevIns->achInstanceData[0];
+        pDevIns->pHlpR3                   = &g_tstDevPdmDevHlpR3;
+        pDevIns->pCfg                     = &Cfg;
+        pDevIns->Internal.s.pVmmCallbacks = &g_tstDevVmmCallbacks;
+        pDevIns->Internal.s.pDut          = &Dut;
+        rc = pPdmDev->pReg->pfnConstruct(pDevIns, 0, &Cfg);
+        if (RT_SUCCESS(rc))
+        {
+            PRTDEVDUTIOPORT pIoPort = RTListGetFirst(&Dut.LstIoPorts, RTDEVDUTIOPORT, NdIoPorts);
+            uint32_t uVal = 0;
+            PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
+            pIoPort->pfnInR0(pDevIns, pIoPort->pvUserR0, pIoPort->PortStart, &uVal, sizeof(uint8_t));
+            PDMCritSectLeave(pDevIns->pCritSectRoR3);
+        }
+    }
+    else
+        rc = VERR_NOT_FOUND;
+
+    return rc;
+}
+
+int main(int argc, char *argv[])
+{
+    /*
+     * Init the runtime and parse the arguments.
+     */
+    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
+    int rc = RTR3InitExe(argc, &argv, 0);
+    if (RT_SUCCESS(rc))
+    {
+        RTListInit(&g_LstPlugins);
+        RTListInit(&g_LstTestcases);
+        RTListInit(&g_LstPdmMods);
+        RTListInit(&g_LstPdmDevs);
+
+        rc = tstDevLoadPlugin("TSTDevTestcases");
+        if (RT_SUCCESS(rc) || true)
+        {
+            rc = tstDevPdmLoadMod(argv[1], TSTDEVPDMMODTYPE_R3);
+            if (RT_SUCCESS(rc))
+                rc = tstDevPdmDevCreate("serial");
+            else
+                rcExit = RTEXITCODE_FAILURE;
+        }
+        else
+            rcExit = RTEXITCODE_FAILURE;
+
+        //rcExit = tstDevParseOptions(argc, argv);
+    }
+    else
+        rcExit = RTEXITCODE_FAILURE;
+
+    return rcExit;
+}
+
Index: trunk/src/VBox/Devices/testcase/tstDeviceInternal.h
===================================================================
--- trunk/src/VBox/Devices/testcase/tstDeviceInternal.h	(revision 69162)
+++ trunk/src/VBox/Devices/testcase/tstDeviceInternal.h	(revision 69162)
@@ -0,0 +1,136 @@
+/** @file
+ * tstDevice: Shared definitions between the framework and the shim library.
+ */
+
+/*
+ * Copyright (C) 2017 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.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___tstDeviceInternal_h
+#define ___tstDeviceInternal_h
+
+#include <VBox/types.h>
+#include <iprt/assert.h>
+#include <iprt/list.h>
+
+#include "tstDevicePlugin.h"
+#include "tstDeviceVMMInternal.h"
+
+RT_C_DECLS_BEGIN
+
+/**
+ * PDM module descriptor type.
+ */
+typedef enum TSTDEVPDMMODTYPE
+{
+    /** Invalid module type. */
+    TSTDEVPDMMODTYPE_INVALID = 0,
+    /** Ring 3 module. */
+    TSTDEVPDMMODTYPE_R3,
+    /** Ring 0 module. */
+    TSTDEVPDMMODTYPE_R0,
+    /** Raw context module. */
+    TSTDEVPDMMODTYPE_RC,
+    /** 32bit hack. */
+    TSTDEVPDMMODTYPE_32BIT_HACK = 0x7fffffff
+} TSTDEVPDMMODTYPE;
+
+/**
+ * Registered I/O port access handler.
+ */
+typedef struct RTDEVDUTIOPORT
+{
+    /** Node for the list of registered handlers. */
+    RTLISTNODE                      NdIoPorts;
+    /** Start I/O port the handler is for. */
+    RTIOPORT                        PortStart;
+    /** Number of ports handled. */
+    RTIOPORT                        cPorts;
+    /** Opaque user data - R3. */
+    void                            *pvUserR3;
+    /** Out handler - R3. */
+    PFNIOMIOPORTOUT                 pfnOutR3;
+    /** In handler - R3. */
+    PFNIOMIOPORTIN                  pfnInR3;
+    /** Out string handler - R3. */
+    PFNIOMIOPORTOUTSTRING           pfnOutStrR3;
+    /** In string handler - R3. */
+    PFNIOMIOPORTINSTRING            pfnInStrR3;
+
+    /** Opaque user data - R0. */
+    void                            *pvUserR0;
+    /** Out handler - R3. */
+    PFNIOMIOPORTOUT                 pfnOutR0;
+    /** In handler - R3. */
+    PFNIOMIOPORTIN                  pfnInR0;
+    /** Out string handler - R3. */
+    PFNIOMIOPORTOUTSTRING           pfnOutStrR0;
+    /** In string handler - R3. */
+    PFNIOMIOPORTINSTRING            pfnInStrR0;
+
+    /** @todo: RC */
+} RTDEVDUTIOPORT;
+/** Pointer to a registered I/O port handler. */
+typedef RTDEVDUTIOPORT *PRTDEVDUTIOPORT;
+/** Pointer to a const I/O port handler. */
+typedef const RTDEVDUTIOPORT *PCRTDEVDUTIOPORT;
+
+/**
+ * The contex the device under test is currently in.
+ */
+typedef enum TSTDEVDUTCTX
+{
+    /** Invalid context. */
+    TSTDEVDUTCTX_INVALID = 0,
+    /** R3 context. */
+    TSTDEVDUTCTX_R3,
+    /** R0 context. */
+    TSTDEVDUTCTX_R0,
+    /** RC context. */
+    TSTDEVDUTCTX_RC,
+    /** 32bit hack. */
+    TSTDEVDUTCTX_32BIT_HACK = 0x7fffffff
+} TSTDEVDUTCTX;
+
+/**
+ * Device under test instance data.
+ */
+typedef struct TSTDEVDUTINT
+{
+    /** Pointer to the testcase this device is part of. */
+    PCTSTDEVTESTCASEREG             pTestcaseReg;
+    /** Pointer to the PDM device instance. */
+    PPDMDEVINS                      pDevIns;
+    /** Current device context. */
+    TSTDEVDUTCTX                    enmCtx;
+    /** List of registered I/O port handlers. */
+    RTLISTANCHOR                    LstIoPorts;
+    /** List of timers registered. */
+    RTLISTANCHOR                    LstTimers;
+} TSTDEVDUTINT;
+/** Pointer to the internal device under test instance data. */
+typedef TSTDEVDUTINT *PDEVDUTINT;
+
+DECLHIDDEN(int) tstDevPdmLdrGetSymbol(PDEVDUTINT pThis, const char *pszR0Mod, TSTDEVPDMMODTYPE enmModType,
+                                      const char *pszSymbol, PFNRT *ppfn);
+
+RT_C_DECLS_END
+
+#endif
Index: trunk/src/VBox/Devices/testcase/tstDevicePdmDevHlp.cpp
===================================================================
--- trunk/src/VBox/Devices/testcase/tstDevicePdmDevHlp.cpp	(revision 69162)
+++ trunk/src/VBox/Devices/testcase/tstDevicePdmDevHlp.cpp	(revision 69162)
@@ -0,0 +1,1890 @@
+/* $Id$ */
+/** @file
+ * tstDevice - Test framework for PDM devices/drivers, PDM helper implementation.
+ */
+
+/*
+ * Copyright (C) 2017 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_DEFAULT /** @todo */
+#include <VBox/types.h>
+#include <VBox/version.h>
+#include <VBox/vmm/pdmpci.h>
+
+#include <iprt/mem.h>
+
+#include "tstDeviceInternal.h"
+
+/*********************************************************************************************************************************
+*   Defined Constants And Macros                                                                                                 *
+*********************************************************************************************************************************/
+
+/** @def PDMDEV_ASSERT_DEVINS
+ * Asserts the validity of the device instance.
+ */
+#ifdef VBOX_STRICT
+# define PDMDEV_ASSERT_DEVINS(pDevIns)   \
+    do { \
+        AssertPtr(pDevIns); \
+        Assert(pDevIns->u32Version == PDM_DEVINS_VERSION); \
+        Assert(pDevIns->CTX_SUFF(pvInstanceData) == (void *)&pDevIns->achInstanceData[0]); \
+    } while (0)
+#else
+# define PDMDEV_ASSERT_DEVINS(pDevIns)   do { } while (0)
+#endif
+
+
+/*********************************************************************************************************************************
+*   Structures and Typedefs                                                                                                      *
+*********************************************************************************************************************************/
+
+
+
+/*********************************************************************************************************************************
+*   Global Variables                                                                                                             *
+*********************************************************************************************************************************/
+
+
+
+/*********************************************************************************************************************************
+*   Internal Functions                                                                                                           *
+*********************************************************************************************************************************/
+
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnIOPortRegister} */
+static DECLCALLBACK(int) pdmR3DevHlp_IOPortRegister(PPDMDEVINS pDevIns, RTIOPORT Port, RTIOPORT cPorts, RTHCPTR pvUser, PFNIOMIOPORTOUT pfnOut, PFNIOMIOPORTIN pfnIn,
+                                                    PFNIOMIOPORTOUTSTRING pfnOutStr, PFNIOMIOPORTINSTRING pfnInStr, const char *pszDesc)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_IOPortRegister: caller='%s'/%d: Port=%#x cPorts=%#x pvUser=%p pfnOut=%p pfnIn=%p pfnOutStr=%p pfnInStr=%p p32_tszDesc=%p:{%s}\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, Port, cPorts, pvUser, pfnOut, pfnIn, pfnOutStr, pfnInStr, pszDesc, pszDesc));
+
+    /** @todo: Verify there is no overlapping. */
+
+    RT_NOREF(pszDesc);
+    int rc = VINF_SUCCESS;
+    PRTDEVDUTIOPORT pIoPort = (PRTDEVDUTIOPORT)RTMemAllocZ(sizeof(RTDEVDUTIOPORT));
+    if (RT_LIKELY(pIoPort))
+    {
+        pIoPort->PortStart   = Port;
+        pIoPort->cPorts      = cPorts;
+        pIoPort->pvUserR3    = pvUser;
+        pIoPort->pfnOutR3    = pfnOut;
+        pIoPort->pfnInR3     = pfnIn;
+        pIoPort->pfnOutStrR3 = pfnOutStr;
+        pIoPort->pfnInStrR3  = pfnInStr;
+        RTListAppend(&pDevIns->Internal.s.pDut->LstIoPorts, &pIoPort->NdIoPorts);
+    }
+    else
+        rc = VERR_NO_MEMORY;
+
+    LogFlow(("pdmR3DevHlp_IOPortRegister: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnIOPortRegisterRC} */
+static DECLCALLBACK(int) pdmR3DevHlp_IOPortRegisterRC(PPDMDEVINS pDevIns, RTIOPORT Port, RTIOPORT cPorts, RTRCPTR pvUser,
+                                                      const char *pszOut, const char *pszIn,
+                                                      const char *pszOutStr, const char *pszInStr, const char *pszDesc)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_IOPortRegisterRC: caller='%s'/%d: Port=%#x cPorts=%#x pvUser=%p pszOut=%p:{%s} pszIn=%p:{%s} pszOutStr=%p:{%s} pszInStr=%p:{%s} pszDesc=%p:{%s}\n", 
+             pDevIns->pReg->szName, pDevIns->iInstance, Port, cPorts, pvUser, pszOut, pszOut, pszIn, pszIn, pszOutStr, pszOutStr, pszInStr, pszInStr, pszDesc, pszDesc));
+
+    /** @todo */
+    int rc = VINF_SUCCESS;
+    //AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_IOPortRegisterRC: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnIOPortRegisterR0} */
+static DECLCALLBACK(int) pdmR3DevHlp_IOPortRegisterR0(PPDMDEVINS pDevIns, RTIOPORT Port, RTIOPORT cPorts, RTR0PTR pvUser,
+                                                      const char *pszOut, const char *pszIn,
+                                                      const char *pszOutStr, const char *pszInStr, const char *pszDesc)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_IOPortRegisterR0: caller='%s'/%d: Port=%#x cPorts=%#x pvUser=%p pszOut=%p:{%s} pszIn=%p:{%s} pszOutStr=%p:{%s} pszInStr=%p:{%s} pszDesc=%p:{%s}\n", 
+             pDevIns->pReg->szName, pDevIns->iInstance, Port, cPorts, pvUser, pszOut, pszOut, pszIn, pszIn, pszOutStr, pszOutStr, pszInStr, pszInStr, pszDesc, pszDesc));
+
+    PDEVDUTINT pThis = pDevIns->Internal.s.pDut;
+    PRTDEVDUTIOPORT pIoPort;
+    int rc = VERR_NOT_FOUND;
+    RTListForEach(&pThis->LstIoPorts, pIoPort, RTDEVDUTIOPORT, NdIoPorts)
+    {
+        /** @todo: Support overlapping port ranges. */
+        if (   pIoPort->PortStart == Port
+            && pIoPort->cPorts == cPorts)
+        {
+            rc = VINF_SUCCESS;
+            pIoPort->pvUserR0 = (void *)pvUser;
+            if (pszOut)
+                rc = tstDevPdmLdrGetSymbol(pThis, pDevIns->pReg->szR0Mod, TSTDEVPDMMODTYPE_R0, pszOut, (PFNRT *)&pIoPort->pfnOutR0);
+            if (RT_SUCCESS(rc) && pszIn)
+                rc = tstDevPdmLdrGetSymbol(pThis, pDevIns->pReg->szR0Mod, TSTDEVPDMMODTYPE_R0, pszIn, (PFNRT *)&pIoPort->pfnInR0);
+            if (RT_SUCCESS(rc) && pszOutStr)
+                rc = tstDevPdmLdrGetSymbol(pThis, pDevIns->pReg->szR0Mod, TSTDEVPDMMODTYPE_R0, pszOutStr, (PFNRT *)&pIoPort->pfnOutStrR0);
+            if (RT_SUCCESS(rc) && pszInStr)
+                rc = tstDevPdmLdrGetSymbol(pThis, pDevIns->pReg->szR0Mod, TSTDEVPDMMODTYPE_R0, pszInStr, (PFNRT *)&pIoPort->pfnInStrR0);
+            break;
+        }
+    }
+
+    LogFlow(("pdmR3DevHlp_IOPortRegisterR0: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnIOPortDeregister} */
+static DECLCALLBACK(int) pdmR3DevHlp_IOPortDeregister(PPDMDEVINS pDevIns, RTIOPORT Port, RTIOPORT cPorts)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_IOPortDeregister: caller='%s'/%d: Port=%#x cPorts=%#x\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, Port, cPorts));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_IOPortDeregister: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnMMIORegister} */
+static DECLCALLBACK(int) pdmR3DevHlp_MMIORegister(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, RTGCPHYS cbRange, RTHCPTR pvUser,
+                                                  PFNIOMMMIOWRITE pfnWrite, PFNIOMMMIOREAD pfnRead, PFNIOMMMIOFILL pfnFill,
+                                                  uint32_t fFlags, const char *pszDesc)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_MMIORegister: caller='%s'/%d: GCPhysStart=%RGp cbRange=%RGp pvUser=%p pfnWrite=%p pfnRead=%p pfnFill=%p fFlags=%#x pszDesc=%p:{%s}\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, GCPhysStart, cbRange, pvUser, pfnWrite, pfnRead, pfnFill, pszDesc, fFlags, pszDesc));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_MMIORegister: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnMMIORegisterRC} */
+static DECLCALLBACK(int) pdmR3DevHlp_MMIORegisterRC(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, RTGCPHYS cbRange, RTRCPTR pvUser,
+                                                    const char *pszWrite, const char *pszRead, const char *pszFill)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_MMIORegisterRC: caller='%s'/%d: GCPhysStart=%RGp cbRange=%RGp pvUser=%p pszWrite=%p:{%s} pszRead=%p:{%s} pszFill=%p:{%s}\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, GCPhysStart, cbRange, pvUser, pszWrite, pszWrite, pszRead, pszRead, pszFill, pszFill));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_MMIORegisterRC: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnMMIORegisterR0} */
+static DECLCALLBACK(int) pdmR3DevHlp_MMIORegisterR0(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, RTGCPHYS cbRange, RTR0PTR pvUser,
+                                                    const char *pszWrite, const char *pszRead, const char *pszFill)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_MMIORegisterHC: caller='%s'/%d: GCPhysStart=%RGp cbRange=%RGp pvUser=%p pszWrite=%p:{%s} pszRead=%p:{%s} pszFill=%p:{%s}\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, GCPhysStart, cbRange, pvUser, pszWrite, pszWrite, pszRead, pszRead, pszFill, pszFill));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_MMIORegisterR0: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnMMIODeregister} */
+static DECLCALLBACK(int) pdmR3DevHlp_MMIODeregister(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, RTGCPHYS cbRange)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_MMIODeregister: caller='%s'/%d: GCPhysStart=%RGp cbRange=%RGp\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, GCPhysStart, cbRange));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_MMIODeregister: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/**
+ * @copydoc PDMDEVHLPR3::pfnMMIO2Register
+ */
+static DECLCALLBACK(int) pdmR3DevHlp_MMIO2Register(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS cb,
+                                                   uint32_t fFlags, void **ppv, const char *pszDesc)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_MMIO2Register: caller='%s'/%d: pPciDev=%p (%#x) iRegion=%#x cb=%#RGp fFlags=%RX32 ppv=%p pszDescp=%p:{%s}\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pPciDev, pPciDev ? pPciDev->uDevFn : UINT32_MAX, iRegion,
+             cb, fFlags, ppv, pszDesc, pszDesc));
+    //AssertReturn(!pPciDev || pPciDev->Int.s.pDevInsR3 == pDevIns, VERR_INVALID_PARAMETER);
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_MMIO2Register: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/**
+ * @interface_method_impl{PDMDEVHLPR3,pfnMMIOExPreRegister}
+ */
+static DECLCALLBACK(int)
+pdmR3DevHlp_MMIOExPreRegister(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS cbRegion, uint32_t fFlags,
+                              const char *pszDesc,
+                              RTHCPTR pvUser, PFNIOMMMIOWRITE pfnWrite, PFNIOMMMIOREAD pfnRead, PFNIOMMMIOFILL pfnFill,
+                              RTR0PTR pvUserR0, const char *pszWriteR0, const char *pszReadR0, const char *pszFillR0,
+                              RTRCPTR pvUserRC, const char *pszWriteRC, const char *pszReadRC, const char *pszFillRC)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_MMIOExPreRegister: caller='%s'/%d: pPciDev=%p:{%#x} iRegion=%#x cbRegion=%#RGp fFlags=%RX32 pszDesc=%p:{%s}\n"
+             "                               pvUser=%p pfnWrite=%p pfnRead=%p pfnFill=%p\n"
+             "                               pvUserR0=%p pszWriteR0=%s pszReadR0=%s pszFillR0=%s\n"
+             "                               pvUserRC=%p pszWriteRC=%s pszReadRC=%s pszFillRC=%s\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pPciDev, pPciDev ? pPciDev->uDevFn : UINT32_MAX, iRegion, cbRegion,
+             fFlags, pszDesc, pszDesc,
+             pvUser, pfnWrite, pfnRead, pfnFill,
+             pvUserR0, pszWriteR0, pszReadR0, pszFillR0,
+             pvUserRC, pszWriteRC, pszReadRC, pszFillRC));
+    //AssertReturn(!pPciDev || pPciDev->Int.s.pDevInsR3 == pDevIns, VERR_INVALID_PARAMETER);
+
+    /*
+     * Resolve the functions.
+     */
+    AssertLogRelReturn(   (!pszWriteR0 && !pszReadR0 && !pszFillR0)
+                       || (pDevIns->pReg->szR0Mod[0] && (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_R0)),
+                       VERR_INVALID_PARAMETER);
+    AssertLogRelReturn(   (!pszWriteRC && !pszReadRC && !pszFillRC)
+                       || (pDevIns->pReg->szRCMod[0] && (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_RC)),
+                       VERR_INVALID_PARAMETER);
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_MMIOExPreRegister: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/**
+ * @copydoc PDMDEVHLPR3::pfnMMIOExDeregister
+ */
+static DECLCALLBACK(int) pdmR3DevHlp_MMIOExDeregister(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_MMIOExDeregister: caller='%s'/%d: pPciDev=%p:{%#x} iRegion=%#x\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pPciDev, pPciDev ? pPciDev->uDevFn : UINT32_MAX, iRegion));
+
+    AssertReturn(iRegion <= UINT8_MAX || iRegion == UINT32_MAX, VERR_INVALID_PARAMETER);
+    //AssertReturn(!pPciDev || pPciDev->Int.s.pDevInsR3 == pDevIns, VERR_INVALID_PARAMETER);
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_MMIOExDeregister: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/**
+ * @copydoc PDMDEVHLPR3::pfnMMIOExMap
+ */
+static DECLCALLBACK(int) pdmR3DevHlp_MMIOExMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS GCPhys)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_MMIOExMap: caller='%s'/%d: pPciDev=%p:{%#x} iRegion=%#x GCPhys=%#RGp\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pPciDev, pPciDev ? pPciDev->uDevFn : UINT32_MAX, iRegion, GCPhys));
+    //AssertReturn(!pPciDev || pPciDev->Int.s.pDevInsR3 != NULL, VERR_INVALID_PARAMETER);
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_MMIOExMap: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/**
+ * @copydoc PDMDEVHLPR3::pfnMMIOExUnmap
+ */
+static DECLCALLBACK(int) pdmR3DevHlp_MMIOExUnmap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS GCPhys)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_MMIOExUnmap: caller='%s'/%d: pPciDev=%p:{%#x} iRegion=%#x GCPhys=%#RGp\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pPciDev, pPciDev ? pPciDev->uDevFn : UINT32_MAX, iRegion, GCPhys));
+    //AssertReturn(!pPciDev || pPciDev->Int.s.pDevInsR3 != NULL, VERR_INVALID_PARAMETER);
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_MMIOExUnmap: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/**
+ * @copydoc PDMDEVHLPR3::pfnMMIOExReduce
+ */
+static DECLCALLBACK(int) pdmR3DevHlp_MMIOExReduce(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS cbRegion)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_MMIOExReduce: caller='%s'/%d: pPciDev=%p:{%#x} iRegion=%#x cbRegion=%RGp\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pPciDev, pPciDev ? pPciDev->uDevFn : UINT32_MAX, iRegion, cbRegion));
+    //AssertReturn(!pPciDev || pPciDev->Int.s.pDevInsR3 != NULL, VERR_INVALID_PARAMETER);
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_MMIOExReduce: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/**
+ * @copydoc PDMDEVHLPR3::pfnMMHyperMapMMIO2
+ */
+static DECLCALLBACK(int) pdmR3DevHlp_MMHyperMapMMIO2(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS off,
+                                                     RTGCPHYS cb, const char *pszDesc, PRTRCPTR pRCPtr)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_MMHyperMapMMIO2: caller='%s'/%d: pPciDev=%p:{%#x} iRegion=%#x off=%RGp cb=%RGp pszDesc=%p:{%s} pRCPtr=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pPciDev, pPciDev ? pPciDev->uDevFn : UINT32_MAX, iRegion, off, cb, pszDesc, pszDesc, pRCPtr));
+    //AssertReturn(!pPciDev || pPciDev->Int.s.pDevInsR3 == pDevIns, VERR_INVALID_PARAMETER);
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_MMHyperMapMMIO2: caller='%s'/%d: returns %Rrc *pRCPtr=%RRv\n", pDevIns->pReg->szName, pDevIns->iInstance, rc, *pRCPtr));
+    return rc;
+}
+
+
+/**
+ * @copydoc PDMDEVHLPR3::pfnMMIO2MapKernel
+ */
+static DECLCALLBACK(int) pdmR3DevHlp_MMIO2MapKernel(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS off,
+                                                    RTGCPHYS cb,const char *pszDesc, PRTR0PTR pR0Ptr)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_MMIO2MapKernel: caller='%s'/%d: pPciDev=%p:{%#x} iRegion=%#x off=%RGp cb=%RGp pszDesc=%p:{%s} pR0Ptr=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pPciDev, pPciDev ? pPciDev->uDevFn : UINT32_MAX, iRegion, off, cb, pszDesc, pszDesc, pR0Ptr));
+    //AssertReturn(!pPciDev || pPciDev->Int.s.pDevInsR3 == pDevIns, VERR_INVALID_PARAMETER);
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_MMIO2MapKernel: caller='%s'/%d: returns %Rrc *pR0Ptr=%RHv\n", pDevIns->pReg->szName, pDevIns->iInstance, rc, *pR0Ptr));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnROMRegister} */
+static DECLCALLBACK(int) pdmR3DevHlp_ROMRegister(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange,
+                                                 const void *pvBinary, uint32_t cbBinary, uint32_t fFlags, const char *pszDesc)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_ROMRegister: caller='%s'/%d: GCPhysStart=%RGp cbRange=%#x pvBinary=%p cbBinary=%#x fFlags=%#RX32 pszDesc=%p:{%s}\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, GCPhysStart, cbRange, pvBinary, cbBinary, fFlags, pszDesc, pszDesc));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_ROMRegister: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnROMProtectShadow} */
+static DECLCALLBACK(int) pdmR3DevHlp_ROMProtectShadow(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange, PGMROMPROT enmProt)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_ROMProtectShadow: caller='%s'/%d: GCPhysStart=%RGp cbRange=%#x enmProt=%d\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, GCPhysStart, cbRange, enmProt));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_ROMProtectShadow: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnSSMRegister} */
+static DECLCALLBACK(int) pdmR3DevHlp_SSMRegister(PPDMDEVINS pDevIns, uint32_t uVersion, size_t cbGuess, const char *pszBefore,
+                                                 PFNSSMDEVLIVEPREP pfnLivePrep, PFNSSMDEVLIVEEXEC pfnLiveExec, PFNSSMDEVLIVEVOTE pfnLiveVote,
+                                                 PFNSSMDEVSAVEPREP pfnSavePrep, PFNSSMDEVSAVEEXEC pfnSaveExec, PFNSSMDEVSAVEDONE pfnSaveDone,
+                                                 PFNSSMDEVLOADPREP pfnLoadPrep, PFNSSMDEVLOADEXEC pfnLoadExec, PFNSSMDEVLOADDONE pfnLoadDone)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_SSMRegister: caller='%s'/%d: uVersion=%#x cbGuess=%#x pszBefore=%p:{%s}\n"
+             "    pfnLivePrep=%p pfnLiveExec=%p pfnLiveVote=%p pfnSavePrep=%p pfnSaveExec=%p pfnSaveDone=%p pszLoadPrep=%p pfnLoadExec=%p pfnLoadDone=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, uVersion, cbGuess, pszBefore, pszBefore,
+             pfnLivePrep, pfnLiveExec, pfnLiveVote,
+             pfnSavePrep, pfnSaveExec, pfnSaveDone,
+             pfnLoadPrep, pfnLoadExec, pfnLoadDone));
+
+    /** @todo */
+    int rc = VINF_SUCCESS;
+    //AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_SSMRegister: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnTMTimerCreate} */
+static DECLCALLBACK(int) pdmR3DevHlp_TMTimerCreate(PPDMDEVINS pDevIns, TMCLOCK enmClock, PFNTMTIMERDEV pfnCallback, void *pvUser,
+                                                   uint32_t fFlags, const char *pszDesc, PPTMTIMERR3 ppTimer)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_TMTimerCreate: caller='%s'/%d: enmClock=%d pfnCallback=%p pvUser=%p fFlags=%#x pszDesc=%p:{%s} ppTimer=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, enmClock, pfnCallback, pvUser, fFlags, pszDesc, pszDesc, ppTimer));
+
+    int rc = VINF_SUCCESS;
+    PTMTIMERR3 pTimer = (PTMTIMERR3)RTMemAllocZ(sizeof(TMTIMER));
+    if (RT_LIKELY(pTimer))
+    {
+        pTimer->pVmmCallbacks  = pDevIns->Internal.s.pVmmCallbacks;
+        pTimer->enmClock       = enmClock;
+        pTimer->pfnCallbackDev = pfnCallback;
+        pTimer->pvUser         = pvUser;
+        pTimer->fFlags         = fFlags;
+        RTListAppend(&pDevIns->Internal.s.pDut->LstTimers, &pTimer->NdDevTimers);
+        *ppTimer = pTimer;
+    }
+    else
+        rc = VERR_NO_MEMORY;
+
+    LogFlow(("pdmR3DevHlp_TMTimerCreate: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnTMUtcNow} */
+static DECLCALLBACK(PRTTIMESPEC) pdmR3DevHlp_TMUtcNow(PPDMDEVINS pDevIns, PRTTIMESPEC pTime)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_TMUtcNow: caller='%s'/%d: pTime=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pTime));
+
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_TMUtcNow: caller='%s'/%d: returns %RU64\n", pDevIns->pReg->szName, pDevIns->iInstance, RTTimeSpecGetNano(pTime)));
+    return pTime;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnTMTimeVirtGet} */
+static DECLCALLBACK(uint64_t) pdmR3DevHlp_TMTimeVirtGet(PPDMDEVINS pDevIns)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_TMTimeVirtGet: caller='%s'/%d\n",
+             pDevIns->pReg->szName, pDevIns->iInstance));
+
+    uint64_t u64Time = 0;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_TMTimeVirtGet: caller='%s'/%d: returns %RU64\n", pDevIns->pReg->szName, pDevIns->iInstance, u64Time));
+    return u64Time;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnTMTimeVirtGetFreq} */
+static DECLCALLBACK(uint64_t) pdmR3DevHlp_TMTimeVirtGetFreq(PPDMDEVINS pDevIns)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_TMTimeVirtGetFreq: caller='%s'/%d\n",
+             pDevIns->pReg->szName, pDevIns->iInstance));
+
+    uint64_t u64Freq = 0;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_TMTimeVirtGetFreq: caller='%s'/%d: returns %RU64\n", pDevIns->pReg->szName, pDevIns->iInstance, u64Freq));
+    return u64Freq;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnTMTimeVirtGetNano} */
+static DECLCALLBACK(uint64_t) pdmR3DevHlp_TMTimeVirtGetNano(PPDMDEVINS pDevIns)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_TMTimeVirtGetNano: caller='%s'/%d\n",
+             pDevIns->pReg->szName, pDevIns->iInstance));
+
+    uint64_t u64Nano = 0;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_TMTimeVirtGetNano: caller='%s'/%d: returns %RU64\n", pDevIns->pReg->szName, pDevIns->iInstance, u64Nano));
+    return u64Nano;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnGetSupDrvSession} */
+static DECLCALLBACK(PSUPDRVSESSION) pdmR3DevHlp_GetSupDrvSession(PPDMDEVINS pDevIns)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_GetSupDrvSession: caller='%s'/%d\n",
+             pDevIns->pReg->szName, pDevIns->iInstance));
+
+    PSUPDRVSESSION pSession = 0;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_GetSupDrvSession: caller='%s'/%d: returns %#p\n", pDevIns->pReg->szName, pDevIns->iInstance, pSession));
+    return pSession;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnQueryGenericUserObject} */
+static DECLCALLBACK(void *) pdmR3DevHlp_QueryGenericUserObject(PPDMDEVINS pDevIns, PCRTUUID pUuid)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_QueryGenericUserObject: caller='%s'/%d: pUuid=%p:%RTuuid\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pUuid, pUuid));
+
+    void *pvRet = NULL;
+
+    LogRel(("pdmR3DevHlp_QueryGenericUserObject: caller='%s'/%d: returns %#p for %RTuuid\n",
+            pDevIns->pReg->szName, pDevIns->iInstance, pvRet, pUuid));
+    return pvRet;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnPhysRead} */
+static DECLCALLBACK(int) pdmR3DevHlp_PhysRead(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_PhysRead: caller='%s'/%d: GCPhys=%RGp pvBuf=%p cbRead=%#x\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, GCPhys, pvBuf, cbRead));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    Log(("pdmR3DevHlp_PhysRead: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnPhysWrite} */
+static DECLCALLBACK(int) pdmR3DevHlp_PhysWrite(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_PhysWrite: caller='%s'/%d: GCPhys=%RGp pvBuf=%p cbWrite=%#x\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, GCPhys, pvBuf, cbWrite));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    Log(("pdmR3DevHlp_PhysWrite: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnPhysGCPhys2CCPtr} */
+static DECLCALLBACK(int) pdmR3DevHlp_PhysGCPhys2CCPtr(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint32_t fFlags, void **ppv, PPGMPAGEMAPLOCK pLock)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_PhysGCPhys2CCPtr: caller='%s'/%d: GCPhys=%RGp fFlags=%#x ppv=%p pLock=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, GCPhys, fFlags, ppv, pLock));
+    AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    Log(("pdmR3DevHlp_PhysGCPhys2CCPtr: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnPhysGCPhys2CCPtrReadOnly} */
+static DECLCALLBACK(int) pdmR3DevHlp_PhysGCPhys2CCPtrReadOnly(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint32_t fFlags, const void **ppv, PPGMPAGEMAPLOCK pLock)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_PhysGCPhys2CCPtrReadOnly: caller='%s'/%d: GCPhys=%RGp fFlags=%#x ppv=%p pLock=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, GCPhys, fFlags, ppv, pLock));
+    AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    Log(("pdmR3DevHlp_PhysGCPhys2CCPtrReadOnly: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnPhysReleasePageMappingLock} */
+static DECLCALLBACK(void) pdmR3DevHlp_PhysReleasePageMappingLock(PPDMDEVINS pDevIns, PPGMPAGEMAPLOCK pLock)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_PhysReleasePageMappingLock: caller='%s'/%d: pLock=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pLock));
+
+    AssertFailed();
+
+    Log(("pdmR3DevHlp_PhysReleasePageMappingLock: caller='%s'/%d: returns void\n", pDevIns->pReg->szName, pDevIns->iInstance));
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnPhysReadGCVirt} */
+static DECLCALLBACK(int) pdmR3DevHlp_PhysReadGCVirt(PPDMDEVINS pDevIns, void *pvDst, RTGCPTR GCVirtSrc, size_t cb)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_PhysReadGCVirt: caller='%s'/%d: pvDst=%p GCVirt=%RGv cb=%#x\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pvDst, GCVirtSrc, cb));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_PhysReadGCVirt: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnPhysWriteGCVirt} */
+static DECLCALLBACK(int) pdmR3DevHlp_PhysWriteGCVirt(PPDMDEVINS pDevIns, RTGCPTR GCVirtDst, const void *pvSrc, size_t cb)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_PhysWriteGCVirt: caller='%s'/%d: GCVirtDst=%RGv pvSrc=%p cb=%#x\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, GCVirtDst, pvSrc, cb));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_PhysWriteGCVirt: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnPhysGCPtr2GCPhys} */
+static DECLCALLBACK(int) pdmR3DevHlp_PhysGCPtr2GCPhys(PPDMDEVINS pDevIns, RTGCPTR GCPtr, PRTGCPHYS pGCPhys)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_PhysGCPtr2GCPhys: caller='%s'/%d: GCPtr=%RGv pGCPhys=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, GCPtr, pGCPhys));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_PhysGCPtr2GCPhys: caller='%s'/%d: returns %Rrc *pGCPhys=%RGp\n", pDevIns->pReg->szName, pDevIns->iInstance, rc, *pGCPhys));
+
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnMMHeapAlloc} */
+static DECLCALLBACK(void *) pdmR3DevHlp_MMHeapAlloc(PPDMDEVINS pDevIns, size_t cb)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_MMHeapAlloc: caller='%s'/%d: cb=%#x\n", pDevIns->pReg->szName, pDevIns->iInstance, cb));
+
+    void *pv = NULL;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_MMHeapAlloc: caller='%s'/%d: returns %p\n", pDevIns->pReg->szName, pDevIns->iInstance, pv));
+    return pv;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnMMHeapAllocZ} */
+static DECLCALLBACK(void *) pdmR3DevHlp_MMHeapAllocZ(PPDMDEVINS pDevIns, size_t cb)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_MMHeapAllocZ: caller='%s'/%d: cb=%#x\n", pDevIns->pReg->szName, pDevIns->iInstance, cb));
+
+    void *pv = NULL;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_MMHeapAllocZ: caller='%s'/%d: returns %p\n", pDevIns->pReg->szName, pDevIns->iInstance, pv));
+    return pv;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnMMHeapFree} */
+static DECLCALLBACK(void) pdmR3DevHlp_MMHeapFree(PPDMDEVINS pDevIns, void *pv)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns); RT_NOREF_PV(pDevIns);
+    LogFlow(("pdmR3DevHlp_MMHeapFree: caller='%s'/%d: pv=%p\n", pDevIns->pReg->szName, pDevIns->iInstance, pv));
+
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_MMHeapAlloc: caller='%s'/%d: returns void\n", pDevIns->pReg->szName, pDevIns->iInstance));
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnVMState} */
+static DECLCALLBACK(VMSTATE) pdmR3DevHlp_VMState(PPDMDEVINS pDevIns)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+
+    VMSTATE enmVMState = VMSTATE_CREATING;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_VMState: caller='%s'/%d: returns %d\n", pDevIns->pReg->szName, pDevIns->iInstance,
+             enmVMState));
+    return enmVMState;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnVMTeleportedAndNotFullyResumedYet} */
+static DECLCALLBACK(bool) pdmR3DevHlp_VMTeleportedAndNotFullyResumedYet(PPDMDEVINS pDevIns)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+
+    bool fRc = false;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_VMState: caller='%s'/%d: returns %RTbool\n", pDevIns->pReg->szName, pDevIns->iInstance,
+             fRc));
+    return fRc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnVMSetError} */
+static DECLCALLBACK(int) pdmR3DevHlp_VMSetError(PPDMDEVINS pDevIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    RT_NOREF(rc, pszFile, iLine, pszFunction, pszFormat);
+    rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnVMSetErrorV} */
+static DECLCALLBACK(int) pdmR3DevHlp_VMSetErrorV(PPDMDEVINS pDevIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    RT_NOREF(rc, pszFile, iLine, pszFunction, pszFormat, va);
+    rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnVMSetRuntimeError} */
+static DECLCALLBACK(int) pdmR3DevHlp_VMSetRuntimeError(PPDMDEVINS pDevIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    RT_NOREF(fFlags, pszErrorId, pszFormat);
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnVMSetRuntimeErrorV} */
+static DECLCALLBACK(int) pdmR3DevHlp_VMSetRuntimeErrorV(PPDMDEVINS pDevIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    RT_NOREF(fFlags, pszErrorId, pszFormat, va);
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnDBGFStopV} */
+static DECLCALLBACK(int) pdmR3DevHlp_DBGFStopV(PPDMDEVINS pDevIns, const char *pszFile, unsigned iLine, const char *pszFunction, const char *pszFormat, va_list args)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+#ifdef LOG_ENABLED
+    va_list va2;
+    va_copy(va2, args);
+    LogFlow(("pdmR3DevHlp_DBGFStopV: caller='%s'/%d: pszFile=%p:{%s} iLine=%d pszFunction=%p:{%s} pszFormat=%p:{%s} (%N)\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pszFile, pszFile, iLine, pszFunction, pszFunction, pszFormat, pszFormat, pszFormat, &va2));
+    va_end(va2);
+#endif
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_DBGFStopV: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnDBGFInfoRegister} */
+static DECLCALLBACK(int) pdmR3DevHlp_DBGFInfoRegister(PPDMDEVINS pDevIns, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDEV pfnHandler)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_DBGFInfoRegister: caller='%s'/%d: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pszName, pszName, pszDesc, pszDesc, pfnHandler));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_DBGFInfoRegister: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnDBGFRegRegister} */
+static DECLCALLBACK(int) pdmR3DevHlp_DBGFRegRegister(PPDMDEVINS pDevIns, PCDBGFREGDESC paRegisters)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_DBGFRegRegister: caller='%s'/%d: paRegisters=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, paRegisters));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_DBGFRegRegister: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnDBGFTraceBuf} */
+static DECLCALLBACK(RTTRACEBUF) pdmR3DevHlp_DBGFTraceBuf(PPDMDEVINS pDevIns)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    RTTRACEBUF hTraceBuf = NULL;
+    AssertFailed();
+    LogFlow(("pdmR3DevHlp_DBGFTraceBuf: caller='%s'/%d: returns %p\n", pDevIns->pReg->szName, pDevIns->iInstance, hTraceBuf));
+    return hTraceBuf;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnSTAMRegister} */
+static DECLCALLBACK(void) pdmR3DevHlp_STAMRegister(PPDMDEVINS pDevIns, void *pvSample, STAMTYPE enmType, const char *pszName,
+                                                   STAMUNIT enmUnit, const char *pszDesc)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    RT_NOREF(pvSample, enmType, pszName, enmUnit, pszDesc);
+    AssertFailed();
+}
+
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnSTAMRegisterF} */
+static DECLCALLBACK(void) pdmR3DevHlp_STAMRegisterF(PPDMDEVINS pDevIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
+                                                    STAMUNIT enmUnit, const char *pszDesc, const char *pszName, ...)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    RT_NOREF(pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName);
+    AssertFailed();
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnSTAMRegisterV} */
+static DECLCALLBACK(void) pdmR3DevHlp_STAMRegisterV(PPDMDEVINS pDevIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
+                                                    STAMUNIT enmUnit, const char *pszDesc, const char *pszName, va_list args)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    RT_NOREF(pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, args);
+    AssertFailed();
+}
+
+
+/**
+ * @interface_method_impl{PDMDEVHLPR3,pfnPCIRegister}
+ */
+static DECLCALLBACK(int) pdmR3DevHlp_PCIRegister(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t idxDevCfg, uint32_t fFlags,
+                                                 uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_PCIRegister: caller='%s'/%d: pPciDev=%p:{.config={%#.256Rhxs} idxDevCfg=%d fFlags=%#x uPciDevNo=%#x uPciFunNo=%#x pszName=%p:{%s}\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pPciDev, pPciDev->abConfig, idxDevCfg, fFlags, uPciDevNo, uPciFunNo, pszName, pszName ? pszName : ""));
+
+    /*
+     * Validate input.
+     */
+    AssertLogRelMsgReturn(RT_VALID_PTR(pPciDev),
+                          ("'%s'/%d: Invalid pPciDev value: %p\n", pDevIns->pReg->szName, pDevIns->iInstance, pPciDev),
+                          VERR_INVALID_POINTER);
+    AssertLogRelMsgReturn(PDMPciDevGetVendorId(pPciDev),
+                          ("'%s'/%d: Vendor ID is not set!\n", pDevIns->pReg->szName, pDevIns->iInstance),
+                          VERR_INVALID_POINTER);
+    AssertLogRelMsgReturn(idxDevCfg < 256 || idxDevCfg == PDMPCIDEVREG_CFG_NEXT,
+                          ("'%s'/%d: Invalid config selector: %#x\n", pDevIns->pReg->szName, pDevIns->iInstance, idxDevCfg),
+                          VERR_OUT_OF_RANGE);
+    AssertLogRelMsgReturn(   uPciDevNo < 32
+                          || uPciDevNo == PDMPCIDEVREG_DEV_NO_FIRST_UNUSED
+                          || uPciDevNo == PDMPCIDEVREG_DEV_NO_SAME_AS_PREV,
+                          ("'%s'/%d: Invalid PCI device number: %#x\n", pDevIns->pReg->szName, pDevIns->iInstance, uPciDevNo),
+                          VERR_INVALID_PARAMETER);
+    AssertLogRelMsgReturn(   uPciFunNo < 8
+                          || uPciFunNo == PDMPCIDEVREG_FUN_NO_FIRST_UNUSED,
+                          ("'%s'/%d: Invalid PCI funcion number: %#x\n", pDevIns->pReg->szName, pDevIns->iInstance, uPciFunNo),
+                          VERR_INVALID_PARAMETER);
+    AssertLogRelMsgReturn(!(fFlags & ~PDMPCIDEVREG_F_VALID_MASK),
+                          ("'%s'/%d: Invalid flags: %#x\n", pDevIns->pReg->szName, pDevIns->iInstance, fFlags),
+                          VERR_INVALID_FLAGS);
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_PCIRegister: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnPCIRegisterMsi} */
+static DECLCALLBACK(int) pdmR3DevHlp_PCIRegisterMsi(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, PPDMMSIREG pMsiReg)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_PCIRegisterMsi: caller='%s'/%d: pPciDev=%p:{%#x} pMsgReg=%p:{cMsiVectors=%d, cMsixVectors=%d}\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pPciDev, pPciDev->uDevFn, pMsiReg, pMsiReg->cMsiVectors, pMsiReg->cMsixVectors));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_PCIRegisterMsi: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnPCIIORegionRegister} */
+static DECLCALLBACK(int) pdmR3DevHlp_PCIIORegionRegister(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
+                                                         RTGCPHYS cbRegion, PCIADDRESSSPACE enmType, PFNPCIIOREGIONMAP pfnCallback)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_PCIIORegionRegister: caller='%s'/%d: pPciDev=%p:{%#x} iRegion=%d cbRegion=%RGp enmType=%d pfnCallback=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pPciDev, pPciDev->uDevFn, iRegion, cbRegion, enmType, pfnCallback));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_PCIIORegionRegister: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnPCISetConfigCallbacks} */
+static DECLCALLBACK(void) pdmR3DevHlp_PCISetConfigCallbacks(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, PFNPCICONFIGREAD pfnRead, PPFNPCICONFIGREAD ppfnReadOld,
+                                                            PFNPCICONFIGWRITE pfnWrite, PPFNPCICONFIGWRITE ppfnWriteOld)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_PCISetConfigCallbacks: caller='%s'/%d: pPciDev=%p pfnRead=%p ppfnReadOld=%p pfnWrite=%p ppfnWriteOld=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pPciDev, pfnRead, ppfnReadOld, pfnWrite, ppfnWriteOld));
+
+    /*
+     * Validate input and resolve defaults.
+     */
+    AssertPtr(pfnRead);
+    AssertPtr(pfnWrite);
+    AssertPtrNull(ppfnReadOld);
+    AssertPtrNull(ppfnWriteOld);
+    AssertPtrNull(pPciDev);
+
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_PCISetConfigCallbacks: caller='%s'/%d: returns void\n", pDevIns->pReg->szName, pDevIns->iInstance));
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnPCIPhysRead} */
+static DECLCALLBACK(int) pdmR3DevHlp_PCIPhysRead(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    RT_NOREF(pPciDev);
+    return pDevIns->pHlpR3->pfnPhysRead(pDevIns, GCPhys, pvBuf, cbRead);
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnPCIPhysWrite} */
+static DECLCALLBACK(int)
+pdmR3DevHlp_PCIPhysWrite(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    RT_NOREF(pPciDev);
+    return pDevIns->pHlpR3->pfnPhysWrite(pDevIns, GCPhys, pvBuf, cbWrite);
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnPCISetIrq} */
+static DECLCALLBACK(void) pdmR3DevHlp_PCISetIrq(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_PCISetIrq: caller='%s'/%d: pPciDev=%p:{%#x} iIrq=%d iLevel=%d\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pPciDev, pPciDev->uDevFn, iIrq, iLevel));
+
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_PCISetIrq: caller='%s'/%d: returns void\n", pDevIns->pReg->szName, pDevIns->iInstance));
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnPCISetIrqNoWait} */
+static DECLCALLBACK(void) pdmR3DevHlp_PCISetIrqNoWait(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel)
+{
+    pdmR3DevHlp_PCISetIrq(pDevIns, pPciDev, iIrq, iLevel);
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnISASetIrq} */
+static DECLCALLBACK(void) pdmR3DevHlp_ISASetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_ISASetIrq: caller='%s'/%d: iIrq=%d iLevel=%d\n", pDevIns->pReg->szName, pDevIns->iInstance, iIrq, iLevel));
+
+    //AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_ISASetIrq: caller='%s'/%d: returns void\n", pDevIns->pReg->szName, pDevIns->iInstance));
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnISASetIrqNoWait} */
+static DECLCALLBACK(void) pdmR3DevHlp_ISASetIrqNoWait(PPDMDEVINS pDevIns, int iIrq, int iLevel)
+{
+    pdmR3DevHlp_ISASetIrq(pDevIns, iIrq, iLevel);
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnIoApicSendMsi} */
+static DECLCALLBACK(void) pdmR3DevHlp_IoApicSendMsi(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint32_t uValue)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_IoApicSendMsi: caller='%s'/%d: GCPhys=%RGp uValue=%#x\n", pDevIns->pReg->szName, pDevIns->iInstance, GCPhys, uValue));
+
+    /*
+     * Validate input.
+     */
+    Assert(GCPhys != 0);
+    Assert(uValue != 0);
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_IoApicSendMsi: caller='%s'/%d: returns void\n", pDevIns->pReg->szName, pDevIns->iInstance));
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnDriverAttach} */
+static DECLCALLBACK(int) pdmR3DevHlp_DriverAttach(PPDMDEVINS pDevIns, uint32_t iLun, PPDMIBASE pBaseInterface, PPDMIBASE *ppBaseInterface, const char *pszDesc)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_DriverAttach: caller='%s'/%d: iLun=%d pBaseInterface=%p ppBaseInterface=%p pszDesc=%p:{%s}\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, iLun, pBaseInterface, ppBaseInterface, pszDesc, pszDesc));
+
+    /** @todo */
+    int rc = VERR_PDM_NO_ATTACHED_DRIVER;
+    //AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_DriverAttach: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnDriverDetach} */
+static DECLCALLBACK(int) pdmR3DevHlp_DriverDetach(PPDMDEVINS pDevIns, PPDMDRVINS pDrvIns, uint32_t fFlags)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns); RT_NOREF_PV(pDevIns);
+    LogFlow(("pdmR3DevHlp_DriverDetach: caller='%s'/%d: pDrvIns=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pDrvIns));
+
+    RT_NOREF(fFlags);
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_DriverDetach: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnQueueCreate} */
+static DECLCALLBACK(int) pdmR3DevHlp_QueueCreate(PPDMDEVINS pDevIns, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval,
+                                                 PFNPDMQUEUEDEV pfnCallback, bool fRZEnabled, const char *pszName, PPDMQUEUE *ppQueue)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_QueueCreate: caller='%s'/%d: cbItem=%#x cItems=%#x cMilliesInterval=%u pfnCallback=%p fRZEnabled=%RTbool pszName=%p:{%s} ppQueue=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, cbItem, cItems, cMilliesInterval, pfnCallback, fRZEnabled, pszName, pszName, ppQueue));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_QueueCreate: caller='%s'/%d: returns %Rrc *ppQueue=%p\n", pDevIns->pReg->szName, pDevIns->iInstance, rc, *ppQueue));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnCritSectInit} */
+static DECLCALLBACK(int) pdmR3DevHlp_CritSectInit(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL,
+                                                  const char *pszNameFmt, va_list va)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_CritSectInit: caller='%s'/%d: pCritSect=%p pszNameFmt=%p:{%s}\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pCritSect, pszNameFmt, pszNameFmt));
+
+    RT_NOREF(RT_SRC_POS_ARGS, pszNameFmt, pCritSect, va);
+    int rc = RTCritSectInit(&pCritSect->s.CritSect);
+    if (RT_SUCCESS(rc))
+        pCritSect->s.pVmmCallbacks = pDevIns->Internal.s.pVmmCallbacks;
+
+    LogFlow(("pdmR3DevHlp_CritSectInit: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnCritSectGetNop} */
+static DECLCALLBACK(PPDMCRITSECT) pdmR3DevHlp_CritSectGetNop(PPDMDEVINS pDevIns)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+
+    AssertFailed();
+    PPDMCRITSECT pCritSect = NULL;
+
+    LogFlow(("pdmR3DevHlp_CritSectGetNop: caller='%s'/%d: return %p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pCritSect));
+    return pCritSect;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnCritSectGetNopR0} */
+static DECLCALLBACK(R0PTRTYPE(PPDMCRITSECT)) pdmR3DevHlp_CritSectGetNopR0(PPDMDEVINS pDevIns)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+
+    R0PTRTYPE(PPDMCRITSECT) pCritSect = 0;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_CritSectGetNopR0: caller='%s'/%d: return %RHv\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pCritSect));
+    return pCritSect;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnCritSectGetNopRC} */
+static DECLCALLBACK(RCPTRTYPE(PPDMCRITSECT)) pdmR3DevHlp_CritSectGetNopRC(PPDMDEVINS pDevIns)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+
+    RCPTRTYPE(PPDMCRITSECT) pCritSect = 0;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_CritSectGetNopRC: caller='%s'/%d: return %RRv\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pCritSect));
+    return pCritSect;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnSetDeviceCritSect} */
+static DECLCALLBACK(int) pdmR3DevHlp_SetDeviceCritSect(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)
+{
+    /*
+     * Validate input.
+     *
+     * Note! We only allow the automatically created default critical section
+     *       to be replaced by this API.
+     */
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    AssertPtrReturn(pCritSect, VERR_INVALID_POINTER);
+    LogFlow(("pdmR3DevHlp_SetDeviceCritSect: caller='%s'/%d: pCritSect=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pCritSect));
+
+    /** @todo: Implement default atomatic critical section. */
+    pDevIns->pCritSectRoR3 = pCritSect;
+
+    LogFlow(("pdmR3DevHlp_SetDeviceCritSect: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, VINF_SUCCESS));
+    return VINF_SUCCESS;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnThreadCreate} */
+static DECLCALLBACK(int) pdmR3DevHlp_ThreadCreate(PPDMDEVINS pDevIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADDEV pfnThread,
+                                                  PFNPDMTHREADWAKEUPDEV pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_ThreadCreate: caller='%s'/%d: ppThread=%p pvUser=%p pfnThread=%p pfnWakeup=%p cbStack=%#zx enmType=%d pszName=%p:{%s}\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName, pszName));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_ThreadCreate: caller='%s'/%d: returns %Rrc *ppThread=%RTthrd\n", pDevIns->pReg->szName, pDevIns->iInstance,
+            rc, *ppThread));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnSetAsyncNotification} */
+static DECLCALLBACK(int) pdmR3DevHlp_SetAsyncNotification(PPDMDEVINS pDevIns, PFNPDMDEVASYNCNOTIFY pfnAsyncNotify)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_SetAsyncNotification: caller='%s'/%d: pfnAsyncNotify=%p\n", pDevIns->pReg->szName, pDevIns->iInstance, pfnAsyncNotify));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_SetAsyncNotification: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnAsyncNotificationCompleted} */
+static DECLCALLBACK(void) pdmR3DevHlp_AsyncNotificationCompleted(PPDMDEVINS pDevIns)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    AssertFailed();
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnRTCRegister} */
+static DECLCALLBACK(int) pdmR3DevHlp_RTCRegister(PPDMDEVINS pDevIns, PCPDMRTCREG pRtcReg, PCPDMRTCHLP *ppRtcHlp)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_RTCRegister: caller='%s'/%d: pRtcReg=%p:{.u32Version=%#x, .pfnWrite=%p, .pfnRead=%p} ppRtcHlp=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pRtcReg, pRtcReg->u32Version, pRtcReg->pfnWrite,
+             pRtcReg->pfnWrite, ppRtcHlp));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_RTCRegister: caller='%s'/%d: returns %Rrc\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnDMARegister} */
+static DECLCALLBACK(int) pdmR3DevHlp_DMARegister(PPDMDEVINS pDevIns, unsigned uChannel, PFNDMATRANSFERHANDLER pfnTransferHandler, void *pvUser)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+
+    RT_NOREF(uChannel, pfnTransferHandler, pvUser);
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_DMARegister: caller='%s'/%d: returns %Rrc\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnDMAReadMemory} */
+static DECLCALLBACK(int) pdmR3DevHlp_DMAReadMemory(PPDMDEVINS pDevIns, unsigned uChannel, void *pvBuffer, uint32_t off, uint32_t cbBlock, uint32_t *pcbRead)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_DMAReadMemory: caller='%s'/%d: uChannel=%d pvBuffer=%p off=%#x cbBlock=%#x pcbRead=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, uChannel, pvBuffer, off, cbBlock, pcbRead));
+
+    RT_NOREF(uChannel, pvBuffer, off, cbBlock, pcbRead);
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_DMAReadMemory: caller='%s'/%d: returns %Rrc\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnDMAWriteMemory} */
+static DECLCALLBACK(int) pdmR3DevHlp_DMAWriteMemory(PPDMDEVINS pDevIns, unsigned uChannel, const void *pvBuffer, uint32_t off, uint32_t cbBlock, uint32_t *pcbWritten)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_DMAWriteMemory: caller='%s'/%d: uChannel=%d pvBuffer=%p off=%#x cbBlock=%#x pcbWritten=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, uChannel, pvBuffer, off, cbBlock, pcbWritten));
+
+    RT_NOREF(uChannel, pvBuffer, off, cbBlock, pcbWritten);
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_DMAWriteMemory: caller='%s'/%d: returns %Rrc\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnDMASetDREQ} */
+static DECLCALLBACK(int) pdmR3DevHlp_DMASetDREQ(PPDMDEVINS pDevIns, unsigned uChannel, unsigned uLevel)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_DMASetDREQ: caller='%s'/%d: uChannel=%d uLevel=%d\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, uChannel, uLevel));
+
+    RT_NOREF(uChannel, uLevel);
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_DMASetDREQ: caller='%s'/%d: returns %Rrc\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnDMAGetChannelMode} */
+static DECLCALLBACK(uint8_t) pdmR3DevHlp_DMAGetChannelMode(PPDMDEVINS pDevIns, unsigned uChannel)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_DMAGetChannelMode: caller='%s'/%d: uChannel=%d\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, uChannel));
+
+    uint8_t u8Mode = 0;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_DMAGetChannelMode: caller='%s'/%d: returns %#04x\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, u8Mode));
+    return u8Mode;
+}
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnDMASchedule} */
+static DECLCALLBACK(void) pdmR3DevHlp_DMASchedule(PPDMDEVINS pDevIns)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_DMASchedule: caller='%s'/%d\n",
+             pDevIns->pReg->szName, pDevIns->iInstance));
+
+    AssertFailed();
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnCMOSWrite} */
+static DECLCALLBACK(int) pdmR3DevHlp_CMOSWrite(PPDMDEVINS pDevIns, unsigned iReg, uint8_t u8Value)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_CMOSWrite: caller='%s'/%d: iReg=%#04x u8Value=%#04x\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, iReg, u8Value));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_CMOSWrite: caller='%s'/%d: return %Rrc\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnCMOSRead} */
+static DECLCALLBACK(int) pdmR3DevHlp_CMOSRead(PPDMDEVINS pDevIns, unsigned iReg, uint8_t *pu8Value)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_CMOSWrite: caller='%s'/%d: iReg=%#04x pu8Value=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, iReg, pu8Value));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_CMOSWrite: caller='%s'/%d: return %Rrc\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnAssertEMT} */
+static DECLCALLBACK(bool) pdmR3DevHlp_AssertEMT(PPDMDEVINS pDevIns, const char *pszFile, unsigned iLine, const char *pszFunction)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    RT_NOREF(pszFile, iLine, pszFunction);
+    AssertFailed();
+    return false;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnAssertOther} */
+static DECLCALLBACK(bool) pdmR3DevHlp_AssertOther(PPDMDEVINS pDevIns, const char *pszFile, unsigned iLine, const char *pszFunction)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    RT_NOREF(pszFile, iLine, pszFunction);
+    AssertFailed();
+    return false;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnLdrGetRCInterfaceSymbols} */
+static DECLCALLBACK(int) pdmR3DevHlp_LdrGetRCInterfaceSymbols(PPDMDEVINS pDevIns, void *pvInterface, size_t cbInterface,
+                                                              const char *pszSymPrefix, const char *pszSymList)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_PDMLdrGetRCInterfaceSymbols: caller='%s'/%d: pvInterface=%p cbInterface=%zu pszSymPrefix=%p:{%s} pszSymList=%p:{%s}\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pvInterface, cbInterface, pszSymPrefix, pszSymPrefix, pszSymList, pszSymList));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_PDMLdrGetRCInterfaceSymbols: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName,
+             pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnLdrGetR0InterfaceSymbols} */
+static DECLCALLBACK(int) pdmR3DevHlp_LdrGetR0InterfaceSymbols(PPDMDEVINS pDevIns, void *pvInterface, size_t cbInterface,
+                                                              const char *pszSymPrefix, const char *pszSymList)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_PDMLdrGetR0InterfaceSymbols: caller='%s'/%d: pvInterface=%p cbInterface=%zu pszSymPrefix=%p:{%s} pszSymList=%p:{%s}\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pvInterface, cbInterface, pszSymPrefix, pszSymPrefix, pszSymList, pszSymList));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_PDMLdrGetR0InterfaceSymbols: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName,
+             pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnCallR0} */
+static DECLCALLBACK(int) pdmR3DevHlp_CallR0(PPDMDEVINS pDevIns, uint32_t uOperation, uint64_t u64Arg)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_CallR0: caller='%s'/%d: uOperation=%#x u64Arg=%#RX64\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, uOperation, u64Arg));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_CallR0: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName,
+             pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnVMGetSuspendReason} */
+static DECLCALLBACK(VMSUSPENDREASON) pdmR3DevHlp_VMGetSuspendReason(PPDMDEVINS pDevIns)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    VMSUSPENDREASON enmReason = VMSUSPENDREASON_INVALID;
+    AssertFailed();
+    LogFlow(("pdmR3DevHlp_VMGetSuspendReason: caller='%s'/%d: returns %d\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, enmReason));
+    return enmReason;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnVMGetResumeReason} */
+static DECLCALLBACK(VMRESUMEREASON) pdmR3DevHlp_VMGetResumeReason(PPDMDEVINS pDevIns)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    VMRESUMEREASON enmReason = VMRESUMEREASON_INVALID;
+    AssertFailed();
+    LogFlow(("pdmR3DevHlp_VMGetResumeReason: caller='%s'/%d: returns %d\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, enmReason));
+    return enmReason;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnGetUVM} */
+static DECLCALLBACK(PUVM) pdmR3DevHlp_GetUVM(PPDMDEVINS pDevIns)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    AssertFailed();
+    LogFlow(("pdmR3DevHlp_GetUVM: caller='%s'/%d: returns %p\n", pDevIns->pReg->szName, pDevIns->iInstance, NULL));
+    return NULL;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnGetVM} */
+static DECLCALLBACK(PVM) pdmR3DevHlp_GetVM(PPDMDEVINS pDevIns)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    AssertFailed();
+    LogFlow(("pdmR3DevHlp_GetVM: caller='%s'/%d: returns %p\n", pDevIns->pReg->szName, pDevIns->iInstance, NULL));
+    return NULL;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnGetVMCPU} */
+static DECLCALLBACK(PVMCPU) pdmR3DevHlp_GetVMCPU(PPDMDEVINS pDevIns)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    AssertFailed();
+    LogFlow(("pdmR3DevHlp_GetVMCPU: caller='%s'/%d for CPU %u\n", pDevIns->pReg->szName, pDevIns->iInstance, NULL));
+    return NULL;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnGetCurrentCpuId} */
+static DECLCALLBACK(VMCPUID) pdmR3DevHlp_GetCurrentCpuId(PPDMDEVINS pDevIns)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    VMCPUID idCpu = 0;
+    AssertFailed();
+    LogFlow(("pdmR3DevHlp_GetCurrentCpuId: caller='%s'/%d for CPU %u\n", pDevIns->pReg->szName, pDevIns->iInstance, idCpu));
+    return idCpu;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnPCIBusRegister} */
+static DECLCALLBACK(int) pdmR3DevHlp_PCIBusRegister(PPDMDEVINS pDevIns, PPDMPCIBUSREG pPciBusReg,
+                                                    PCPDMPCIHLPR3 *ppPciHlpR3, uint32_t *piBus)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_PCIBusRegister: caller='%s'/%d: pPciBusReg=%p:{.u32Version=%#x, .pfnRegisterR3=%p, .pfnIORegionRegisterR3=%p, "
+             ".pfnSetIrqR3=%p, .pszSetIrqRC=%p:{%s}, .pszSetIrqR0=%p:{%s}} ppPciHlpR3=%p piBus=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pPciBusReg, pPciBusReg->u32Version, pPciBusReg->pfnRegisterR3,
+             pPciBusReg->pfnIORegionRegisterR3, pPciBusReg->pfnSetIrqR3, pPciBusReg->pszSetIrqRC, pPciBusReg->pszSetIrqRC,
+             pPciBusReg->pszSetIrqR0, pPciBusReg->pszSetIrqR0, ppPciHlpR3, piBus));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_PCIBusRegister: caller='%s'/%d: returns %Rrc *piBus=%u\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, rc, *piBus));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnPICRegister} */
+static DECLCALLBACK(int) pdmR3DevHlp_PICRegister(PPDMDEVINS pDevIns, PPDMPICREG pPicReg, PCPDMPICHLPR3 *ppPicHlpR3)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_PICRegister: caller='%s'/%d: pPicReg=%p:{.u32Version=%#x, .pfnSetIrqR3=%p, .pfnGetInterruptR3=%p, .pszGetIrqRC=%p:{%s}, .pszGetInterruptRC=%p:{%s}, .pszGetIrqR0=%p:{%s}, .pszGetInterruptR0=%p:{%s} } ppPicHlpR3=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pPicReg, pPicReg->u32Version, pPicReg->pfnSetIrqR3, pPicReg->pfnGetInterruptR3,
+             pPicReg->pszSetIrqRC, pPicReg->pszSetIrqRC, pPicReg->pszGetInterruptRC, pPicReg->pszGetInterruptRC,
+             pPicReg->pszSetIrqR0, pPicReg->pszSetIrqR0, pPicReg->pszGetInterruptR0, pPicReg->pszGetInterruptR0,
+             ppPicHlpR3));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_PICRegister: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnAPICRegister} */
+static DECLCALLBACK(int) pdmR3DevHlp_APICRegister(PPDMDEVINS pDevIns)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_APICRegister: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnIOAPICRegister} */
+static DECLCALLBACK(int) pdmR3DevHlp_IOAPICRegister(PPDMDEVINS pDevIns, PPDMIOAPICREG pIoApicReg, PCPDMIOAPICHLPR3 *ppIoApicHlpR3)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_IOAPICRegister: caller='%s'/%d: pIoApicReg=%p:{.u32Version=%#x, .pfnSetIrqR3=%p, .pszSetIrqRC=%p:{%s}, .pszSetIrqR0=%p:{%s}} ppIoApicHlpR3=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pIoApicReg, pIoApicReg->u32Version, pIoApicReg->pfnSetIrqR3,
+             pIoApicReg->pszSetIrqRC, pIoApicReg->pszSetIrqRC, pIoApicReg->pszSetIrqR0, pIoApicReg->pszSetIrqR0, ppIoApicHlpR3));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_IOAPICRegister: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnHPETRegister} */
+static DECLCALLBACK(int) pdmR3DevHlp_HPETRegister(PPDMDEVINS pDevIns, PPDMHPETREG pHpetReg, PCPDMHPETHLPR3 *ppHpetHlpR3)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns); RT_NOREF_PV(pDevIns);
+    LogFlow(("pdmR3DevHlp_HPETRegister: caller='%s'/%d:\n", pDevIns->pReg->szName, pDevIns->iInstance));
+
+    RT_NOREF(pHpetReg, ppHpetHlpR3);
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_HPETRegister: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnPciRawRegister} */
+static DECLCALLBACK(int) pdmR3DevHlp_PciRawRegister(PPDMDEVINS pDevIns, PPDMPCIRAWREG pPciRawReg, PCPDMPCIRAWHLPR3 *ppPciRawHlpR3)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns); RT_NOREF_PV(pDevIns);
+    LogFlow(("pdmR3DevHlp_PciRawRegister: caller='%s'/%d:\n", pDevIns->pReg->szName, pDevIns->iInstance));
+
+    RT_NOREF(pPciRawReg, ppPciRawHlpR3);
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_PciRawRegister: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnDMACRegister} */
+static DECLCALLBACK(int) pdmR3DevHlp_DMACRegister(PPDMDEVINS pDevIns, PPDMDMACREG pDmacReg, PCPDMDMACHLP *ppDmacHlp)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_DMACRegister: caller='%s'/%d: pDmacReg=%p:{.u32Version=%#x, .pfnRun=%p, .pfnRegister=%p, .pfnReadMemory=%p, .pfnWriteMemory=%p, .pfnSetDREQ=%p, .pfnGetChannelMode=%p} ppDmacHlp=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pDmacReg, pDmacReg->u32Version, pDmacReg->pfnRun, pDmacReg->pfnRegister,
+             pDmacReg->pfnReadMemory, pDmacReg->pfnWriteMemory, pDmacReg->pfnSetDREQ, pDmacReg->pfnGetChannelMode, ppDmacHlp));
+
+    RT_NOREF(pDmacReg, ppDmacHlp);
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_DMACRegister: caller='%s'/%d: returns %Rrc\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/**
+ * @copydoc PDMDEVHLPR3::pfnRegisterVMMDevHeap
+ */
+static DECLCALLBACK(int) pdmR3DevHlp_RegisterVMMDevHeap(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTR3PTR pvHeap, unsigned cbHeap)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_RegisterVMMDevHeap: caller='%s'/%d: GCPhys=%RGp pvHeap=%p cbHeap=%#x\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, GCPhys, pvHeap, cbHeap));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_RegisterVMMDevHeap: caller='%s'/%d: returns %Rrc\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/**
+ * @interface_method_impl{PDMDEVHLPR3,pfnFirmwareRegister}
+ */
+static DECLCALLBACK(int) pdmR3DevHlp_FirmwareRegister(PPDMDEVINS pDevIns, PCPDMFWREG pFwReg, PCPDMFWHLPR3 *ppFwHlp)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_FirmwareRegister: caller='%s'/%d: pFWReg=%p:{.u32Version=%#x, .pfnIsHardReset=%p, .u32TheEnd=%#x} ppFwHlp=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, pFwReg, pFwReg->u32Version, pFwReg->pfnIsHardReset, pFwReg->u32TheEnd, ppFwHlp));
+
+    RT_NOREF(pFwReg, ppFwHlp);
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_FirmwareRegister: caller='%s'/%d: returns %Rrc\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnVMReset} */
+static DECLCALLBACK(int) pdmR3DevHlp_VMReset(PPDMDEVINS pDevIns, uint32_t fFlags)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_VMReset: caller='%s'/%d: fFlags=%#x\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, fFlags));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_VMReset: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnVMSuspend} */
+static DECLCALLBACK(int) pdmR3DevHlp_VMSuspend(PPDMDEVINS pDevIns)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_VMSuspend: caller='%s'/%d:\n",
+             pDevIns->pReg->szName, pDevIns->iInstance));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_VMSuspend: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnVMSuspendSaveAndPowerOff} */
+static DECLCALLBACK(int) pdmR3DevHlp_VMSuspendSaveAndPowerOff(PPDMDEVINS pDevIns)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_VMSuspendSaveAndPowerOff: caller='%s'/%d:\n",
+             pDevIns->pReg->szName, pDevIns->iInstance));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_VMSuspendSaveAndPowerOff: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnVMPowerOff} */
+static DECLCALLBACK(int) pdmR3DevHlp_VMPowerOff(PPDMDEVINS pDevIns)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_VMPowerOff: caller='%s'/%d:\n",
+             pDevIns->pReg->szName, pDevIns->iInstance));
+
+    int rc = VERR_NOT_IMPLEMENTED;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_VMPowerOff: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+    return rc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnA20IsEnabled} */
+static DECLCALLBACK(bool) pdmR3DevHlp_A20IsEnabled(PPDMDEVINS pDevIns)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+
+    bool fRc = false;
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_A20IsEnabled: caller='%s'/%d: returns %d\n", pDevIns->pReg->szName, pDevIns->iInstance, fRc));
+    return fRc;
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnA20Set} */
+static DECLCALLBACK(void) pdmR3DevHlp_A20Set(PPDMDEVINS pDevIns, bool fEnable)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_A20Set: caller='%s'/%d: fEnable=%d\n", pDevIns->pReg->szName, pDevIns->iInstance, fEnable));
+    AssertFailed();
+}
+
+
+/** @interface_method_impl{PDMDEVHLPR3,pfnGetCpuId} */
+static DECLCALLBACK(void) pdmR3DevHlp_GetCpuId(PPDMDEVINS pDevIns, uint32_t iLeaf,
+                                               uint32_t *pEax, uint32_t *pEbx, uint32_t *pEcx, uint32_t *pEdx)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3DevHlp_GetCpuId: caller='%s'/%d: iLeaf=%d pEax=%p pEbx=%p pEcx=%p pEdx=%p\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, iLeaf, pEax, pEbx, pEcx, pEdx));
+    AssertPtr(pEax); AssertPtr(pEbx); AssertPtr(pEcx); AssertPtr(pEdx);
+
+    AssertFailed();
+
+    LogFlow(("pdmR3DevHlp_GetCpuId: caller='%s'/%d: returns void - *pEax=%#x *pEbx=%#x *pEcx=%#x *pEdx=%#x\n",
+             pDevIns->pReg->szName, pDevIns->iInstance, *pEax, *pEbx, *pEcx, *pEdx));
+}
+
+const PDMDEVHLPR3 g_tstDevPdmDevHlpR3 =
+{
+    PDM_DEVHLPR3_VERSION,
+    pdmR3DevHlp_IOPortRegister,
+    pdmR3DevHlp_IOPortRegisterRC,
+    pdmR3DevHlp_IOPortRegisterR0,
+    pdmR3DevHlp_IOPortDeregister,
+    pdmR3DevHlp_MMIORegister,
+    pdmR3DevHlp_MMIORegisterRC,
+    pdmR3DevHlp_MMIORegisterR0,
+    pdmR3DevHlp_MMIODeregister,
+    pdmR3DevHlp_MMIO2Register,
+    pdmR3DevHlp_MMIOExPreRegister,
+    pdmR3DevHlp_MMIOExDeregister,
+    pdmR3DevHlp_MMIOExMap,
+    pdmR3DevHlp_MMIOExUnmap,
+    pdmR3DevHlp_MMIOExReduce,
+    pdmR3DevHlp_MMHyperMapMMIO2,
+    pdmR3DevHlp_MMIO2MapKernel,
+    pdmR3DevHlp_ROMRegister,
+    pdmR3DevHlp_ROMProtectShadow,
+    pdmR3DevHlp_SSMRegister,
+    pdmR3DevHlp_TMTimerCreate,
+    pdmR3DevHlp_TMUtcNow,
+    pdmR3DevHlp_PhysRead,
+    pdmR3DevHlp_PhysWrite,
+    pdmR3DevHlp_PhysGCPhys2CCPtr,
+    pdmR3DevHlp_PhysGCPhys2CCPtrReadOnly,
+    pdmR3DevHlp_PhysReleasePageMappingLock,
+    pdmR3DevHlp_PhysReadGCVirt,
+    pdmR3DevHlp_PhysWriteGCVirt,
+    pdmR3DevHlp_PhysGCPtr2GCPhys,
+    pdmR3DevHlp_MMHeapAlloc,
+    pdmR3DevHlp_MMHeapAllocZ,
+    pdmR3DevHlp_MMHeapFree,
+    pdmR3DevHlp_VMState,
+    pdmR3DevHlp_VMTeleportedAndNotFullyResumedYet,
+    pdmR3DevHlp_VMSetError,
+    pdmR3DevHlp_VMSetErrorV,
+    pdmR3DevHlp_VMSetRuntimeError,
+    pdmR3DevHlp_VMSetRuntimeErrorV,
+    pdmR3DevHlp_DBGFStopV,
+    pdmR3DevHlp_DBGFInfoRegister,
+    pdmR3DevHlp_DBGFRegRegister,
+    pdmR3DevHlp_DBGFTraceBuf,
+    pdmR3DevHlp_STAMRegister,
+    pdmR3DevHlp_STAMRegisterF,
+    pdmR3DevHlp_STAMRegisterV,
+    pdmR3DevHlp_PCIRegister,
+    pdmR3DevHlp_PCIRegisterMsi,
+    pdmR3DevHlp_PCIIORegionRegister,
+    pdmR3DevHlp_PCISetConfigCallbacks,
+    pdmR3DevHlp_PCIPhysRead,
+    pdmR3DevHlp_PCIPhysWrite,
+    pdmR3DevHlp_PCISetIrq,
+    pdmR3DevHlp_PCISetIrqNoWait,
+    pdmR3DevHlp_ISASetIrq,
+    pdmR3DevHlp_ISASetIrqNoWait,
+    pdmR3DevHlp_IoApicSendMsi,
+    pdmR3DevHlp_DriverAttach,
+    pdmR3DevHlp_DriverDetach,
+    pdmR3DevHlp_QueueCreate,
+    pdmR3DevHlp_CritSectInit,
+    pdmR3DevHlp_CritSectGetNop,
+    pdmR3DevHlp_CritSectGetNopR0,
+    pdmR3DevHlp_CritSectGetNopRC,
+    pdmR3DevHlp_SetDeviceCritSect,
+    pdmR3DevHlp_ThreadCreate,
+    pdmR3DevHlp_SetAsyncNotification,
+    pdmR3DevHlp_AsyncNotificationCompleted,
+    pdmR3DevHlp_RTCRegister,
+    pdmR3DevHlp_PCIBusRegister,
+    pdmR3DevHlp_PICRegister,
+    pdmR3DevHlp_APICRegister,
+    pdmR3DevHlp_IOAPICRegister,
+    pdmR3DevHlp_HPETRegister,
+    pdmR3DevHlp_PciRawRegister,
+    pdmR3DevHlp_DMACRegister,
+    pdmR3DevHlp_DMARegister,
+    pdmR3DevHlp_DMAReadMemory,
+    pdmR3DevHlp_DMAWriteMemory,
+    pdmR3DevHlp_DMASetDREQ,
+    pdmR3DevHlp_DMAGetChannelMode,
+    pdmR3DevHlp_DMASchedule,
+    pdmR3DevHlp_CMOSWrite,
+    pdmR3DevHlp_CMOSRead,
+    pdmR3DevHlp_AssertEMT,
+    pdmR3DevHlp_AssertOther,
+    pdmR3DevHlp_LdrGetRCInterfaceSymbols,
+    pdmR3DevHlp_LdrGetR0InterfaceSymbols,
+    pdmR3DevHlp_CallR0,
+    pdmR3DevHlp_VMGetSuspendReason,
+    pdmR3DevHlp_VMGetResumeReason,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    pdmR3DevHlp_GetUVM,
+    pdmR3DevHlp_GetVM,
+    pdmR3DevHlp_GetVMCPU,
+    pdmR3DevHlp_GetCurrentCpuId,
+    pdmR3DevHlp_RegisterVMMDevHeap,
+    pdmR3DevHlp_FirmwareRegister,
+    pdmR3DevHlp_VMReset,
+    pdmR3DevHlp_VMSuspend,
+    pdmR3DevHlp_VMSuspendSaveAndPowerOff,
+    pdmR3DevHlp_VMPowerOff,
+    pdmR3DevHlp_A20IsEnabled,
+    pdmR3DevHlp_A20Set,
+    pdmR3DevHlp_GetCpuId,
+    pdmR3DevHlp_TMTimeVirtGet,
+    pdmR3DevHlp_TMTimeVirtGetFreq,
+    pdmR3DevHlp_TMTimeVirtGetNano,
+    pdmR3DevHlp_GetSupDrvSession,
+    pdmR3DevHlp_QueryGenericUserObject,
+    PDM_DEVHLPR3_VERSION /* the end */
+};
+
Index: trunk/src/VBox/Devices/testcase/tstDevicePlugin.h
===================================================================
--- trunk/src/VBox/Devices/testcase/tstDevicePlugin.h	(revision 69162)
+++ trunk/src/VBox/Devices/testcase/tstDevicePlugin.h	(revision 69162)
@@ -0,0 +1,134 @@
+/** @file
+ * tstDevice: Plugin API.
+ */
+
+/*
+ * Copyright (C) 2017 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.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___tstDevicePlugin_h
+#define ___tstDevicePlugin_h
+
+#include <VBox/types.h>
+
+/**
+ * Config item type.
+ */
+typedef enum TSTDEVCFGITEMTYPE
+{
+    /** Invalid type. */
+    TSTDEVCFGITEMTYPE_INVALID = 0,
+    /** String type. */
+    TSTDEVCFGITEMTYPE_STRING,
+    /** Integer value encoded in the string. */
+    TSTDEVCFGITEMTYPE_INTEGER,
+    /** Raw bytes. */
+    TSTDEVCFGITEMTYPE_BYTES,
+    /** 32bit hack. */
+    TSTDEVCFGITEMTYPE_32BIT_HACK = 0x7fffffff
+} TSTDEVCFGITEMTYPE;
+/** Pointer to a config item type. */
+typedef TSTDEVCFGITEMTYPE *PTSTDEVCFGITEMTYPE;
+
+
+/**
+ * Testcase config item.
+ */
+typedef struct TSTDEVCFGITEM
+{
+    /** The key of the item. */
+    const char          *pszKey;
+    /** Type of the config item. */
+    TSTDEVCFGITEMTYPE   enmType;
+    /** The value of the item (as a string/number of bytes to make static
+     * instantiation easier). */
+    const char          *pszVal;
+} TSTDEVCFGITEM;
+/** Pointer to a testcase config item. */
+typedef TSTDEVCFGITEM *PTSTDEVCFGITEM;
+/** Pointer to a constant testcase config item. */
+typedef const TSTDEVCFGITEM *PCTSTDEVCFGITEM;
+
+
+/** Device under test handle. */
+typedef struct TSTDEVDUTINT *TSTDEVDUT;
+
+/**
+ * Testcase registration structure.
+ */
+typedef struct TSTDEVTESTCASEREG
+{
+    /** Testcase name. */
+    char                szName[16];
+    /** Testcase description. */
+    const char          *pszDesc;
+    /** The device name the testcase handles. */
+    char                szDevName[16];
+    /** Flags for this testcase. */
+    uint32_t            fFlags;
+    /** CFGM configuration for the device to be instantiated. */
+    PCTSTDEVCFGITEM     paDevCfg;
+
+    /**
+     * Testcase entry point.
+     *
+     * @returns VBox status code.
+     * @param   hDut      Handle of the device under test.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnTestEntry, (TSTDEVDUT hDut));
+} TSTDEVTESTCASEREG;
+/** Pointer to a testcase registration structure. */
+typedef TSTDEVTESTCASEREG *PTSTDEVTESTCASEREG;
+/** Pointer to a constant testcase registration structure. */
+typedef const TSTDEVTESTCASEREG *PCTSTDEVTESTCASEREG;
+
+
+/**
+ * Testcase register callbacks structure.
+ */
+typedef struct TSTDEVPLUGINREGISTER
+{
+    /**
+     * Registers a new testcase.
+     *
+     * @returns VBox status code.
+     * @param   pvUser       Opaque user data given in the plugin load callback.
+     * @param   pTestcaseReg The testcase descriptor to register.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnRegisterTestcase, (void *pvUser, PCTSTDEVTESTCASEREG pTestcaseReg));
+
+} TSTDEVPLUGINREGISTER;
+/** Pointer to a backend register callbacks structure. */
+typedef TSTDEVPLUGINREGISTER *PTSTDEVPLUGINREGISTER;
+
+
+/**
+ * Initialization entry point called by the device test framework when
+ * a plugin is loaded.
+ *
+ * @returns VBox status code.
+ * @param   pvUser             Opaque user data passed in the register callbacks.
+ * @param   pRegisterCallbacks Pointer to the register callbacks structure.
+ */
+typedef DECLCALLBACK(int) FNTSTDEVPLUGINLOAD(void *pvUser, PTSTDEVPLUGINREGISTER pRegisterCallbacks);
+typedef FNTSTDEVPLUGINLOAD *PFNTSTDEVPLUGINLOAD;
+#define TSTDEV_PLUGIN_LOAD_NAME "TSTDevPluginLoad"
+
+#endif
Index: trunk/src/VBox/Devices/testcase/tstDeviceVMM.cpp
===================================================================
--- trunk/src/VBox/Devices/testcase/tstDeviceVMM.cpp	(revision 69162)
+++ trunk/src/VBox/Devices/testcase/tstDeviceVMM.cpp	(revision 69162)
@@ -0,0 +1,1069 @@
+/* $Id$ */
+/** @file
+ * tstDevice - Test framework for PDM devices/drivers, VMM callbacks implementation.
+ */
+
+/*
+ * Copyright (C) 2017 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_DEFAULT /** @todo */
+#include <VBox/types.h>
+#include <VBox/version.h>
+#include <VBox/vmm/pdmpci.h>
+
+#include "tstDeviceInternal.h"
+
+/*********************************************************************************************************************************
+*   Defined Constants And Macros                                                                                                 *
+*********************************************************************************************************************************/
+
+/** Frequency of the real clock. */
+#define TMCLOCK_FREQ_REAL       UINT32_C(1000)
+/** Frequency of the virtual clock. */
+#define TMCLOCK_FREQ_VIRTUAL    UINT32_C(1000000000)
+
+/*********************************************************************************************************************************
+*   Structures and Typedefs                                                                                                      *
+*********************************************************************************************************************************/
+
+
+
+/*********************************************************************************************************************************
+*   Global Variables                                                                                                             *
+*********************************************************************************************************************************/
+
+
+
+/*********************************************************************************************************************************
+*   Internal Functions                                                                                                           *
+*********************************************************************************************************************************/
+
+/**
+ * Resolves a path reference to a configuration item.
+ *
+ * @returns VBox status code.
+ * @param   paDevCfg        The array of config items.
+ * @param   pszName         Name of a byte string value.
+ * @param   ppItem          Where to store the pointer to the item.
+ */
+static int tstDev_CfgmR3ResolveItem(PCTSTDEVCFGITEM paDevCfg, const char *pszName, PCTSTDEVCFGITEM *ppItem)
+{
+    *ppItem = NULL;
+    if (!paDevCfg)
+        return VERR_CFGM_VALUE_NOT_FOUND;
+
+    size_t          cchName = strlen(pszName);
+    PCTSTDEVCFGITEM pDevCfgItem = paDevCfg;
+    while (pDevCfgItem->pszKey != NULL)
+    {
+        size_t cchKey = strlen(pDevCfgItem->pszKey);
+        if (cchName == cchKey)
+        {
+            int iDiff = memcmp(pszName, pDevCfgItem->pszKey, cchName);
+            if (iDiff <= 0)
+            {
+                if (iDiff != 0)
+                    break;
+                *ppItem = pDevCfgItem;
+                return VINF_SUCCESS;
+            }
+        }
+
+        /* next */
+        pDevCfgItem++;
+    }
+    return VERR_CFGM_VALUE_NOT_FOUND;
+}
+
+
+static DECLCALLBACK(bool) tstDevVmm_CFGMR3AreValuesValid(PCFGMNODE pNode, const char *pszzValid)
+{
+    if (pNode && pNode->pDut->pTestcaseReg->paDevCfg)
+    {
+        PCTSTDEVCFGITEM pDevCfgItem = pNode->pDut->pTestcaseReg->paDevCfg;
+        while (pDevCfgItem->pszKey != NULL)
+        {
+            size_t cchKey = strlen(pDevCfgItem->pszKey);
+
+            /* search pszzValid for the name */
+            const char *psz = pszzValid;
+            while (*psz)
+            {
+                size_t cch = strlen(psz);
+                if (    cch == cchKey
+                    &&  !memcmp(psz, pDevCfgItem->pszKey, cch))
+                    break;
+
+                /* next */
+                psz += cch + 1;
+            }
+
+            /* if at end of pszzValid we didn't find it => failure */
+            if (!*psz)
+                return false;
+
+            pDevCfgItem++;
+        }
+    }
+
+    return true;
+}
+
+
+static DECLCALLBACK(void) tstDevVmm_CFGMR3Dump(PCFGMNODE pRoot)
+{
+    RT_NOREF(pRoot);
+    AssertFailed();
+}
+
+
+static DECLCALLBACK(PCFGMNODE) tstDevVmm_CFGMR3GetChild(PCFGMNODE pNode, const char *pszPath)
+{
+    RT_NOREF(pNode, pszPath);
+    AssertFailed();
+    return NULL;
+}
+
+
+static DECLCALLBACK(PCFGMNODE) tstDevVmm_CFGMR3GetChildFV(PCFGMNODE pNode, const char *pszPathFormat, va_list Args)
+{
+    RT_NOREF(pNode, pszPathFormat, Args);
+    AssertFailed();
+    return NULL;
+}
+
+
+static DECLCALLBACK(PCFGMNODE) tstDevVmm_CFGMR3GetFirstChild(PCFGMNODE pNode)
+{
+    RT_NOREF(pNode);
+    AssertFailed();
+    return NULL;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_CFGMR3GetName(PCFGMNODE pCur, char *pszName, size_t cchName)
+{
+    RT_NOREF(pCur, pszName, cchName);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(PCFGMNODE) tstDevVmm_CFGMR3GetNextChild(PCFGMNODE pCur)
+{
+    RT_NOREF(pCur);
+    AssertFailed();
+    return NULL;
+}
+
+
+static DECLCALLBACK(PCFGMNODE) tstDevVmm_CFGMR3GetParent(PCFGMNODE pNode)
+{
+    RT_NOREF(pNode);
+    AssertFailed();
+    return NULL;
+}
+
+
+static DECLCALLBACK(PCFGMNODE) tstDevVmm_CFGMR3GetRoot(PVM pVM)
+{
+    RT_NOREF(pVM);
+    AssertFailed();
+    return NULL;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_CFGMR3InsertNode(PCFGMNODE pNode, const char *pszName, PCFGMNODE *ppChild)
+{
+    RT_NOREF(pNode, pszName, ppChild);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_CFGMR3InsertNodeFV(PCFGMNODE pNode, PCFGMNODE *ppChild,
+                                                      const char *pszNameFormat, va_list Args)
+{
+    RT_NOREF(pNode, ppChild, pszNameFormat, Args);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_CFGMR3InsertString(PCFGMNODE pNode, const char *pszName, const char *pszString)
+{
+    RT_NOREF(pNode, pszName, pszString);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_CFGMR3QueryBytes(PCFGMNODE pNode, const char *pszName, void *pvData, size_t cbData)
+{
+    RT_NOREF(pNode, pszName, pvData, cbData);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_CFGMR3QueryInteger(PCFGMNODE pNode, const char *pszName, uint64_t *pu64)
+{
+    if (!pNode)
+        return VERR_CFGM_NO_PARENT;
+
+    PCTSTDEVCFGITEM pCfgItem;
+    int rc = tstDev_CfgmR3ResolveItem(pNode->pDut->pTestcaseReg->paDevCfg, pszName, &pCfgItem);
+    if (RT_SUCCESS(rc))
+    {
+        if (pCfgItem->enmType == TSTDEVCFGITEMTYPE_INTEGER)
+            *pu64 = RTStrToUInt64(pCfgItem->pszVal);
+        else
+            rc = VERR_CFGM_NOT_INTEGER;
+    }
+
+    return rc;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_CFGMR3QuerySize(PCFGMNODE pNode, const char *pszName, size_t *pcb)
+{
+    if (!pNode)
+        return VERR_CFGM_NO_PARENT;
+
+    PCTSTDEVCFGITEM pCfgItem;
+    int rc = tstDev_CfgmR3ResolveItem(pNode->pDut->pTestcaseReg->paDevCfg, pszName, &pCfgItem);
+    if (RT_SUCCESS(rc))
+    {
+        switch (pCfgItem->enmType)
+        {
+            case TSTDEVCFGITEMTYPE_INTEGER:
+                *pcb = sizeof(uint64_t);
+                break;
+
+            case TSTDEVCFGITEMTYPE_STRING:
+                *pcb = strlen(pCfgItem->pszVal) + 1;
+                break;
+
+            case TSTDEVCFGITEMTYPE_BYTES:
+                AssertFailed();
+                break;
+
+            default:
+                rc = VERR_CFGM_IPE_1;
+                AssertMsgFailed(("Invalid value type %d\n", pCfgItem->enmType));
+                break;
+        }
+    }
+    return rc;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_CFGMR3QueryString(PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString)
+{
+    RT_NOREF(pNode, pszName, pszString, cchString);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_CFGMR3QueryStringAlloc(PCFGMNODE pNode, const char *pszName, char **ppszString)
+{
+    RT_NOREF(pNode, pszName, ppszString);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_CFGMR3QueryStringAllocDef(PCFGMNODE pNode, const char *pszName, char **ppszString, const char *pszDef)
+{
+    RT_NOREF(pNode, pszName, ppszString, pszDef);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(void) tstDevVmm_CFGMR3RemoveNode(PCFGMNODE pNode)
+{
+    RT_NOREF(pNode);
+    AssertFailed();
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_CFGMR3ValidateConfig(PCFGMNODE pNode, const char *pszNode,
+                                                        const char *pszValidValues, const char *pszValidNodes,
+                                                        const char *pszWho, uint32_t uInstance)
+{
+    RT_NOREF(pNode, pszNode, pszValidValues, pszValidNodes, pszWho, uInstance);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_IOMIOPortWrite(PVM pVM, PVMCPU pVCpu, RTIOPORT Port, uint32_t u32Value, size_t cbValue)
+{
+    RT_NOREF(pVM, pVCpu, Port, u32Value, cbValue);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_IOMMMIOMapMMIO2Page(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysRemapped, uint64_t fPageFlags)
+{
+    RT_NOREF(pVM, GCPhys, GCPhysRemapped, fPageFlags);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_IOMMMIOResetRegion(PVM pVM, RTGCPHYS GCPhys)
+{
+    RT_NOREF(pVM, GCPhys);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_MMHyperAlloc(PVM pVM, size_t cb, uint32_t uAlignment, MMTAG enmTag, void **ppv)
+{
+    RT_NOREF(pVM, cb, uAlignment, enmTag, ppv);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_MMHyperFree(PVM pVM, void *pv)
+{
+    RT_NOREF(pVM, pv);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(RTR0PTR) tstDevVmm_MMHyperR3ToR0(PVM pVM, RTR3PTR R3Ptr)
+{
+    RT_NOREF(pVM, R3Ptr);
+    AssertFailed();
+    return NIL_RTR0PTR;
+}
+
+
+static DECLCALLBACK(RTRCPTR) tstDevVmm_MMHyperR3ToRC(PVM pVM, RTR3PTR R3Ptr)
+{
+    RT_NOREF(pVM, R3Ptr);
+    AssertFailed();
+    return NIL_RTRCPTR;
+}
+
+
+static DECLCALLBACK(void) tstDevVmm_MMR3HeapFree(void *pv)
+{
+    RT_NOREF(pv);
+    AssertFailed();
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_MMR3HyperAllocOnceNoRel(PVM pVM, size_t cb, uint32_t uAlignment, MMTAG enmTag, void **ppv)
+{
+    RT_NOREF(pVM, cb, uAlignment, enmTag, ppv);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(uint64_t) tstDevVmm_MMR3PhysGetRamSize(PVM pVM)
+{
+    RT_NOREF(pVM);
+    AssertFailed();
+    return 0;
+}
+
+
+static DECLCALLBACK(uint64_t) tstDevVmm_MMR3PhysGetRamSizeAbove4GB(PVM pVM)
+{
+    RT_NOREF(pVM);
+    AssertFailed();
+    return 0;
+}
+
+
+static DECLCALLBACK(uint32_t) tstDevVmm_MMR3PhysGetRamSizeBelow4GB(PVM pVM)
+{
+    RT_NOREF(pVM);
+    AssertFailed();
+    return 0;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMCritSectEnterDebug(PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)
+{
+    RT_NOREF(rcBusy, uId, RT_SRC_POS_ARGS);
+    return RTCritSectEnter(&pCritSect->s.CritSect);
+}
+
+
+static DECLCALLBACK(bool) tstDevVmm_PDMCritSectIsInitialized(PCPDMCRITSECT pCritSect)
+{
+    RT_NOREF(pCritSect);
+    AssertFailed();
+    return false;
+}
+
+
+static DECLCALLBACK(bool) tstDevVmm_PDMCritSectIsOwner(PCPDMCRITSECT pCritSect)
+{
+    return RTCritSectIsOwner(&pCritSect->s.CritSect);
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMCritSectLeave(PPDMCRITSECT pCritSect)
+{
+    return RTCritSectLeave(&pCritSect->s.CritSect);
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMCritSectTryEnterDebug(PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)
+{
+    RT_NOREF(pCritSect, uId, RT_SRC_POS_ARGS);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMHCCritSectScheduleExitEvent(PPDMCRITSECT pCritSect, SUPSEMEVENT hEventToSignal)
+{
+    RT_NOREF(pCritSect, hEventToSignal);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(bool) tstDevVmm_PDMNsAllocateBandwidth(PPDMNSFILTER pFilter, size_t cbTransfer)
+{
+    RT_NOREF(pFilter, cbTransfer);
+    AssertFailed();
+    return false;
+}
+
+
+static DECLCALLBACK(PPDMQUEUEITEMCORE) tstDevVmm_PDMQueueAlloc(PPDMQUEUE pQueue)
+{
+    RT_NOREF(pQueue);
+    AssertFailed();
+    return NULL;
+}
+
+
+static DECLCALLBACK(bool) tstDevVmm_PDMQueueFlushIfNecessary(PPDMQUEUE pQueue)
+{
+    RT_NOREF(pQueue);
+    AssertFailed();
+    return false;
+}
+
+
+static DECLCALLBACK(void) tstDevVmm_PDMQueueInsert(PPDMQUEUE pQueue, PPDMQUEUEITEMCORE pItem)
+{
+    RT_NOREF(pQueue, pItem);
+    AssertFailed();
+}
+
+
+static DECLCALLBACK(R0PTRTYPE(PPDMQUEUE)) tstDevVmm_PDMQueueR0Ptr(PPDMQUEUE pQueue)
+{
+    RT_NOREF(pQueue);
+    AssertFailed();
+    return NIL_RTR0PTR;
+}
+
+
+static DECLCALLBACK(RCPTRTYPE(PPDMQUEUE)) tstDevVmm_PDMQueueRCPtr(PPDMQUEUE pQueue)
+{
+    RT_NOREF(pQueue);
+    AssertFailed();
+    return NIL_RTRCPTR;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMR3AsyncCompletionEpClose(PPDMASYNCCOMPLETIONENDPOINT pEndpoint)
+{
+    RT_NOREF(pEndpoint);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMR3AsyncCompletionEpCreateForFile(PPPDMASYNCCOMPLETIONENDPOINT ppEndpoint,
+                                                                       const char *pszFilename, uint32_t fFlags,
+                                                                       PPDMASYNCCOMPLETIONTEMPLATE pTemplate)
+{
+    RT_NOREF(ppEndpoint, pszFilename, fFlags, pTemplate);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMR3AsyncCompletionEpFlush(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, void *pvUser,
+                                                               PPPDMASYNCCOMPLETIONTASK ppTask)
+{
+    RT_NOREF(pEndpoint, pvUser, ppTask);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMR3AsyncCompletionEpGetSize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t *pcbSize)
+{
+    RT_NOREF(pEndpoint, pcbSize);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMR3AsyncCompletionEpRead(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off,
+                                                              PCRTSGSEG paSegments, unsigned cSegments,
+                                                              size_t cbRead, void *pvUser,
+                                                              PPPDMASYNCCOMPLETIONTASK ppTask)
+{
+    RT_NOREF(pEndpoint, off, paSegments, cSegments, cbRead, pvUser, ppTask);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMR3AsyncCompletionEpSetBwMgr(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, const char *pszBwMgr)
+{
+    RT_NOREF(pEndpoint, pszBwMgr);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMR3AsyncCompletionEpSetSize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t cbSize)
+{
+    RT_NOREF(pEndpoint, cbSize);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMR3AsyncCompletionEpWrite(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off,
+                                                               PCRTSGSEG paSegments, unsigned cSegments,
+                                                               size_t cbWrite, void *pvUser,
+                                                               PPPDMASYNCCOMPLETIONTASK ppTask)
+{
+    RT_NOREF(pEndpoint, off, paSegments, cSegments, cbWrite, pvUser, ppTask);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMR3AsyncCompletionTemplateDestroy(PPDMASYNCCOMPLETIONTEMPLATE pTemplate)
+{
+    RT_NOREF(pTemplate);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMR3BlkCacheClear(PPDMBLKCACHE pBlkCache)
+{
+    RT_NOREF(pBlkCache);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMR3BlkCacheDiscard(PPDMBLKCACHE pBlkCache, PCRTRANGE paRanges,
+                                                        unsigned cRanges, void *pvUser)
+{
+    RT_NOREF(pBlkCache, paRanges, cRanges, pvUser);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMR3BlkCacheFlush(PPDMBLKCACHE pBlkCache, void *pvUser)
+{
+    RT_NOREF(pBlkCache, pvUser);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMR3BlkCacheIoXferComplete(PPDMBLKCACHE pBlkCache, PPDMBLKCACHEIOXFER hIoXfer, int rcIoXfer)
+{
+    RT_NOREF(pBlkCache, hIoXfer, rcIoXfer);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMR3BlkCacheRead(PPDMBLKCACHE pBlkCache, uint64_t off, PCRTSGBUF pSgBuf, size_t cbRead, void *pvUser)
+{
+    RT_NOREF(pBlkCache, off, pSgBuf, cbRead, pvUser);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMR3BlkCacheRelease(PPDMBLKCACHE pBlkCache)
+{
+    RT_NOREF(pBlkCache);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMR3BlkCacheResume(PPDMBLKCACHE pBlkCache)
+{
+    RT_NOREF(pBlkCache);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMR3BlkCacheSuspend(PPDMBLKCACHE pBlkCache)
+{
+    RT_NOREF(pBlkCache);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMR3BlkCacheWrite(PPDMBLKCACHE pBlkCache, uint64_t off, PCRTSGBUF pSgBuf, size_t cbWrite, void *pvUser)
+{
+    RT_NOREF(pBlkCache, off, pSgBuf, cbWrite, pvUser);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMR3CritSectDelete(PPDMCRITSECT pCritSect)
+{
+    RT_NOREF(pCritSect);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMR3QueryLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPPDMIBASE ppBase)
+{
+    RT_NOREF(pUVM, pszDevice, iInstance, iLun, ppBase);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMR3ThreadDestroy(PPDMTHREAD pThread, int *pRcThread)
+{
+    RT_NOREF(pThread, pRcThread);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMR3ThreadResume(PPDMTHREAD pThread)
+{
+    RT_NOREF(pThread);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMR3ThreadSleep(PPDMTHREAD pThread, RTMSINTERVAL cMillies)
+{
+    RT_NOREF(pThread, cMillies);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_PDMR3ThreadSuspend(PPDMTHREAD pThread)
+{
+    RT_NOREF(pThread);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(uint64_t) tstDevVmm_TMCpuTicksPerSecond(PVM pVM)
+{
+    RT_NOREF(pVM);
+    AssertFailed();
+    return 0;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_TMR3TimerDestroy(PTMTIMER pTimer)
+{
+    RT_NOREF(pTimer);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_TMR3TimerLoad(PTMTIMERR3 pTimer, PSSMHANDLE pSSM)
+{
+    RT_NOREF(pTimer, pSSM);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_TMR3TimerSave(PTMTIMERR3 pTimer, PSSMHANDLE pSSM)
+{
+    RT_NOREF(pTimer, pSSM);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_TMR3TimerSetCritSect(PTMTIMERR3 pTimer, PPDMCRITSECT pCritSect)
+{
+    RT_NOREF(pTimer, pCritSect);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(uint64_t) tstDevVmm_TMTimerFromMilli(PTMTIMER pTimer, uint64_t cMilliSecs)
+{
+    RT_NOREF(pTimer, cMilliSecs);
+    AssertFailed();
+    return 0;
+}
+
+
+static DECLCALLBACK(uint64_t) tstDevVmm_TMTimerFromNano(PTMTIMER pTimer, uint64_t cNanoSecs)
+{
+    RT_NOREF(pTimer, cNanoSecs);
+    AssertFailed();
+    return 0;
+}
+
+
+static DECLCALLBACK(uint64_t) tstDevVmm_TMTimerGet(PTMTIMER pTimer)
+{
+    RT_NOREF(pTimer);
+    AssertFailed();
+    return 0;
+}
+
+
+static DECLCALLBACK(uint64_t) tstDevVmm_TMTimerGetFreq(PTMTIMER pTimer)
+{
+    switch (pTimer->enmClock)
+    {
+        case TMCLOCK_VIRTUAL:
+        case TMCLOCK_VIRTUAL_SYNC:
+            return TMCLOCK_FREQ_VIRTUAL;
+
+        case TMCLOCK_REAL:
+            return TMCLOCK_FREQ_REAL;
+
+        default:
+            AssertMsgFailed(("Invalid enmClock=%d\n", pTimer->enmClock));
+            return 0;
+    }
+}
+
+
+static DECLCALLBACK(uint64_t) tstDevVmm_TMTimerGetNano(PTMTIMER pTimer)
+{
+    RT_NOREF(pTimer);
+    AssertFailed();
+    return 0;
+}
+
+
+static DECLCALLBACK(bool) tstDevVmm_TMTimerIsActive(PTMTIMER pTimer)
+{
+    RT_NOREF(pTimer);
+    AssertFailed();
+    return false;
+}
+
+
+static DECLCALLBACK(bool) tstDevVmm_TMTimerIsLockOwner(PTMTIMER pTimer)
+{
+    RT_NOREF(pTimer);
+    AssertFailed();
+    return false;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_TMTimerLock(PTMTIMER pTimer, int rcBusy)
+{
+    RT_NOREF(pTimer, rcBusy);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(PTMTIMERR0) tstDevVmm_TMTimerR0Ptr(PTMTIMER pTimer)
+{
+    return (PTMTIMERR0)pTimer;
+}
+
+
+static DECLCALLBACK(PTMTIMERRC) tstDevVmm_TMTimerRCPtr(PTMTIMER pTimer)
+{
+    RT_NOREF(pTimer);
+    /* Impossible to implement RC modules at the moment. */
+    return NIL_RTRCPTR;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_TMTimerSet(PTMTIMER pTimer, uint64_t u64Expire)
+{
+    RT_NOREF(pTimer, u64Expire);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_TMTimerSetFrequencyHint(PTMTIMER pTimer, uint32_t uHz)
+{
+    RT_NOREF(pTimer, uHz);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_TMTimerSetMicro(PTMTIMER pTimer, uint64_t cMicrosToNext)
+{
+    RT_NOREF(pTimer, cMicrosToNext);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_TMTimerSetMillies(PTMTIMER pTimer, uint32_t cMilliesToNext)
+{
+    RT_NOREF(pTimer, cMilliesToNext);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_TMTimerSetNano(PTMTIMER pTimer, uint64_t cNanosToNext)
+{
+    RT_NOREF(pTimer, cNanosToNext);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_TMTimerStop(PTMTIMER pTimer)
+{
+    RT_NOREF(pTimer);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(void) tstDevVmm_TMTimerUnlock(PTMTIMER pTimer)
+{
+    RT_NOREF(pTimer);
+    AssertFailed();
+}
+
+
+static DECLCALLBACK(PVMCPU) tstDevVmm_VMMGetCpu(PVM pVM)
+{
+    RT_NOREF(pVM);
+    AssertFailed();
+    return NULL;
+}
+
+
+static DECLCALLBACK(VMCPUID) tstDevVmm_VMMGetCpuId(PVM pVM)
+{
+    RT_NOREF(pVM);
+    AssertFailed();
+    return NIL_VMCPUID;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_VMMR3DeregisterPatchMemory(PVM pVM, RTGCPTR pPatchMem, unsigned cbPatchMem)
+{
+    RT_NOREF(pVM, pPatchMem, cbPatchMem);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_VMMR3RegisterPatchMemory(PVM pVM, RTGCPTR pPatchMem, unsigned cbPatchMem)
+{
+    RT_NOREF(pVM, pPatchMem, cbPatchMem);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(RTNATIVETHREAD) tstDevVmm_VMR3GetVMCPUNativeThread(PVM pVM)
+{
+    RT_NOREF(pVM);
+    AssertFailed();
+    return NIL_RTNATIVETHREAD;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_VMR3NotifyCpuDeviceReady(PVM pVM, VMCPUID idCpu)
+{
+    RT_NOREF(pVM, idCpu);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_VMR3ReqCallNoWait(PVM pVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...)
+{
+    RT_NOREF(pVM, idDstCpu, pfnFunction, cArgs);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_VMR3ReqCallVoidNoWait(PVM pVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...)
+{
+    RT_NOREF(pVM, idDstCpu, pfnFunction, cArgs);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_VMR3ReqPriorityCallWait(PVM pVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...)
+{
+    RT_NOREF(pVM, idDstCpu, pfnFunction, cArgs);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+static DECLCALLBACK(int) tstDevVmm_VMR3WaitForDeviceReady(PVM pVM, VMCPUID idCpu)
+{
+    RT_NOREF(pVM, idCpu);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+
+const TSTDEVVMMCALLBACKS g_tstDevVmmCallbacks =
+{
+    tstDevVmm_CFGMR3AreValuesValid,
+    tstDevVmm_CFGMR3Dump,
+    tstDevVmm_CFGMR3GetChild,
+    tstDevVmm_CFGMR3GetChildFV,
+    tstDevVmm_CFGMR3GetFirstChild,
+    tstDevVmm_CFGMR3GetName,
+    tstDevVmm_CFGMR3GetNextChild,
+    tstDevVmm_CFGMR3GetParent,
+    tstDevVmm_CFGMR3GetRoot,
+    tstDevVmm_CFGMR3InsertNode,
+    tstDevVmm_CFGMR3InsertNodeFV,
+    tstDevVmm_CFGMR3InsertString,
+    tstDevVmm_CFGMR3QueryBytes,
+    tstDevVmm_CFGMR3QueryInteger,
+    tstDevVmm_CFGMR3QuerySize,
+    tstDevVmm_CFGMR3QueryString,
+    tstDevVmm_CFGMR3QueryStringAlloc,
+    tstDevVmm_CFGMR3QueryStringAllocDef,
+    tstDevVmm_CFGMR3RemoveNode,
+    tstDevVmm_CFGMR3ValidateConfig,
+    tstDevVmm_IOMIOPortWrite,
+    tstDevVmm_IOMMMIOMapMMIO2Page,
+    tstDevVmm_IOMMMIOResetRegion,
+    tstDevVmm_MMHyperAlloc,
+    tstDevVmm_MMHyperFree,
+    tstDevVmm_MMHyperR3ToR0,
+    tstDevVmm_MMHyperR3ToRC,
+    tstDevVmm_MMR3HeapFree,
+    tstDevVmm_MMR3HyperAllocOnceNoRel,
+    tstDevVmm_MMR3PhysGetRamSize,
+    tstDevVmm_MMR3PhysGetRamSizeAbove4GB,
+    tstDevVmm_MMR3PhysGetRamSizeBelow4GB,
+    tstDevVmm_PDMCritSectEnterDebug,
+    tstDevVmm_PDMCritSectIsInitialized,
+    tstDevVmm_PDMCritSectIsOwner,
+    tstDevVmm_PDMCritSectLeave,
+    tstDevVmm_PDMCritSectTryEnterDebug,
+    tstDevVmm_PDMHCCritSectScheduleExitEvent,
+    tstDevVmm_PDMNsAllocateBandwidth,
+    tstDevVmm_PDMQueueAlloc,
+    tstDevVmm_PDMQueueFlushIfNecessary,
+    tstDevVmm_PDMQueueInsert,
+    tstDevVmm_PDMQueueR0Ptr,
+    tstDevVmm_PDMQueueRCPtr,
+    tstDevVmm_PDMR3AsyncCompletionEpClose,
+    tstDevVmm_PDMR3AsyncCompletionEpCreateForFile,
+    tstDevVmm_PDMR3AsyncCompletionEpFlush,
+    tstDevVmm_PDMR3AsyncCompletionEpGetSize,
+    tstDevVmm_PDMR3AsyncCompletionEpRead,
+    tstDevVmm_PDMR3AsyncCompletionEpSetBwMgr,
+    tstDevVmm_PDMR3AsyncCompletionEpSetSize,
+    tstDevVmm_PDMR3AsyncCompletionEpWrite,
+    tstDevVmm_PDMR3AsyncCompletionTemplateDestroy,
+    tstDevVmm_PDMR3BlkCacheClear,
+    tstDevVmm_PDMR3BlkCacheDiscard,
+    tstDevVmm_PDMR3BlkCacheFlush,
+    tstDevVmm_PDMR3BlkCacheIoXferComplete,
+    tstDevVmm_PDMR3BlkCacheRead,
+    tstDevVmm_PDMR3BlkCacheRelease,
+    tstDevVmm_PDMR3BlkCacheResume,
+    tstDevVmm_PDMR3BlkCacheSuspend,
+    tstDevVmm_PDMR3BlkCacheWrite,
+    tstDevVmm_PDMR3CritSectDelete,
+    tstDevVmm_PDMR3QueryLun,
+    tstDevVmm_PDMR3ThreadDestroy,
+    tstDevVmm_PDMR3ThreadResume,
+    tstDevVmm_PDMR3ThreadSleep,
+    tstDevVmm_PDMR3ThreadSuspend,
+    tstDevVmm_TMCpuTicksPerSecond,
+    tstDevVmm_TMR3TimerDestroy,
+    tstDevVmm_TMR3TimerLoad,
+    tstDevVmm_TMR3TimerSave,
+    tstDevVmm_TMR3TimerSetCritSect,
+    tstDevVmm_TMTimerFromMilli,
+    tstDevVmm_TMTimerFromNano,
+    tstDevVmm_TMTimerGet,
+    tstDevVmm_TMTimerGetFreq,
+    tstDevVmm_TMTimerGetNano,
+    tstDevVmm_TMTimerIsActive,
+    tstDevVmm_TMTimerIsLockOwner,
+    tstDevVmm_TMTimerLock,
+    tstDevVmm_TMTimerR0Ptr,
+    tstDevVmm_TMTimerRCPtr,
+    tstDevVmm_TMTimerSet,
+    tstDevVmm_TMTimerSetFrequencyHint,
+    tstDevVmm_TMTimerSetMicro,
+    tstDevVmm_TMTimerSetMillies,
+    tstDevVmm_TMTimerSetNano,
+    tstDevVmm_TMTimerStop,
+    tstDevVmm_TMTimerUnlock,
+    tstDevVmm_VMMGetCpu,
+    tstDevVmm_VMMGetCpuId,
+    tstDevVmm_VMMR3DeregisterPatchMemory,
+    tstDevVmm_VMMR3RegisterPatchMemory,
+    tstDevVmm_VMR3GetVMCPUNativeThread,
+    tstDevVmm_VMR3NotifyCpuDeviceReady,
+    tstDevVmm_VMR3ReqCallNoWait,
+    tstDevVmm_VMR3ReqCallVoidNoWait,
+    tstDevVmm_VMR3ReqPriorityCallWait,
+    tstDevVmm_VMR3WaitForDeviceReady
+};
+
Index: trunk/src/VBox/Devices/testcase/tstDeviceVMMInternal.h
===================================================================
--- trunk/src/VBox/Devices/testcase/tstDeviceVMMInternal.h	(revision 69162)
+++ trunk/src/VBox/Devices/testcase/tstDeviceVMMInternal.h	(revision 69162)
@@ -0,0 +1,332 @@
+/* $Id$ */
+/** @file
+ * tstDevice - Test framework for PDM devices/drivers, definitions of VMM internal types.
+ */
+
+/*
+ * Copyright (C) 2017 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.
+ */
+#ifndef ___tstDeviceVMMInternal_h
+#define ___tstDeviceVMMInternal_h
+
+#include <VBox/types.h>
+#include <VBox/vmm/tm.h>
+#include <iprt/critsect.h>
+#include <iprt/list.h>
+
+RT_C_DECLS_BEGIN
+
+/** Pointer to a VMM callback table. */
+typedef struct TSTDEVVMMCALLBACKS *PTSTDEVVMMCALLBACKS;
+/** Pointer to a constant VMM callback table. */
+typedef const struct TSTDEVVMMCALLBACKS *PCTSTDEVVMMCALLBACKS;
+
+/** Pointer to the internal device under test instance. */
+typedef struct TSTDEVDUTINT *PTSTDEVDUTINT;
+/** Pointer to a constant device under test instance. */
+typedef const struct TSTDEVDUTINT *PCTSTDEVDUTINT;
+
+/**
+ * Private device instance data.
+ */
+typedef struct PDMDEVINSINT
+{
+    /** Pointer to the callback table. */
+    PCTSTDEVVMMCALLBACKS            pVmmCallbacks;
+    /** Pointer to the device under test the PDM device instance is for. */
+    PTSTDEVDUTINT                   pDut;
+} PDMDEVINSINT;
+AssertCompile(sizeof(PDMDEVINSINT) <= (HC_ARCH_BITS == 32 ? 72 : 112 + 0x28));
+
+/**
+ * CFGM node structure.
+ */
+typedef struct CFGMNODE
+{
+    /** Pointer to the callback table. */
+    PCTSTDEVVMMCALLBACKS pVmmCallbacks;
+    /** Device under test this CFGM node is for. */
+    PTSTDEVDUTINT        pDut;
+    /** @todo: */
+} CFGMNODE;
+
+/**
+ * PDM queue structure.
+ */
+typedef struct PDMQUEUE
+{
+    /** Pointer to the callback table. */
+    PCTSTDEVVMMCALLBACKS pVmmCallbacks;
+    /** @todo: */
+} PDMQUEUE;
+
+/**
+ * TM timer structure.
+ */
+typedef struct TMTIMER
+{
+    /** Pointer to the callback table. */
+    PCTSTDEVVMMCALLBACKS pVmmCallbacks;
+    /** List of timers created by the device. */
+    RTLISTNODE           NdDevTimers;
+    /** Clock this timer belongs to. */
+    TMCLOCK              enmClock;
+    /** Callback to call when the timer expires. */
+    PFNTMTIMERDEV        pfnCallbackDev;
+    /** Opaque user data to pass to the callback. */
+    void                 *pvUser;
+    /** Flags. */
+    uint32_t             fFlags;
+    /** @todo: */
+} TMTIMER;
+
+/**
+ * Internal VMM structure of VMCPU
+ */
+typedef struct VMMCPU
+{
+    /** Pointer to the callback table. */
+    PCTSTDEVVMMCALLBACKS pVmmCallbacks;
+    /** @todo: */
+} VMMCPU;
+AssertCompile(sizeof(VMMCPU) <= 704);
+
+/**
+ * Internal VMM structure of VM
+ */
+typedef struct VMM
+{
+    /** Pointer to the callback table. */
+    PCTSTDEVVMMCALLBACKS pVmmCallbacks;
+    /** @todo: */
+} VMM;
+AssertCompile(sizeof(VMM) <= 1600);
+
+/**
+ * Internal VM structure of VM
+ */
+typedef struct VMINT
+{
+    /** Pointer to the callback table. */
+    PCTSTDEVVMMCALLBACKS pVmmCallbacks;
+    /** @todo: */
+} VMINT;
+AssertCompile(sizeof(VMINT) <= 24);
+
+/**
+ * Internal per vCPU user VM structure.
+ */
+typedef struct VMINTUSERPERVMCPU
+{
+    /** Pointer to the callback table. */
+    PCTSTDEVVMMCALLBACKS pVmmCallbacks;
+    /** @todo: */
+} VMINTUSERPERVMCPU;
+AssertCompile(sizeof(VMINTUSERPERVMCPU) <= 512);
+
+/**
+ * Internal user VM structure.
+ */
+typedef struct VMINTUSERPERVM
+{
+    /** Pointer to the callback table. */
+    PCTSTDEVVMMCALLBACKS pVmmCallbacks;
+    /** @todo: */
+} VMINTUSERPERVM;
+AssertCompile(sizeof(VMINTUSERPERVM) <= 512);
+
+/**
+ * Internal PDM critical section structure.
+ */
+typedef struct PDMCRITSECTINT
+{
+    /** Pointer to the callback table. */
+    PCTSTDEVVMMCALLBACKS pVmmCallbacks;
+    /** The actual critical section used for emulation. */
+    RTCRITSECT           CritSect;
+} PDMCRITSECTINT;
+AssertCompile(sizeof(PDMCRITSECTINT) <= (HC_ARCH_BITS == 32 ? 0x80 : 0xc0));
+
+/**
+ * Internal PDM thread instance data.
+ */
+typedef struct PDMTHREADINT
+{
+    /** Pointer to the callback table. */
+    PCTSTDEVVMMCALLBACKS pVmmCallbacks;
+    /** @todo: */
+} PDMTHREADINT;
+AssertCompile(sizeof(PDMTHREADINT) <= 64);
+
+#if 0
+/**
+ * Internal PDM netshaper filter instance data.
+ */
+typedef struct PDMNSFILTER
+{
+    /** Pointer to the callback table. */
+    PCTSTDEVVMMCALLBACKS pVmmCallbacks;
+    /** @todo: */
+} PDMNSFILTER;
+#endif
+
+#define PDMCRITSECTINT_DECLARED
+#define PDMTHREADINT_DECLARED
+#define PDMDEVINSINT_DECLARED
+#define ___VMInternal_h
+#define ___VMMInternal_h
+RT_C_DECLS_END
+#include <VBox/vmm/pdmcritsect.h>
+#include <VBox/vmm/vm.h>
+#include <VBox/vmm/uvm.h>
+#include <VBox/vmm/cfgm.h>
+#include <VBox/vmm/tm.h>
+#include <VBox/vmm/pdmblkcache.h>
+#include <VBox/vmm/pdmdev.h>
+#include <VBox/vmm/pdmqueue.h>
+#include <VBox/vmm/pdmthread.h>
+#include <VBox/vmm/cfgm.h>
+#include <VBox/vmm/mm.h>
+#include <VBox/vmm/pdmasynccompletion.h>
+#include <VBox/vmm/pdmnetshaper.h>
+#include <VBox/vmm/pgm.h>
+RT_C_DECLS_BEGIN
+
+
+/**
+ * Callback table from the VMM shim library to the PDM test framework.
+ */
+typedef struct TSTDEVVMMCALLBACKS
+{
+    DECLR3CALLBACKMEMBER(bool, pfnCFGMR3AreValuesValid, (PCFGMNODE pNode, const char *pszzValid));
+    DECLR3CALLBACKMEMBER(void, pfnCFGMR3Dump, (PCFGMNODE pRoot));
+    DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMR3GetChild, (PCFGMNODE pNode, const char *pszPath));
+    DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMR3GetChildFV, (PCFGMNODE pNode, const char *pszPathFormat, va_list Args));
+    DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMR3GetFirstChild, (PCFGMNODE pNode));
+    DECLR3CALLBACKMEMBER(int, pfnCFGMR3GetName, (PCFGMNODE pCur, char *pszName, size_t cchName));
+    DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMR3GetNextChild, (PCFGMNODE pCur));
+    DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMR3GetParent, (PCFGMNODE pNode));
+    DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMR3GetRoot, (PVM pVM));
+    DECLR3CALLBACKMEMBER(int, pfnCFGMR3InsertNode, (PCFGMNODE pNode, const char *pszName, PCFGMNODE *ppChild));
+    DECLR3CALLBACKMEMBER(int, pfnCFGMR3InsertNodeFV, (PCFGMNODE pNode, PCFGMNODE *ppChild,
+                                                     const char *pszNameFormat, va_list Args));
+    DECLR3CALLBACKMEMBER(int, pfnCFGMR3InsertString, (PCFGMNODE pNode, const char *pszName, const char *pszString));
+    DECLR3CALLBACKMEMBER(int, pfnCFGMR3QueryBytes, (PCFGMNODE pNode, const char *pszName, void *pvData, size_t cbData));
+    DECLR3CALLBACKMEMBER(int, pfnCFGMR3QueryInteger, (PCFGMNODE pNode, const char *pszName, uint64_t *pu64));
+    DECLR3CALLBACKMEMBER(int, pfnCFGMR3QuerySize, (PCFGMNODE pNode, const char *pszName, size_t *pcb));
+    DECLR3CALLBACKMEMBER(int, pfnCFGMR3QueryString, (PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString));
+    DECLR3CALLBACKMEMBER(int, pfnCFGMR3QueryStringAlloc, (PCFGMNODE pNode, const char *pszName, char **ppszString));
+    DECLR3CALLBACKMEMBER(int, pfnCFGMR3QueryStringAllocDef, (PCFGMNODE pNode, const char *pszName, char **ppszString, const char *pszDef));
+    DECLR3CALLBACKMEMBER(void, pfnCFGMR3RemoveNode, (PCFGMNODE pNode));
+    DECLR3CALLBACKMEMBER(int, pfnCFGMR3ValidateConfig, (PCFGMNODE pNode, const char *pszNode,
+                                                        const char *pszValidValues, const char *pszValidNodes,
+                                                        const char *pszWho, uint32_t uInstance));
+
+    DECLR3CALLBACKMEMBER(int, pfnIOMIOPortWrite, (PVM pVM, PVMCPU pVCpu, RTIOPORT Port, uint32_t u32Value, size_t cbValue));
+    DECLR3CALLBACKMEMBER(int, pfnIOMMMIOMapMMIO2Page, (PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysRemapped, uint64_t fPageFlags));
+    DECLR3CALLBACKMEMBER(int, pfnIOMMMIOResetRegion, (PVM pVM, RTGCPHYS GCPhys));
+    DECLR3CALLBACKMEMBER(int, pfnMMHyperAlloc, (PVM pVM, size_t cb, uint32_t uAlignment, MMTAG enmTag, void **ppv));
+    DECLR3CALLBACKMEMBER(int, pfnMMHyperFree, (PVM pVM, void *pv));
+    DECLR3CALLBACKMEMBER(RTR0PTR, pfnMMHyperR3ToR0, (PVM pVM, RTR3PTR R3Ptr));
+    DECLR3CALLBACKMEMBER(RTRCPTR, pfnMMHyperR3ToRC, (PVM pVM, RTR3PTR R3Ptr));
+    DECLR3CALLBACKMEMBER(void, pfnMMR3HeapFree, (void *pv));
+    DECLR3CALLBACKMEMBER(int, pfnMMR3HyperAllocOnceNoRel, (PVM pVM, size_t cb, uint32_t uAlignment, MMTAG enmTag, void **ppv));
+    DECLR3CALLBACKMEMBER(uint64_t, pfnMMR3PhysGetRamSize, (PVM pVM));
+    DECLR3CALLBACKMEMBER(uint64_t, pfnMMR3PhysGetRamSizeAbove4GB, (PVM pVM));
+    DECLR3CALLBACKMEMBER(uint32_t, pfnMMR3PhysGetRamSizeBelow4GB, (PVM pVM));
+    DECLR3CALLBACKMEMBER(int, pfnPDMCritSectEnterDebug, (PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL));
+    DECLR3CALLBACKMEMBER(bool, pfnPDMCritSectIsInitialized, (PCPDMCRITSECT pCritSect));
+    DECLR3CALLBACKMEMBER(bool, pfnPDMCritSectIsOwner, (PCPDMCRITSECT pCritSect));
+    DECLR3CALLBACKMEMBER(int, pfnPDMCritSectLeave, (PPDMCRITSECT pCritSect));
+    DECLR3CALLBACKMEMBER(int, pfnPDMCritSectTryEnterDebug, (PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL));
+    DECLR3CALLBACKMEMBER(int, pfnPDMHCCritSectScheduleExitEvent, (PPDMCRITSECT pCritSect, SUPSEMEVENT hEventToSignal));
+    DECLR3CALLBACKMEMBER(bool, pfnPDMNsAllocateBandwidth, (PPDMNSFILTER pFilter, size_t cbTransfer));
+    DECLR3CALLBACKMEMBER(PPDMQUEUEITEMCORE, pfnPDMQueueAlloc, (PPDMQUEUE pQueue));
+    DECLR3CALLBACKMEMBER(bool, pfnPDMQueueFlushIfNecessary, (PPDMQUEUE pQueue));
+    DECLR3CALLBACKMEMBER(void, pfnPDMQueueInsert, (PPDMQUEUE pQueue, PPDMQUEUEITEMCORE pItem));
+    DECLR3CALLBACKMEMBER(R0PTRTYPE(PPDMQUEUE), pfnPDMQueueR0Ptr, (PPDMQUEUE pQueue));
+    DECLR3CALLBACKMEMBER(RCPTRTYPE(PPDMQUEUE), pfnPDMQueueRCPtr, (PPDMQUEUE pQueue));
+    DECLR3CALLBACKMEMBER(int, pfnPDMR3AsyncCompletionEpClose, (PPDMASYNCCOMPLETIONENDPOINT pEndpoint));
+    DECLR3CALLBACKMEMBER(int, pfnPDMR3AsyncCompletionEpCreateForFile, (PPPDMASYNCCOMPLETIONENDPOINT ppEndpoint,
+                                                                       const char *pszFilename, uint32_t fFlags,
+                                                                       PPDMASYNCCOMPLETIONTEMPLATE pTemplate));
+    DECLR3CALLBACKMEMBER(int, pfnPDMR3AsyncCompletionEpFlush, (PPDMASYNCCOMPLETIONENDPOINT pEndpoint, void *pvUser,
+                                                               PPPDMASYNCCOMPLETIONTASK ppTask));
+    DECLR3CALLBACKMEMBER(int, pfnPDMR3AsyncCompletionEpGetSize, (PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t *pcbSize));
+    DECLR3CALLBACKMEMBER(int, pfnPDMR3AsyncCompletionEpRead, (PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off,
+                                                              PCRTSGSEG paSegments, unsigned cSegments,
+                                                              size_t cbRead, void *pvUser,
+                                                              PPPDMASYNCCOMPLETIONTASK ppTask));
+    DECLR3CALLBACKMEMBER(int, pfnPDMR3AsyncCompletionEpSetBwMgr, (PPDMASYNCCOMPLETIONENDPOINT pEndpoint, const char *pszBwMgr));
+    DECLR3CALLBACKMEMBER(int, pfnPDMR3AsyncCompletionEpSetSize, (PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t cbSize));
+    DECLR3CALLBACKMEMBER(int, pfnPDMR3AsyncCompletionEpWrite, (PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off,
+                                                               PCRTSGSEG paSegments, unsigned cSegments,
+                                                               size_t cbWrite, void *pvUser,
+                                                               PPPDMASYNCCOMPLETIONTASK ppTask));
+    DECLR3CALLBACKMEMBER(int, pfnPDMR3AsyncCompletionTemplateDestroy, (PPDMASYNCCOMPLETIONTEMPLATE pTemplate));
+    DECLR3CALLBACKMEMBER(int, pfnPDMR3BlkCacheClear, (PPDMBLKCACHE pBlkCache));
+    DECLR3CALLBACKMEMBER(int, pfnPDMR3BlkCacheDiscard, (PPDMBLKCACHE pBlkCache, PCRTRANGE paRanges,
+                                                        unsigned cRanges, void *pvUser));
+    DECLR3CALLBACKMEMBER(int, pfnPDMR3BlkCacheFlush, (PPDMBLKCACHE pBlkCache, void *pvUser));
+    DECLR3CALLBACKMEMBER(int, pfnPDMR3BlkCacheIoXferComplete, (PPDMBLKCACHE pBlkCache, PPDMBLKCACHEIOXFER hIoXfer, int rcIoXfer));
+    DECLR3CALLBACKMEMBER(int, pfnPDMR3BlkCacheRead, (PPDMBLKCACHE pBlkCache, uint64_t off, PCRTSGBUF pSgBuf, size_t cbRead, void *pvUser));
+    DECLR3CALLBACKMEMBER(int, pfnPDMR3BlkCacheRelease, (PPDMBLKCACHE pBlkCache));
+    DECLR3CALLBACKMEMBER(int, pfnPDMR3BlkCacheResume, (PPDMBLKCACHE pBlkCache));
+    DECLR3CALLBACKMEMBER(int, pfnPDMR3BlkCacheSuspend, (PPDMBLKCACHE pBlkCache));
+    DECLR3CALLBACKMEMBER(int, pfnPDMR3BlkCacheWrite, (PPDMBLKCACHE pBlkCache, uint64_t off, PCRTSGBUF pSgBuf, size_t cbWrite, void *pvUser));
+    DECLR3CALLBACKMEMBER(int, pfnPDMR3CritSectDelete, (PPDMCRITSECT pCritSect));
+    DECLR3CALLBACKMEMBER(int, pfnPDMR3QueryLun, (PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPPDMIBASE ppBase));
+    DECLR3CALLBACKMEMBER(int, pfnPDMR3ThreadDestroy, (PPDMTHREAD pThread, int *pRcThread));
+    DECLR3CALLBACKMEMBER(int, pfnPDMR3ThreadResume, (PPDMTHREAD pThread));
+    DECLR3CALLBACKMEMBER(int, pfnPDMR3ThreadSleep, (PPDMTHREAD pThread, RTMSINTERVAL cMillies));
+    DECLR3CALLBACKMEMBER(int, pfnPDMR3ThreadSuspend, (PPDMTHREAD pThread));
+    DECLR3CALLBACKMEMBER(uint64_t, pfnTMCpuTicksPerSecond, (PVM pVM));
+    DECLR3CALLBACKMEMBER(int, pfnTMR3TimerDestroy, (PTMTIMER pTimer));
+    DECLR3CALLBACKMEMBER(int, pfnTMR3TimerLoad, (PTMTIMERR3 pTimer, PSSMHANDLE pSSM));
+    DECLR3CALLBACKMEMBER(int, pfnTMR3TimerSave, (PTMTIMERR3 pTimer, PSSMHANDLE pSSM));
+    DECLR3CALLBACKMEMBER(int, pfnTMR3TimerSetCritSect, (PTMTIMERR3 pTimer, PPDMCRITSECT pCritSect));
+    DECLR3CALLBACKMEMBER(uint64_t, pfnTMTimerFromMilli, (PTMTIMER pTimer, uint64_t cMilliSecs));
+    DECLR3CALLBACKMEMBER(uint64_t, pfnTMTimerFromNano, (PTMTIMER pTimer, uint64_t cNanoSecs));
+    DECLR3CALLBACKMEMBER(uint64_t, pfnTMTimerGet, (PTMTIMER pTimer));
+    DECLR3CALLBACKMEMBER(uint64_t, pfnTMTimerGetFreq, (PTMTIMER pTimer));
+    DECLR3CALLBACKMEMBER(uint64_t, pfnTMTimerGetNano, (PTMTIMER pTimer));
+    DECLR3CALLBACKMEMBER(bool, pfnTMTimerIsActive, (PTMTIMER pTimer));
+    DECLR3CALLBACKMEMBER(bool, pfnTMTimerIsLockOwner, (PTMTIMER pTimer));
+    DECLR3CALLBACKMEMBER(int, pfnTMTimerLock, (PTMTIMER pTimer, int rcBusy));
+    DECLR3CALLBACKMEMBER(PTMTIMERR0, pfnTMTimerR0Ptr, (PTMTIMER pTimer));
+    DECLR3CALLBACKMEMBER(PTMTIMERRC, pfnTMTimerRCPtr, (PTMTIMER pTimer));
+    DECLR3CALLBACKMEMBER(int, pfnTMTimerSet, (PTMTIMER pTimer, uint64_t u64Expire));
+    DECLR3CALLBACKMEMBER(int, pfnTMTimerSetFrequencyHint, (PTMTIMER pTimer, uint32_t uHz));
+    DECLR3CALLBACKMEMBER(int, pfnTMTimerSetMicro, (PTMTIMER pTimer, uint64_t cMicrosToNext));
+    DECLR3CALLBACKMEMBER(int, pfnTMTimerSetMillies, (PTMTIMER pTimer, uint32_t cMilliesToNext));
+    DECLR3CALLBACKMEMBER(int, pfnTMTimerSetNano, (PTMTIMER pTimer, uint64_t cNanosToNext));
+    DECLR3CALLBACKMEMBER(int, pfnTMTimerStop, (PTMTIMER pTimer));
+    DECLR3CALLBACKMEMBER(void, pfnTMTimerUnlock, (PTMTIMER pTimer));
+    DECLR3CALLBACKMEMBER(PVMCPU, pfnVMMGetCpu, (PVM pVM));
+    DECLR3CALLBACKMEMBER(VMCPUID, pfnVMMGetCpuId, (PVM pVM));
+    DECLR3CALLBACKMEMBER(int, pfnVMMR3DeregisterPatchMemory, (PVM pVM, RTGCPTR pPatchMem, unsigned cbPatchMem));
+    DECLR3CALLBACKMEMBER(int, pfnVMMR3RegisterPatchMemory, (PVM pVM, RTGCPTR pPatchMem, unsigned cbPatchMem));
+    DECLR3CALLBACKMEMBER(RTNATIVETHREAD, pfnVMR3GetVMCPUNativeThread, (PVM pVM));
+    DECLR3CALLBACKMEMBER(int, pfnVMR3NotifyCpuDeviceReady, (PVM pVM, VMCPUID idCpu));
+    DECLR3CALLBACKMEMBER(int, pfnVMR3ReqCallNoWait, (PVM pVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...));
+    DECLR3CALLBACKMEMBER(int, pfnVMR3ReqCallVoidNoWait, (PVM pVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...));
+    DECLR3CALLBACKMEMBER(int, pfnVMR3ReqPriorityCallWait, (PVM pVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...));
+    DECLR3CALLBACKMEMBER(int, pfnVMR3WaitForDeviceReady, (PVM pVM, VMCPUID idCpu));
+} TSTDEVVMMCALLBACKS;
+
+
+extern const PDMDEVHLPR3 g_tstDevPdmDevHlpR3;
+extern const TSTDEVVMMCALLBACKS g_tstDevVmmCallbacks;
+
+RT_C_DECLS_END
+
+#endif
+
Index: trunk/src/VBox/Devices/testcase/tstDeviceVMMStubs.cpp
===================================================================
--- trunk/src/VBox/Devices/testcase/tstDeviceVMMStubs.cpp	(revision 69162)
+++ trunk/src/VBox/Devices/testcase/tstDeviceVMMStubs.cpp	(revision 69162)
@@ -0,0 +1,990 @@
+/* $Id$ */
+/** @file
+ * tstDevice - Test framework for PDM devices/drivers, shim library exporting methods
+ *             originally for VBoxVMM for intercepting (we don't want to use the PDM module
+ *             to use the originals from VBoxVMM).
+ */
+
+/*
+ * Copyright (C) 2017 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.
+ */
+/* Methods imported from VBoxVMM by VBoxDD are extracted with:
+ *     objdump -T VBoxDD.so | grep "UND" | awk -F ' ' '{print $5}' | grep -E "^TM|^PGM|^PDM|^CFGM|^IOM|^MM|^VM|^PDM|^SUP" | sort
+ */
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_DEFAULT /** @todo */
+#include <iprt/assert.h>
+#include <iprt/mem.h>
+
+#include <VBox/err.h>
+#include <VBox/cdefs.h>
+
+#include "tstDeviceVMMInternal.h"
+
+/*********************************************************************************************************************************
+*   Defined Constants And Macros                                                                                                 *
+*********************************************************************************************************************************/
+
+
+/*********************************************************************************************************************************
+*   Structures and Typedefs                                                                                                      *
+*********************************************************************************************************************************/
+
+
+/*********************************************************************************************************************************
+*   Global Variables                                                                                                             *
+*********************************************************************************************************************************/
+
+
+/*********************************************************************************************************************************
+*   Internal Functions                                                                                                           *
+*********************************************************************************************************************************/
+
+
+/**
+ * @copydoc CFGMR3AreValuesValid
+ */
+VMMR3DECL(bool) CFGMR3AreValuesValid(PCFGMNODE pNode, const char *pszzValid)
+{
+    return pNode->pVmmCallbacks->pfnCFGMR3AreValuesValid(pNode, pszzValid);
+}
+
+
+/**
+ * @copydoc CFGMR3Dump
+ */
+VMMR3DECL(void) CFGMR3Dump(PCFGMNODE pRoot)
+{
+    pRoot->pVmmCallbacks->pfnCFGMR3Dump(pRoot);
+}
+
+
+/**
+ * @copydoc CFGMR3GetChild
+ */
+VMMR3DECL(PCFGMNODE) CFGMR3GetChild(PCFGMNODE pNode, const char *pszPath)
+{
+    return pNode->pVmmCallbacks->pfnCFGMR3GetChild(pNode, pszPath);
+}
+
+
+/**
+ * @copydoc CFGMR3GetChildF
+ */
+VMMR3DECL(PCFGMNODE) CFGMR3GetChildF(PCFGMNODE pNode, const char *pszPathFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3)
+{
+    va_list Args;
+    va_start(Args, pszPathFormat);
+    PCFGMNODE pChild = pNode->pVmmCallbacks->pfnCFGMR3GetChildFV(pNode, pszPathFormat, Args);
+    va_end(Args);
+
+    return pChild;
+}
+
+
+/**
+ * @copydoc CFGMR3GetFirstChild
+ */
+VMMR3DECL(PCFGMNODE) CFGMR3GetFirstChild(PCFGMNODE pNode)
+{
+    return pNode->pVmmCallbacks->pfnCFGMR3GetFirstChild(pNode);
+}
+
+
+/**
+ * @copydoc CFGMR3GetName
+ */
+VMMR3DECL(int) CFGMR3GetName(PCFGMNODE pCur, char *pszName, size_t cchName)
+{
+    return pCur->pVmmCallbacks->pfnCFGMR3GetName(pCur, pszName, cchName);
+}
+
+
+/**
+ * @copydoc CFGMR3GetFirstChild
+ */
+VMMR3DECL(PCFGMNODE) CFGMR3GetNextChild(PCFGMNODE pNode)
+{
+    return pNode->pVmmCallbacks->pfnCFGMR3GetNextChild(pNode);
+}
+
+
+/**
+ * @copydoc CFGMR3GetParent
+ */
+VMMR3DECL(PCFGMNODE) CFGMR3GetParent(PCFGMNODE pNode)
+{
+    return pNode->pVmmCallbacks->pfnCFGMR3GetParent(pNode);
+}
+
+
+/**
+ * @copydoc CFGMR3GetRoot
+ */
+VMMR3DECL(PCFGMNODE) CFGMR3GetRoot(PVM pVM)
+{
+    return pVM->vm.s.pVmmCallbacks->pfnCFGMR3GetRoot(pVM);
+}
+
+
+/**
+ * @copydoc CFGMR3InsertNode
+ */
+VMMR3DECL(int) CFGMR3InsertNode(PCFGMNODE pNode, const char *pszName, PCFGMNODE *ppChild)
+{
+    return pNode->pVmmCallbacks->pfnCFGMR3InsertNode(pNode, pszName, ppChild);
+}
+
+
+/**
+ * @copydoc CFGMR3InsertNodeF
+ */
+VMMR3DECL(int) CFGMR3InsertNodeF(PCFGMNODE pNode, PCFGMNODE *ppChild,
+                                 const char *pszNameFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4)
+{
+    va_list Args;
+    va_start(Args, pszNameFormat);
+    int rc = pNode->pVmmCallbacks->pfnCFGMR3InsertNodeFV(pNode, ppChild, pszNameFormat, Args);
+    va_end(Args);
+
+    return rc;
+}
+
+
+/**
+ * @copydoc CFGMR3InsertString
+ */
+VMMR3DECL(int) CFGMR3InsertString(PCFGMNODE pNode, const char *pszName, const char *pszString)
+{
+    return pNode->pVmmCallbacks->pfnCFGMR3InsertString(pNode, pszName, pszString);
+}
+
+
+/**
+ * @copydoc CFGMR3QueryBool
+ */
+VMMR3DECL(int) CFGMR3QueryBool(PCFGMNODE pNode, const char *pszName, bool *pf)
+{
+    uint64_t u64;
+    int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
+    if (RT_SUCCESS(rc))
+        *pf = u64 ? true : false;
+    return rc;
+}
+
+
+/**
+ * @copydoc CFGMR3QueryBoolDef
+ */
+VMMR3DECL(int) CFGMR3QueryBoolDef(PCFGMNODE pNode, const char *pszName, bool *pf, bool fDef)
+{
+    uint64_t u64;
+    int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, fDef);
+    *pf = u64 ? true : false;
+    return rc;
+}
+
+
+/**
+ * @copydoc CFGMR3QueryBytes
+ */
+VMMR3DECL(int) CFGMR3QueryBytes(PCFGMNODE pNode, const char *pszName, void *pvData, size_t cbData)
+{
+    return pNode->pVmmCallbacks->pfnCFGMR3QueryBytes(pNode, pszName, pvData, cbData);
+}
+
+
+/**
+ * @copydoc CFGMR3QueryInteger
+ */
+VMMR3DECL(int) CFGMR3QueryInteger(PCFGMNODE pNode, const char *pszName, uint64_t *pu64)
+{
+    return pNode->pVmmCallbacks->pfnCFGMR3QueryInteger(pNode, pszName, pu64);
+}
+
+
+/**
+ * @copydoc CFGMR3QueryIntegerDef
+ */
+VMMR3DECL(int) CFGMR3QueryIntegerDef(PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)
+{
+    int rc = CFGMR3QueryInteger(pNode, pszName, pu64);
+    if (RT_FAILURE(rc))
+    {
+        *pu64 = u64Def;
+        if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
+            rc = VINF_SUCCESS;
+    }
+
+    return rc;
+}
+
+
+/**
+ * @copydoc CFGMR3QueryPortDef
+ */
+VMMR3DECL(int) CFGMR3QueryPortDef(PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort, RTIOPORT PortDef)
+{
+    AssertCompileSize(RTIOPORT, 2);
+    return CFGMR3QueryU16Def(pNode, pszName, pPort, PortDef);
+}
+
+
+/**
+ * @copydoc CFGMR3QueryPtr
+ */
+VMMR3DECL(int) CFGMR3QueryPtr(PCFGMNODE pNode, const char *pszName, void **ppv)
+{
+    uint64_t u64;
+    int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
+    if (RT_SUCCESS(rc))
+    {
+        uintptr_t u = (uintptr_t)u64;
+        if (u64 == u)
+            *ppv = (void *)u;
+        else
+            rc = VERR_CFGM_INTEGER_TOO_BIG;
+    }
+    return rc;
+}
+
+
+/**
+ * @copydoc CFGMR3QueryS32
+ */
+VMMR3DECL(int) CFGMR3QueryS32(PCFGMNODE pNode, const char *pszName, int32_t *pi32)
+{
+    uint64_t u64;
+    int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
+    if (RT_SUCCESS(rc))
+    {
+        if (   !(u64 & UINT64_C(0xffffffff80000000))
+            ||  (u64 & UINT64_C(0xffffffff80000000)) == UINT64_C(0xffffffff80000000))
+            *pi32 = (int32_t)u64;
+        else
+            rc = VERR_CFGM_INTEGER_TOO_BIG;
+    }
+    return rc;
+}
+
+
+/**
+ * @copydoc CFGMR3QueryS32Def
+ */
+VMMR3DECL(int) CFGMR3QueryS32Def(PCFGMNODE pNode, const char *pszName, int32_t *pi32, int32_t i32Def)
+{
+    uint64_t u64;
+    int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, i32Def);
+    if (RT_SUCCESS(rc))
+    {
+        if (   !(u64 & UINT64_C(0xffffffff80000000))
+            ||  (u64 & UINT64_C(0xffffffff80000000)) == UINT64_C(0xffffffff80000000))
+            *pi32 = (int32_t)u64;
+        else
+            rc = VERR_CFGM_INTEGER_TOO_BIG;
+    }
+    if (RT_FAILURE(rc))
+        *pi32 = i32Def;
+    return rc;
+}
+
+
+/**
+ * @copydoc CFGMR3QuerySIntDef
+ */
+VMMR3DECL(int) CFGMR3QuerySIntDef(PCFGMNODE pNode, const char *pszName, signed int *pi, signed int iDef)
+{
+    AssertCompileSize(signed int, 4);
+    return CFGMR3QueryS32Def(pNode, pszName, (int32_t *)pi, iDef);
+}
+
+
+/**
+ * @copydoc CFGMR3QuerySize
+ */
+VMMDECL(int) CFGMR3QuerySize(PCFGMNODE pNode, const char *pszName, size_t *pcb)
+{
+    return pNode->pVmmCallbacks->pfnCFGMR3QuerySize(pNode, pszName, pcb);
+}
+
+
+/**
+ * @copydoc CFGMR3QueryString
+ */
+VMMR3DECL(int) CFGMR3QueryString(PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString)
+{
+    return pNode->pVmmCallbacks->pfnCFGMR3QueryString(pNode, pszName, pszString, cchString);
+}
+
+
+/**
+ * @copydoc CFGMR3QueryStringDef
+ */
+VMMR3DECL(int) CFGMR3QueryStringDef(PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString, const char *pszDef)
+{
+    int rc = CFGMR3QueryString(pNode, pszName, pszString, cchString);
+    if (RT_FAILURE(rc) && rc != VERR_CFGM_NOT_ENOUGH_SPACE)
+    {
+        size_t cchDef = strlen(pszDef);
+        if (cchString > cchDef)
+        {
+            memcpy(pszString, pszDef, cchDef);
+            memset(pszString + cchDef, 0, cchString - cchDef);
+            if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
+                rc = VINF_SUCCESS;
+        }
+        else if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
+            rc = VERR_CFGM_NOT_ENOUGH_SPACE;
+    }
+
+    return rc;
+}
+
+
+/**
+ * @copydoc CFGMR3QueryStringAlloc
+ */
+VMMR3DECL(int) CFGMR3QueryStringAlloc(PCFGMNODE pNode, const char *pszName, char **ppszString)
+{
+#if 0
+    size_t cbString;
+    int rc = CFGMR3QuerySize(pNode, pszName, &cbString);
+    if (RT_SUCCESS(rc))
+    {
+        char *pszString = cfgmR3StrAlloc(pNode->pVM, MM_TAG_CFGM_USER, cbString);
+        if (pszString)
+        {
+            rc = CFGMR3QueryString(pNode, pszName, pszString, cbString);
+            if (RT_SUCCESS(rc))
+                *ppszString = pszString;
+            else
+                cfgmR3StrFree(pNode->pVM, pszString);
+        }
+        else
+            rc = VERR_NO_MEMORY;
+    }
+    return rc;
+#endif
+    RT_NOREF(pNode, pszName, ppszString);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+/**
+ * @copydoc CFGMR3QueryStringAllocDef
+ */
+VMMR3DECL(int) CFGMR3QueryStringAllocDef(PCFGMNODE pNode, const char *pszName, char **ppszString, const char *pszDef)
+{
+    RT_NOREF(pNode, pszName, ppszString, pszDef);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+/**
+ * @copydoc CFGMR3QueryU16
+ */
+VMMR3DECL(int) CFGMR3QueryU16(PCFGMNODE pNode, const char *pszName, uint16_t *pu16)
+{
+    uint64_t u64;
+    int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
+    if (RT_SUCCESS(rc))
+    {
+        if (!(u64 & UINT64_C(0xffffffffffff0000)))
+            *pu16 = (int16_t)u64;
+        else
+            rc = VERR_CFGM_INTEGER_TOO_BIG;
+    }
+    return rc;
+}
+
+
+/**
+ * @copydoc CFGMR3QueryU16Def
+ */
+VMMR3DECL(int) CFGMR3QueryU16Def(PCFGMNODE pNode, const char *pszName, uint16_t *pu16, uint16_t u16Def)
+{
+    uint64_t u64;
+    int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, u16Def);
+    if (RT_SUCCESS(rc))
+    {
+        if (!(u64 & UINT64_C(0xffffffffffff0000)))
+            *pu16 = (int16_t)u64;
+        else
+            rc = VERR_CFGM_INTEGER_TOO_BIG;
+    }
+    if (RT_FAILURE(rc))
+        *pu16 = u16Def;
+    return rc;
+}
+
+
+/**
+ * @copydoc CFGMR3QueryU32
+ */
+VMMR3DECL(int) CFGMR3QueryU32(PCFGMNODE pNode, const char *pszName, uint32_t *pu32)
+{
+    uint64_t u64;
+    int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
+    if (RT_SUCCESS(rc))
+    {
+        if (!(u64 & UINT64_C(0xffffffff00000000)))
+            *pu32 = (uint32_t)u64;
+        else
+            rc = VERR_CFGM_INTEGER_TOO_BIG;
+    }
+    return rc;
+}
+
+
+/**
+ * @copydoc CFGMR3QueryU32Def
+ */
+VMMR3DECL(int) CFGMR3QueryU32Def(PCFGMNODE pNode, const char *pszName, uint32_t *pu32, uint32_t u32Def)
+{
+    uint64_t u64;
+    int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, u32Def);
+    if (RT_SUCCESS(rc))
+    {
+        if (!(u64 & UINT64_C(0xffffffff00000000)))
+            *pu32 = (uint32_t)u64;
+        else
+            rc = VERR_CFGM_INTEGER_TOO_BIG;
+    }
+    if (RT_FAILURE(rc))
+        *pu32 = u32Def;
+    return rc;
+}
+
+
+/**
+ * @copydoc CFGMR3QueryU64
+ */
+VMMR3DECL(int) CFGMR3QueryU64(PCFGMNODE pNode, const char *pszName, uint64_t *pu64)
+{
+    return CFGMR3QueryInteger(pNode, pszName, pu64);
+}
+
+
+/**
+ * @copydoc CFGMR3QueryU64Def
+ */
+VMMR3DECL(int) CFGMR3QueryU64Def(PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)
+{
+    return CFGMR3QueryIntegerDef(pNode, pszName, pu64, u64Def);
+}
+
+
+/**
+ * @copydoc CFGMR3QueryU8
+ */
+VMMR3DECL(int) CFGMR3QueryU8(PCFGMNODE pNode, const char *pszName, uint8_t *pu8)
+{
+    uint64_t u64;
+    int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
+    if (RT_SUCCESS(rc))
+    {
+        if (!(u64 & UINT64_C(0xffffffffffffff00)))
+            *pu8 = (uint8_t)u64;
+        else
+            rc = VERR_CFGM_INTEGER_TOO_BIG;
+    }
+    return rc;
+}
+
+
+/**
+ * @copydoc CFGMR3QueryU8Def
+ */
+VMMR3DECL(int) CFGMR3QueryU8Def(PCFGMNODE pNode, const char *pszName, uint8_t *pu8, uint8_t u8Def)
+{
+    uint64_t u64;
+    int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, u8Def);
+    if (RT_SUCCESS(rc))
+    {
+        if (!(u64 & UINT64_C(0xffffffffffffff00)))
+            *pu8 = (uint8_t)u64;
+        else
+            rc = VERR_CFGM_INTEGER_TOO_BIG;
+    }
+    if (RT_FAILURE(rc))
+        *pu8 = u8Def;
+    return rc;
+}
+
+
+/**
+ * @copydoc CFGMR3RemoveNode
+ */
+VMMR3DECL(void) CFGMR3RemoveNode(PCFGMNODE pNode)
+{
+    pNode->pVmmCallbacks->pfnCFGMR3RemoveNode(pNode);
+}
+
+
+/**
+ * @copydoc CFGMR3ValidateConfig
+ */
+VMMR3DECL(int) CFGMR3ValidateConfig(PCFGMNODE pNode, const char *pszNode,
+                                    const char *pszValidValues, const char *pszValidNodes,
+                                    const char *pszWho, uint32_t uInstance)
+{
+    return pNode->pVmmCallbacks->pfnCFGMR3ValidateConfig(pNode, pszNode, pszValidValues, pszValidNodes, pszWho, uInstance);
+}
+
+
+/**
+ * @copydoc IOMIOPortWrite
+ */
+VMMDECL(VBOXSTRICTRC) IOMIOPortWrite(PVM pVM, PVMCPU pVCpu, RTIOPORT Port, uint32_t u32Value, size_t cbValue)
+{
+    return pVM->vm.s.pVmmCallbacks->pfnIOMIOPortWrite(pVM, pVCpu, Port, u32Value, cbValue);
+}
+
+
+/**
+ * @copydoc IOMMMIOMapMMIO2Page
+ */
+VMMDECL(int) IOMMMIOMapMMIO2Page(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysRemapped, uint64_t fPageFlags)
+{
+    return pVM->vm.s.pVmmCallbacks->pfnIOMMMIOMapMMIO2Page(pVM, GCPhys, GCPhysRemapped, fPageFlags);
+}
+
+
+/**
+ * @copydoc IOMMMIOResetRegion
+ */
+VMMDECL(int) IOMMMIOResetRegion(PVM pVM, RTGCPHYS GCPhys)
+{
+    return pVM->vm.s.pVmmCallbacks->pfnIOMMMIOResetRegion(pVM, GCPhys);
+}
+
+
+/**
+ * @copydoc MMHyperAlloc
+ */
+VMMDECL(int) MMHyperAlloc(PVM pVM, size_t cb, uint32_t uAlignment, MMTAG enmTag, void **ppv)
+{
+    return pVM->vm.s.pVmmCallbacks->pfnMMHyperAlloc(pVM, cb, uAlignment, enmTag, ppv);
+}
+
+
+/**
+ * @copydoc MMHyperFree
+ */
+VMMDECL(int) MMHyperFree(PVM pVM, void *pv)
+{
+    return pVM->vm.s.pVmmCallbacks->pfnMMHyperFree(pVM, pv);
+}
+
+
+/**
+ * @copydoc MMHyperR3ToR0
+ */
+VMMDECL(RTR0PTR) MMHyperR3ToR0(PVM pVM, RTR3PTR R3Ptr)
+{
+    return pVM->vm.s.pVmmCallbacks->pfnMMHyperR3ToR0(pVM, R3Ptr);
+}
+
+
+/**
+ * @copydoc MMHyperR3ToRC
+ */
+VMMDECL(RTRCPTR) MMHyperR3ToRC(PVM pVM, RTR3PTR R3Ptr)
+{
+    return pVM->vm.s.pVmmCallbacks->pfnMMHyperR3ToRC(pVM, R3Ptr);
+}
+
+
+/**
+ * @copydoc MMR3HeapFree
+ */
+VMMR3DECL(void) MMR3HeapFree(void *pv)
+{
+    RTMemFree(pv); /** @todo */
+}
+
+
+/**
+ * @copydoc MMR3HyperAllocOnceNoRel
+ */
+VMMR3DECL(int) MMR3HyperAllocOnceNoRel(PVM pVM, size_t cb, uint32_t uAlignment, MMTAG enmTag, void **ppv)
+{
+    return pVM->vm.s.pVmmCallbacks->pfnMMR3HyperAllocOnceNoRel(pVM, cb, uAlignment, enmTag, ppv);
+}
+
+
+/**
+ * @copydoc MMR3PhysGetRamSize
+ */
+VMMR3DECL(uint64_t) MMR3PhysGetRamSize(PVM pVM)
+{
+    return pVM->vm.s.pVmmCallbacks->pfnMMR3PhysGetRamSize(pVM);
+}
+
+
+/**
+ * @copydoc MMR3PhysGetRamSizeBelow4GB
+ */
+VMMR3DECL(uint32_t) MMR3PhysGetRamSizeBelow4GB(PVM pVM)
+{
+    return pVM->vm.s.pVmmCallbacks->pfnMMR3PhysGetRamSizeBelow4GB(pVM);
+}
+
+
+/**
+ * @copydoc MMR3PhysGetRamSizeAbove4GB
+ */
+VMMR3DECL(uint64_t) MMR3PhysGetRamSizeAbove4GB(PVM pVM)
+{
+    return pVM->vm.s.pVmmCallbacks->pfnMMR3PhysGetRamSizeAbove4GB(pVM);
+}
+
+
+/**
+ * @copydoc PDMCritSectEnterDebug
+ */
+VMMDECL(int) PDMCritSectEnterDebug(PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)
+{
+    return pCritSect->s.pVmmCallbacks->pfnPDMCritSectEnterDebug(pCritSect, rcBusy, uId, RT_SRC_POS_ARGS);
+}
+
+
+/**
+ * @copydoc PDMCritSectIsInitialized
+ */
+VMMDECL(bool) PDMCritSectIsInitialized(PCPDMCRITSECT pCritSect)
+{
+    return pCritSect->s.pVmmCallbacks->pfnPDMCritSectIsInitialized(pCritSect);
+}
+
+
+/**
+ * @copydoc PDMCritSectIsOwner
+ */
+VMMDECL(bool) PDMCritSectIsOwner(PCPDMCRITSECT pCritSect)
+{
+    return pCritSect->s.pVmmCallbacks->pfnPDMCritSectIsOwner(pCritSect);
+}
+
+
+/**
+ * @copydoc PDMCritSectLeave
+ */
+VMMDECL(int) PDMCritSectLeave(PPDMCRITSECT pCritSect)
+{
+    return pCritSect->s.pVmmCallbacks->pfnPDMCritSectLeave(pCritSect);
+}
+
+
+/**
+ * @copydoc PDMCritSectTryEnterDebug
+ */
+VMMDECL(int) PDMCritSectTryEnterDebug(PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)
+{
+    return pCritSect->s.pVmmCallbacks->pfnPDMCritSectTryEnterDebug(pCritSect, uId, RT_SRC_POS_ARGS);
+}
+
+
+/**
+ * @copydoc PDMHCCritSectScheduleExitEvent
+ */
+VMMDECL(int) PDMHCCritSectScheduleExitEvent(PPDMCRITSECT pCritSect, SUPSEMEVENT hEventToSignal)
+{
+    return pCritSect->s.pVmmCallbacks->pfnPDMHCCritSectScheduleExitEvent(pCritSect, hEventToSignal);
+}
+
+
+/**
+ * @copydoc PDMNsAllocateBandwidth
+ */
+VMMDECL(bool) PDMNsAllocateBandwidth(PPDMNSFILTER pFilter, size_t cbTransfer)
+{
+#if 0
+    return pFilter->pVmmCallbacks->pfnPDMNsAllocateBandwidth(pFilter, cbTransfer);
+#endif
+    RT_NOREF(pFilter, cbTransfer);
+    AssertFailed();
+    return false;
+}
+
+
+/**
+ * @copydoc PDMQueueAlloc
+ */
+VMMDECL(PPDMQUEUEITEMCORE) PDMQueueAlloc(PPDMQUEUE pQueue)
+{
+    return pQueue->pVmmCallbacks->pfnPDMQueueAlloc(pQueue);
+}
+
+
+/**
+ * @copydoc PDMQueueFlushIfNecessary
+ */
+VMMDECL(bool) PDMQueueFlushIfNecessary(PPDMQUEUE pQueue)
+{
+    return pQueue->pVmmCallbacks->pfnPDMQueueFlushIfNecessary(pQueue);
+}
+
+
+/**
+ * @copydoc PDMQueueInsert
+ */
+VMMDECL(void) PDMQueueInsert(PPDMQUEUE pQueue, PPDMQUEUEITEMCORE pItem)
+{
+    pQueue->pVmmCallbacks->pfnPDMQueueInsert(pQueue, pItem);
+}
+
+
+/**
+ * @copydoc PDMQueueR0Ptr
+ */
+VMMDECL(R0PTRTYPE(PPDMQUEUE)) PDMQueueR0Ptr(PPDMQUEUE pQueue)
+{
+    return pQueue->pVmmCallbacks->pfnPDMQueueR0Ptr(pQueue);
+}
+
+
+/**
+ * @copydoc PDMQueueRCPtr
+ */
+VMMDECL(RCPTRTYPE(PPDMQUEUE)) PDMQueueRCPtr(PPDMQUEUE pQueue)
+{
+    return pQueue->pVmmCallbacks->pfnPDMQueueRCPtr(pQueue);
+}
+
+
+/**
+ * @copydoc PGMHandlerPhysicalPageTempOff
+ */
+VMMDECL(int) PGMHandlerPhysicalPageTempOff(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage)
+{
+    RT_NOREF(pVM, GCPhys, GCPhysPage);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+
+/**
+ * @copydoc PGMShwMakePageWritable
+ */
+VMMDECL(int) PGMShwMakePageWritable(PVMCPU pVCpu, RTGCPTR GCPtr, uint32_t fFlags)
+{
+    RT_NOREF(pVCpu, GCPtr, fFlags);
+    AssertFailed();
+    return VERR_NOT_IMPLEMENTED;
+}
+
+/** @todo: PDMR3AsyncCompletion + BlkCache + CritSect + QueryLun + Thread. */
+
+/**
+ * @copydoc TMCpuTicksPerSecond
+ */
+VMMDECL(uint64_t) TMCpuTicksPerSecond(PVM pVM)
+{
+    return pVM->vm.s.pVmmCallbacks->pfnTMCpuTicksPerSecond(pVM);
+}
+
+
+/**
+ * @copydoc TMR3TimerDestroy
+ */
+VMMR3DECL(int) TMR3TimerDestroy(PTMTIMER pTimer)
+{
+    return pTimer->pVmmCallbacks->pfnTMR3TimerDestroy(pTimer);
+}
+
+
+/**
+ * @copydoc TMR3TimerSave
+ */
+VMMR3DECL(int) TMR3TimerSave(PTMTIMERR3 pTimer, PSSMHANDLE pSSM)
+{
+    return pTimer->pVmmCallbacks->pfnTMR3TimerSave(pTimer, pSSM);
+}
+
+
+/**
+ * @copydoc TMR3TimerLoad
+ */
+VMMR3DECL(int) TMR3TimerLoad(PTMTIMERR3 pTimer, PSSMHANDLE pSSM)
+{
+    return pTimer->pVmmCallbacks->pfnTMR3TimerLoad(pTimer, pSSM);
+}
+
+
+/**
+ * @copydoc TMR3TimerSetCritSect
+ */
+VMMR3DECL(int) TMR3TimerSetCritSect(PTMTIMERR3 pTimer, PPDMCRITSECT pCritSect)
+{
+    return pTimer->pVmmCallbacks->pfnTMR3TimerSetCritSect(pTimer, pCritSect);
+}
+
+
+/**
+ * @copydoc TMTimerFromMilli
+ */
+VMMDECL(uint64_t) TMTimerFromMilli(PTMTIMER pTimer, uint64_t cMilliSecs)
+{
+    return pTimer->pVmmCallbacks->pfnTMTimerFromMilli(pTimer, cMilliSecs);
+}
+
+
+/**
+ * @copydoc TMTimerFromNano
+ */
+VMMDECL(uint64_t) TMTimerFromNano(PTMTIMER pTimer, uint64_t cNanoSecs)
+{
+    return pTimer->pVmmCallbacks->pfnTMTimerFromNano(pTimer, cNanoSecs);
+}
+
+
+/**
+ * @copydoc TMTimerGet
+ */
+VMMDECL(uint64_t) TMTimerGet(PTMTIMER pTimer)
+{
+    return pTimer->pVmmCallbacks->pfnTMTimerGet(pTimer);
+}
+
+
+/**
+ * @copydoc TMTimerGetFreq
+ */
+VMMDECL(uint64_t) TMTimerGetFreq(PTMTIMER pTimer)
+{
+    return pTimer->pVmmCallbacks->pfnTMTimerGetFreq(pTimer);
+}
+
+
+/**
+ * @copydoc TMTimerGetNano
+ */
+VMMDECL(uint64_t) TMTimerGetNano(PTMTIMER pTimer)
+{
+    return pTimer->pVmmCallbacks->pfnTMTimerGetNano(pTimer);
+}
+
+
+/**
+ * @copydoc TMTimerIsActive
+ */
+VMMDECL(bool) TMTimerIsActive(PTMTIMER pTimer)
+{
+    return pTimer->pVmmCallbacks->pfnTMTimerIsActive(pTimer);
+}
+
+
+/**
+ * @copydoc TMTimerIsLockOwner
+ */
+VMMDECL(bool) TMTimerIsLockOwner(PTMTIMER pTimer)
+{
+    return pTimer->pVmmCallbacks->pfnTMTimerIsLockOwner(pTimer);
+}
+
+
+/**
+ * @copydoc TMTimerLock
+ */
+VMMDECL(int) TMTimerLock(PTMTIMER pTimer, int rcBusy)
+{
+    return pTimer->pVmmCallbacks->pfnTMTimerLock(pTimer, rcBusy);
+}
+
+
+/**
+ * @copydoc TMTimerR0Ptr
+ */
+VMMDECL(PTMTIMERR0) TMTimerR0Ptr(PTMTIMER pTimer)
+{
+    return pTimer->pVmmCallbacks->pfnTMTimerR0Ptr(pTimer);
+}
+
+
+/**
+ * @copydoc TMTimerRCPtr
+ */
+VMMDECL(PTMTIMERRC) TMTimerRCPtr(PTMTIMER pTimer)
+{
+    return pTimer->pVmmCallbacks->pfnTMTimerRCPtr(pTimer);
+}
+
+
+/**
+ * @copydoc TMTimerSet
+ */
+VMMDECL(int) TMTimerSet(PTMTIMER pTimer, uint64_t u64Expire)
+{
+    return pTimer->pVmmCallbacks->pfnTMTimerSet(pTimer, u64Expire);
+}
+
+
+/**
+ * @copydoc TMTimerSetFrequencyHint
+ */
+VMMDECL(int) TMTimerSetFrequencyHint(PTMTIMER pTimer, uint32_t uHz)
+{
+    return pTimer->pVmmCallbacks->pfnTMTimerSetFrequencyHint(pTimer, uHz);
+}
+
+
+/**
+ * @copydoc TMTimerSetMicro
+ */
+VMMDECL(int) TMTimerSetMicro(PTMTIMER pTimer, uint64_t cMicrosToNext)
+{
+    return pTimer->pVmmCallbacks->pfnTMTimerSetMicro(pTimer, cMicrosToNext);
+}
+
+
+/**
+ * @copydoc TMTimerSetMillies
+ */
+VMMDECL(int) TMTimerSetMillies(PTMTIMER pTimer, uint32_t cMilliesToNext)
+{
+    return pTimer->pVmmCallbacks->pfnTMTimerSetMillies(pTimer, cMilliesToNext);
+}
+
+
+/**
+ * @copydoc TMTimerSetNano
+ */
+VMMDECL(int) TMTimerSetNano(PTMTIMER pTimer, uint64_t cNanosToNext)
+{
+    return pTimer->pVmmCallbacks->pfnTMTimerSetNano(pTimer, cNanosToNext);
+}
+
+
+/**
+ * @copydoc TMTimerStop
+ */
+VMMDECL(int) TMTimerStop(PTMTIMER pTimer)
+{
+    return pTimer->pVmmCallbacks->pfnTMTimerStop(pTimer);
+}
+
+
+/**
+ * @copydoc TMTimerUnlock
+ */
+VMMDECL(void) TMTimerUnlock(PTMTIMER pTimer)
+{
+    return pTimer->pVmmCallbacks->pfnTMTimerUnlock(pTimer);
+}
+
+
+
