Index: /trunk/src/VBox/Runtime/testcase/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Runtime/testcase/Makefile.kmk	(revision 32610)
+++ /trunk/src/VBox/Runtime/testcase/Makefile.kmk	(revision 32611)
@@ -144,4 +144,5 @@
 	tstRTR0MemUserKernelDriver \
 	tstRTR0SemMutexDriver \
+	tstRTR0TimerDriver \
 	tstR0ThreadPreemptionDriver \
 	tstTSC
@@ -150,4 +151,5 @@
  	tstRTR0MemUserKernel \
  	tstRTR0SemMutex \
+ 	tstRTR0Timer \
  	tstR0ThreadPreemption
  ifdef VBOX_WITH_RAW_MODE
@@ -346,16 +348,4 @@
 tstRTMemPool_SOURCES = tstRTMemPool.cpp
 
-tstRTR0MemUserKernel_TEMPLATE = VBoxR0
-tstRTR0MemUserKernel_INST = $(INST_TESTCASE)
-tstRTR0MemUserKernel_DEFS = IN_RT_R0
-tstRTR0MemUserKernel_SYSSUFF = .r0
-tstRTR0MemUserKernel_SOURCES = tstRTR0MemUserKernel.cpp
-tstRTR0MemUserKernel_LIBS = $(PATH_LIB)/RuntimeR0$(VBOX_SUFF_LIB)
-if1of ($(VBOX_LDR_FMT), pe lx)
- tstRTR0MemUserKernel_LIBS += $(PATH_LIB)/SUPR0$(VBOX_SUFF_LIB)
-endif
-
-tstRTR0MemUserKernelDriver_SOURCES = tstRTR0MemUserKernelDriver.cpp
-
 tstMove_SOURCES = tstMove.cpp
 
@@ -391,4 +381,131 @@
 tstRand_SOURCES = tstRand.cpp
 
+tstRTFsQueries_SOURCES = tstRTFsQueries.cpp
+
+tstRTProcCreateEx_TEMPLATE = VBOXR3TSTEXE
+tstRTProcCreateEx_SOURCES = tstRTProcCreateEx.cpp
+
+tstRTProcWait_SOURCES = tstRTProcWait.cpp
+
+tstRTProcIsRunningByName_SOURCES = tstRTProcIsRunningByName.cpp
+
+tstRTS3_SOURCES = tstRTS3.cpp
+
+tstSemMutex_SOURCES = tstSemMutex.cpp
+
+tstSemEvent_SOURCES = tstSemEvent.cpp
+
+tstRTSemRW_TEMPLATE = VBOXR3TSTEXE
+tstRTSemRW_SOURCES = tstRTSemRW.cpp
+
+tstSemPingPong_SOURCES = tstSemPingPong.cpp
+
+tstSems_SOURCES = tstSems.cpp
+
+tstRTSemXRoads_TEMPLATE = VBOXR3TSTEXE
+tstRTSemXRoads_SOURCES = tstRTSemXRoads.cpp
+
+tstRTSort_TEMPLATE = VBOXR3TSTEXE
+tstRTSort_SOURCES = tstRTSort.cpp
+
+tstRTStrAlloc_TEMPLATE = VBOXR3TSTEXE
+tstRTStrAlloc_SOURCES = tstRTStrAlloc.cpp
+
+tstRTStrCache_TEMPLATE = VBOXR3TSTEXE
+tstRTStrCache_SOURCES = tstRTStrCache.cpp
+
+tstRTStrFormat_SOURCES = tstRTStrFormat.cpp
+
+tstStrSimplePattern_SOURCES = tstStrSimplePattern.cpp
+
+tstStrToNum_SOURCES = tstStrToNum.cpp
+
+tstRTStrVersion_TEMPLATE = VBOXR3TSTEXE
+tstRTStrVersion_SOURCES = tstRTStrVersion.cpp
+
+tstRTSystemQueryDmi_TEMPLATE = VBOXR3TSTEXE
+tstRTSystemQueryDmi_SOURCES = tstRTSystemQueryDmi.cpp
+
+tstRTSystemQueryOsInfo_TEMPLATE = VBOXR3TSTEXE
+tstRTSystemQueryOsInfo_SOURCES = tstRTSystemQueryOsInfo.cpp
+
+tstRTTemp_TEMPLATE = VBOXR3TSTEXE
+tstRTTemp_SOURCES = tstRTTemp.cpp
+
+tstTermCallbacks_SOURCES = tstTermCallbacks.cpp
+
+tstThread-1_SOURCES = tstThread-1.cpp
+
+tstTime_SOURCES = tstTime.cpp
+
+tstTime-2_SOURCES = tstTime-2.cpp
+
+tstTime-3_SOURCES = tstTime-3.cpp
+
+tstTime-4_SOURCES = tstTime-4.cpp
+
+tstTimer_SOURCES = tstTimer.cpp
+
+tstTimerLR_SOURCES = tstTimerLR.cpp
+
+tstRTTimeSpec_TEMPLATE = VBOXR3TSTEXE
+tstRTTimeSpec_SOURCES = tstRTTimeSpec.cpp
+
+tstTSC_SOURCES = tstTSC.cpp
+tstTSC_CXXFLAGS.linux += -O3
+
+tstRTUuid_TEMPLATE = VBOXR3TSTEXE
+tstRTUuid_SOURCES = tstRTUuid.cpp
+
+tstUtf8_SOURCES = tstUtf8.cpp
+
+tstRTCoreDump_TEMPLACE = VBOXR3TSTEXE
+tstRTCoreDump_SOURCES = tstRTCoreDump.cpp
+
+
+#
+# Ring-0 testcases.
+#
+
+## @todo create a template for compiling the ring-0 part.
+tstRTR0MemUserKernel_TEMPLATE = VBoxR0
+tstRTR0MemUserKernel_INST = $(INST_TESTCASE)
+tstRTR0MemUserKernel_DEFS = IN_RT_R0
+tstRTR0MemUserKernel_SYSSUFF = .r0
+tstRTR0MemUserKernel_SOURCES = tstRTR0MemUserKernel.cpp
+tstRTR0MemUserKernel_LIBS = $(PATH_LIB)/RuntimeR0$(VBOX_SUFF_LIB)
+if1of ($(VBOX_LDR_FMT), pe lx)
+ tstRTR0MemUserKernel_LIBS += $(PATH_LIB)/SUPR0$(VBOX_SUFF_LIB)
+endif
+tstRTR0MemUserKernelDriver_TEMPLATE = VBOXR3TSTEXE
+tstRTR0MemUserKernelDriver_SOURCES = tstRTR0MemUserKernelDriver.cpp
+
+
+tstRTR0SemMutex_TEMPLATE = VBoxR0
+tstRTR0SemMutex_INST = $(INST_TESTCASE)
+tstRTR0SemMutex_DEFS = IN_RT_R0
+tstRTR0SemMutex_SYSSUFF = .r0
+tstRTR0SemMutex_SOURCES = tstRTR0SemMutex.cpp
+tstRTR0SemMutex_LIBS = $(PATH_LIB)/RuntimeR0$(VBOX_SUFF_LIB)
+if1of ($(VBOX_LDR_FMT), pe lx)
+ tstRTR0SemMutex_LIBS += $(PATH_LIB)/SUPR0$(VBOX_SUFF_LIB)
+endif
+tstRTR0SemMutexDriver_TEMPLATE = VBOXR3TSTEXE
+tstRTR0SemMutexDriver_SOURCES = tstRTR0SemMutexDriver.cpp
+
+
+tstRTR0Timer_TEMPLATE = VBoxR0
+tstRTR0Timer_INST = $(INST_TESTCASE)
+tstRTR0Timer_DEFS = IN_RT_R0
+tstRTR0Timer_SYSSUFF = .r0
+tstRTR0Timer_SOURCES = tstRTR0Timer.cpp
+tstRTR0Timer_LIBS = $(PATH_LIB)/RuntimeR0$(VBOX_SUFF_LIB)
+if1of ($(VBOX_LDR_FMT), pe lx)
+ tstRTR0Timer_LIBS += $(PATH_LIB)/SUPR0$(VBOX_SUFF_LIB)
+endif
+tstRTR0TimerDriver_TEMPLATE = VBOXR3TSTEXE
+tstRTR0TimerDriver_SOURCES = tstRTR0TimerDriver.cpp
+
+
 tstR0ThreadPreemption_TEMPLATE = VBoxR0
 tstR0ThreadPreemption_INST = $(INST_TESTCASE)
@@ -400,105 +517,10 @@
  tstR0ThreadPreemption_LIBS += $(PATH_LIB)/SUPR0$(VBOX_SUFF_LIB)
 endif
-
 tstR0ThreadPreemptionDriver_TEMPLATE = VBOXR3TSTEXE
 tstR0ThreadPreemptionDriver_SOURCES = tstR0ThreadPreemptionDriver.cpp
 
-tstRTR0SemMutex_TEMPLATE = VBoxR0
-tstRTR0SemMutex_INST = $(INST_TESTCASE)
-tstRTR0SemMutex_DEFS = IN_RT_R0
-tstRTR0SemMutex_SYSSUFF = .r0
-tstRTR0SemMutex_SOURCES = tstRTR0SemMutex.cpp
-tstRTR0SemMutex_LIBS = $(PATH_LIB)/RuntimeR0$(VBOX_SUFF_LIB)
-if1of ($(VBOX_LDR_FMT), pe lx)
- tstRTR0SemMutex_LIBS += $(PATH_LIB)/SUPR0$(VBOX_SUFF_LIB)
-endif
-
-tstRTR0SemMutexDriver_TEMPLATE = VBOXR3TSTEXE
-tstRTR0SemMutexDriver_SOURCES = tstRTR0SemMutexDriver.cpp
-
-tstRTFsQueries_SOURCES = tstRTFsQueries.cpp
-
-tstRTProcCreateEx_TEMPLATE = VBOXR3TSTEXE
-tstRTProcCreateEx_SOURCES = tstRTProcCreateEx.cpp
-
-tstRTProcWait_SOURCES = tstRTProcWait.cpp
-
-tstRTProcIsRunningByName_SOURCES = tstRTProcIsRunningByName.cpp
-
-tstRTS3_SOURCES = tstRTS3.cpp
-
-tstSemMutex_SOURCES = tstSemMutex.cpp
-
-tstSemEvent_SOURCES = tstSemEvent.cpp
-
-tstRTSemRW_TEMPLATE = VBOXR3TSTEXE
-tstRTSemRW_SOURCES = tstRTSemRW.cpp
-
-tstSemPingPong_SOURCES = tstSemPingPong.cpp
-
-tstSems_SOURCES = tstSems.cpp
-
-tstRTSemXRoads_TEMPLATE = VBOXR3TSTEXE
-tstRTSemXRoads_SOURCES = tstRTSemXRoads.cpp
-
-tstRTSort_TEMPLATE = VBOXR3TSTEXE
-tstRTSort_SOURCES = tstRTSort.cpp
-
-tstRTStrAlloc_TEMPLATE = VBOXR3TSTEXE
-tstRTStrAlloc_SOURCES = tstRTStrAlloc.cpp
-
-tstRTStrCache_TEMPLATE = VBOXR3TSTEXE
-tstRTStrCache_SOURCES = tstRTStrCache.cpp
-
-tstRTStrFormat_SOURCES = tstRTStrFormat.cpp
-
-tstStrSimplePattern_SOURCES = tstStrSimplePattern.cpp
-
-tstStrToNum_SOURCES = tstStrToNum.cpp
-
-tstRTStrVersion_TEMPLATE = VBOXR3TSTEXE
-tstRTStrVersion_SOURCES = tstRTStrVersion.cpp
-
-tstRTSystemQueryDmi_TEMPLATE = VBOXR3TSTEXE
-tstRTSystemQueryDmi_SOURCES = tstRTSystemQueryDmi.cpp
-
-tstRTSystemQueryOsInfo_TEMPLATE = VBOXR3TSTEXE
-tstRTSystemQueryOsInfo_SOURCES = tstRTSystemQueryOsInfo.cpp
-
-tstRTTemp_TEMPLATE = VBOXR3TSTEXE
-tstRTTemp_SOURCES = tstRTTemp.cpp
-
-tstTermCallbacks_SOURCES = tstTermCallbacks.cpp
-
-tstThread-1_SOURCES = tstThread-1.cpp
-
-tstTime_SOURCES = tstTime.cpp
-
-tstTime-2_SOURCES = tstTime-2.cpp
-
-tstTime-3_SOURCES = tstTime-3.cpp
-
-tstTime-4_SOURCES = tstTime-4.cpp
-
-tstTimer_SOURCES = tstTimer.cpp
-
-tstTimerLR_SOURCES = tstTimerLR.cpp
-
-tstRTTimeSpec_TEMPLATE = VBOXR3TSTEXE
-tstRTTimeSpec_SOURCES = tstRTTimeSpec.cpp
-
-tstTSC_SOURCES = tstTSC.cpp
-tstTSC_CXXFLAGS.linux += -O3
-
-tstRTUuid_TEMPLATE = VBOXR3TSTEXE
-tstRTUuid_SOURCES = tstRTUuid.cpp
-
-tstUtf8_SOURCES = tstUtf8.cpp
-
-tstRTCoreDump_TEMPLACE = VBOXR3TSTEXE
-tstRTCoreDump_SOURCES = tstRTCoreDump.cpp
-
-#
-# odds and ends
+
+#
+# Odds and ends.
 #
 
Index: /trunk/src/VBox/Runtime/testcase/tstRTR0Timer.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstRTR0Timer.cpp	(revision 32611)
+++ /trunk/src/VBox/Runtime/testcase/tstRTR0Timer.cpp	(revision 32611)
@@ -0,0 +1,159 @@
+/* $Id$ */
+/** @file
+ * IPRT R0 Testcase - Timers.
+ */
+
+/*
+ * Copyright (C) 2009-2010 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.
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <iprt/mem.h>
+
+#include <iprt/err.h>
+#include <iprt/param.h>
+#include <iprt/time.h>
+#include <iprt/string.h>
+#include <VBox/sup.h>
+#include "tstRTR0Timer.h"
+
+
+
+/**
+ * Service request callback function.
+ *
+ * @returns VBox status code.
+ * @param   pSession    The caller's session.
+ * @param   u64Arg      64-bit integer argument.
+ * @param   pReqHdr     The request header. Input / Output. Optional.
+ */
+DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOperation,
+                                          uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr)
+{
+    if (!VALID_PTR(pReqHdr))
+        return VERR_INVALID_PARAMETER;
+    char   *pszErr = (char *)(pReqHdr + 1);
+    size_t  cchErr = pReqHdr->cbReq - sizeof(*pReqHdr);
+    if (cchErr < 32 || cchErr >= 0x10000)
+        return VERR_INVALID_PARAMETER;
+    *pszErr = '\0';
+
+    if (u64Arg)
+        return VERR_INVALID_PARAMETER;
+
+    /*
+     * The big switch.
+     */
+    switch (uOperation)
+    {
+        case TSTRTR0TIMER_SANITY_OK:
+            break;
+
+        case TSTRTR0TIMER_SANITY_FAILURE:
+            RTStrPrintf(pszErr, cchErr, "!42failure42%1024s", "");
+            break;
+
+#if 0
+        case TSTRTR0TIMER_BASIC:
+        {
+            int rc = RTR0MemUserCopyFrom(pbKrnlBuf, R3Ptr, PAGE_SIZE);
+            if (rc == VINF_SUCCESS)
+            {
+                rc = RTR0MemUserCopyTo(R3Ptr, pbKrnlBuf, PAGE_SIZE);
+                if (rc == VINF_SUCCESS)
+                {
+                    if (RTR0MemUserIsValidAddr(R3Ptr))
+                    {
+                        if (RTR0MemKernelIsValidAddr(pbKrnlBuf))
+                        {
+                            if (RTR0MemAreKrnlAndUsrDifferent())
+                            {
+                                RTStrPrintf(pszErr, cchErr, "RTR0MemAreKrnlAndUsrDifferent returns true");
+                                if (!RTR0MemUserIsValidAddr((uintptr_t)pbKrnlBuf))
+                                {
+                                    if (!RTR0MemKernelIsValidAddr((void *)R3Ptr))
+                                    {
+                                        /* done */
+                                    }
+                                    else
+                                        RTStrPrintf(pszErr, cchErr, "! #5 - RTR0MemKernelIsValidAddr -> true, expected false");
+                                }
+                                else
+                                    RTStrPrintf(pszErr, cchErr, "! #5 - RTR0MemUserIsValidAddr -> true, expected false");
+                            }
+                            else
+                                RTStrPrintf(pszErr, cchErr, "RTR0MemAreKrnlAndUsrDifferent returns false");
+                        }
+                        else
+                            RTStrPrintf(pszErr, cchErr, "! #4 - RTR0MemKernelIsValidAddr -> false, expected true");
+                    }
+                    else
+                        RTStrPrintf(pszErr, cchErr, "! #3 - RTR0MemUserIsValidAddr -> false, expected true");
+                }
+                else
+                    RTStrPrintf(pszErr, cchErr, "! #2 - RTR0MemUserCopyTo -> %Rrc expected %Rrc", rc, VINF_SUCCESS);
+            }
+            else
+                RTStrPrintf(pszErr, cchErr, "! #1 - RTR0MemUserCopyFrom -> %Rrc expected %Rrc", rc, VINF_SUCCESS);
+            break;
+        }
+
+        case TSTRTR0TIMER_GOOD:
+        {
+            for (unsigned off = 0; off < 16 && !*pszErr; off++)
+                for (unsigned cb = 0; cb < PAGE_SIZE - 16; cb++)
+                    TEST_OFF_SIZE(off, cb, VINF_SUCCESS);
+            break;
+        }
+
+        case TSTRTR0TIMER_BAD:
+        {
+            for (unsigned off = 0; off < 16 && !*pszErr; off++)
+                for (unsigned cb = 0; cb < PAGE_SIZE - 16; cb++)
+                    TEST_OFF_SIZE(off, cb, cb > 0 ? VERR_ACCESS_DENIED : VINF_SUCCESS);
+            break;
+        }
+
+        case TSTRTR0TIMER_INVALID_ADDRESS:
+        {
+            if (    !RTR0MemUserIsValidAddr(R3Ptr)
+                &&  RTR0MemKernelIsValidAddr((void *)R3Ptr))
+            {
+                for (unsigned off = 0; off < 16 && !*pszErr; off++)
+                    for (unsigned cb = 0; cb < PAGE_SIZE - 16; cb++)
+                        TEST_OFF_SIZE(off, cb, cb > 0 ? VERR_ACCESS_DENIED : VINF_SUCCESS); /* ... */
+            }
+            else
+                RTStrPrintf(pszErr, cchErr, "RTR0MemUserIsValidAddr returns true");
+            break;
+        }
+#endif
+
+        default:
+            RTStrPrintf(pszErr, cchErr, "!Unknown test #%d", uOperation);
+            break;
+    }
+
+    /* The error indicator is the '!' in the message buffer. */
+    return VINF_SUCCESS;
+}
+
Index: /trunk/src/VBox/Runtime/testcase/tstRTR0Timer.h
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstRTR0Timer.h	(revision 32611)
+++ /trunk/src/VBox/Runtime/testcase/tstRTR0Timer.h	(revision 32611)
@@ -0,0 +1,43 @@
+/* $Id$ */
+/** @file
+ * IPRT R0 Testcase - Timers, common header.
+ */
+
+/*
+ * Copyright (C) 2009-2010 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.
+ */
+
+#ifdef IN_RING0
+RT_C_DECLS_BEGIN
+DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOperation,
+                                          uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr);
+RT_C_DECLS_END
+#endif
+
+typedef enum TSTRTR0TIMER
+{
+    TSTRTR0TIMER_SANITY_OK = 1,
+    TSTRTR0TIMER_SANITY_FAILURE,
+    TSTRTR0TIMER_BASIC,
+    TSTRTR0TIMER_GOOD,
+    TSTRTR0TIMER_BAD,
+    TSTRTR0TIMER_INVALID_ADDRESS
+} TSTRTR0TIMER;
+
Index: /trunk/src/VBox/Runtime/testcase/tstRTR0TimerDriver.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstRTR0TimerDriver.cpp	(revision 32611)
+++ /trunk/src/VBox/Runtime/testcase/tstRTR0TimerDriver.cpp	(revision 32611)
@@ -0,0 +1,203 @@
+/* $Id$ */
+/** @file
+ * IPRT R0 Testcase - Timers, driver program.
+ */
+
+/*
+ * Copyright (C) 2009-2010 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.
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <iprt/initterm.h>
+
+#include <iprt/err.h>
+#include <iprt/path.h>
+#include <iprt/param.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
+#include <iprt/test.h>
+#include <iprt/thread.h>
+#ifdef VBOX
+# include <VBox/sup.h>
+# include "tstRTR0Timer.h"
+#endif
+
+
+int main(int argc, char **argv)
+{
+#ifndef VBOX
+    RTPrintf("tstRTR0Timer: SKIPPED\n");
+    return RTEXITCODE_SKIPPED;
+#else
+    /*
+     * Init.
+     */
+    RTTEST hTest;
+    int rc = RTTestInitAndCreate("tstRTR0Timer", &hTest);
+    if (rc)
+        return rc;
+    RTTestBanner(hTest);
+
+    PSUPDRVSESSION pSession;
+    rc = SUPR3Init(&pSession);
+    if (RT_FAILURE(rc))
+    {
+        RTTestFailed(hTest, "SUPR3Init failed with rc=%Rrc\n", rc);
+        return RTTestSummaryAndDestroy(hTest);
+    }
+
+    char szPath[RTPATH_MAX];
+    rc = RTPathExecDir(szPath, sizeof(szPath));
+    if (RT_SUCCESS(rc))
+        rc = RTPathAppend(szPath, sizeof(szPath), "tstRTR0Timer.r0");
+    if (RT_FAILURE(rc))
+    {
+        RTTestFailed(hTest, "Failed constructing .r0 filename (rc=%Rrc)", rc);
+        return RTTestSummaryAndDestroy(hTest);
+    }
+
+    void *pvImageBase;
+    rc = SUPR3LoadServiceModule(szPath, "tstRTR0Timer", "TSTRTR0TimerSrvReqHandler", &pvImageBase);
+    if (RT_FAILURE(rc))
+    {
+        RTTestFailed(hTest, "SUPR3LoadServiceModule(%s,,,) failed with rc=%Rrc\n", szPath, rc);
+        return RTTestSummaryAndDestroy(hTest);
+    }
+
+    /* test request */
+    struct
+    {
+        SUPR0SERVICEREQHDR  Hdr;
+        char                szMsg[256];
+    } Req;
+
+    /*
+     * Sanity checks.
+     */
+    RTTestSub(hTest, "Sanity");
+    Req.Hdr.u32Magic = SUPR0SERVICEREQHDR_MAGIC;
+    Req.Hdr.cbReq = sizeof(Req);
+    Req.szMsg[0] = '\0';
+    RTTESTI_CHECK_RC(rc = SUPR3CallR0Service("tstRTR0Timer", sizeof("tstRTR0Timer") - 1,
+                                             TSTRTR0TIMER_SANITY_OK, 0, &Req.Hdr), VINF_SUCCESS);
+    if (RT_FAILURE(rc))
+        return RTTestSummaryAndDestroy(hTest);
+    RTTESTI_CHECK_MSG(Req.szMsg[0] == '\0', ("%s", Req.szMsg));
+    if (Req.szMsg[0] != '\0')
+        return RTTestSummaryAndDestroy(hTest);
+
+    Req.Hdr.u32Magic = SUPR0SERVICEREQHDR_MAGIC;
+    Req.Hdr.cbReq = sizeof(Req);
+    Req.szMsg[0] = '\0';
+    RTTESTI_CHECK_RC(rc = SUPR3CallR0Service("tstRTR0Timer", sizeof("tstRTR0Timer") - 1,
+                                             TSTRTR0TIMER_SANITY_FAILURE, 0, &Req.Hdr), VINF_SUCCESS);
+    if (RT_FAILURE(rc))
+        return RTTestSummaryAndDestroy(hTest);
+    RTTESTI_CHECK_MSG(!strncmp(Req.szMsg, "!42failure42", sizeof("!42failure42") - 1), ("%s", Req.szMsg));
+    if (strncmp(Req.szMsg, "!42failure42", sizeof("!42failure42") - 1))
+        return RTTestSummaryAndDestroy(hTest);
+
+#if 0
+    /*
+     * Basic tests, bail out on failure.
+     */
+    RTTestSub(hTest, "Basics");
+    Req.Hdr.u32Magic = SUPR0SERVICEREQHDR_MAGIC;
+    Req.Hdr.cbReq = sizeof(Req);
+    Req.szMsg[0] = '\0';
+    RTTESTI_CHECK_RC(rc = SUPR3CallR0Service("tstRTR0Timer", sizeof("tstRTR0Timer") - 1,
+                                             TSTRTR0TIMER_BASIC, (uintptr_t)pbPage, &Req.Hdr), VINF_SUCCESS);
+    if (RT_FAILURE(rc))
+        return RTTestSummaryAndDestroy(hTest);
+    if (Req.szMsg[0] == '!')
+    {
+        RTTestIFailed("%s", &Req.szMsg[1]);
+        return RTTestSummaryAndDestroy(hTest);
+    }
+    if (Req.szMsg[0])
+        RTTestIPrintf(RTTESTLVL_ALWAYS, "%s", Req.szMsg);
+
+    /*
+     * Good buffer, bail out on failure.
+     */
+    RTTestSub(hTest, "Good buffer");
+    Req.Hdr.u32Magic = SUPR0SERVICEREQHDR_MAGIC;
+    Req.Hdr.cbReq = sizeof(Req);
+    Req.szMsg[0] = '\0';
+    RTTESTI_CHECK_RC(rc = SUPR3CallR0Service("tstRTR0Timer", sizeof("tstRTR0Timer") - 1,
+                                             TSTRTR0TIMER_GOOD, (uintptr_t)pbPage, &Req.Hdr), VINF_SUCCESS);
+    if (RT_FAILURE(rc))
+        return RTTestSummaryAndDestroy(hTest);
+    if (Req.szMsg[0] == '!')
+    {
+        RTTestIFailed("%s", &Req.szMsg[1]);
+        return RTTestSummaryAndDestroy(hTest);
+    }
+    if (Req.szMsg[0])
+        RTTestIPrintf(RTTESTLVL_ALWAYS, "%s", Req.szMsg);
+
+    /*
+     * Bad buffer, bail out on failure.
+     */
+    RTTestSub(hTest, "Bad buffer");
+    Req.Hdr.u32Magic = SUPR0SERVICEREQHDR_MAGIC;
+    Req.Hdr.cbReq = sizeof(Req);
+    Req.szMsg[0] = '\0';
+    RTTESTI_CHECK_RC(rc = SUPR3CallR0Service("tstRTR0Timer", sizeof("tstRTR0Timer") - 1,
+                                             TSTRTR0TIMER_BAD, (uintptr_t)pbPage + PAGE_SIZE, &Req.Hdr), VINF_SUCCESS);
+    if (RT_FAILURE(rc))
+        return RTTestSummaryAndDestroy(hTest);
+    if (Req.szMsg[0] == '!')
+    {
+        RTTestIFailed("%s", &Req.szMsg[1]);
+        return RTTestSummaryAndDestroy(hTest);
+    }
+    if (Req.szMsg[0])
+        RTTestIPrintf(RTTESTLVL_ALWAYS, "%s", Req.szMsg);
+
+    /*
+     * Bad buffer, bail out on failure.
+     */
+    RTTestSub(hTest, "Kernel buffer");
+    Req.Hdr.u32Magic = SUPR0SERVICEREQHDR_MAGIC;
+    Req.Hdr.cbReq = sizeof(Req);
+    Req.szMsg[0] = '\0';
+    RTTESTI_CHECK_RC(rc = SUPR3CallR0Service("tstRTR0Timer", sizeof("tstRTR0Timer") - 1,
+                                             TSTRTR0TIMER_INVALID_ADDRESS, (uintptr_t)pvImageBase, &Req.Hdr), VINF_SUCCESS);
+    if (RT_FAILURE(rc))
+        return RTTestSummaryAndDestroy(hTest);
+    if (Req.szMsg[0] == '!')
+    {
+        RTTestIFailed("%s", &Req.szMsg[1]);
+        return RTTestSummaryAndDestroy(hTest);
+    }
+    if (Req.szMsg[0])
+        RTTestIPrintf(RTTESTLVL_ALWAYS, "%s", Req.szMsg);
+# endif
+
+    /*
+     * Done.
+     */
+    return RTTestSummaryAndDestroy(hTest);
+#endif
+}
+
