Index: /trunk/include/iprt/time.h
===================================================================
--- /trunk/include/iprt/time.h	(revision 5455)
+++ /trunk/include/iprt/time.h	(revision 5456)
@@ -684,7 +684,86 @@
  * Debugging the time api.
  *
- * @returns the number of 1ns steps which has been applied by rtTimeNanoTSInternal().
- */
-RTDECL(uint32_t) RTTime1nsSteps(void);
+ * @returns the number of 1ns steps which has been applied by RTTimeNanoTS().
+ */
+RTDECL(uint32_t) RTTimeDbgSteps(void);
+
+/**
+ * Debugging the time api.
+ *
+ * @returns the number of times the TSC interval expired RTTimeNanoTS().
+ */
+RTDECL(uint32_t) RTTimeDbgExpired(void);
+
+/**
+ * Debugging the time api.
+ *
+ * @returns the number of bad previous values encountered by RTTimeNanoTS().
+ */
+RTDECL(uint32_t) RTTimeDbgBad(void);
+
+/**
+ * Debugging the time api.
+ *
+ * @returns the number of update races in RTTimeNanoTS().
+ */
+RTDECL(uint32_t) RTTimeDbgRaces(void);
+
+/** @name RTTimeNanoTS GIP worker functions, for TM.
+ * @{ */
+/** Pointer to a RTTIMENANOTSDATA structure. */
+typedef struct RTTIMENANOTSDATA *PRTTIMENANOTSDATA;
+
+/**
+ * Nanosecond timestamp data.
+ *
+ * This is used to keep track of statistics and callback so IPRT
+ * and TM (VirtualBox) can share code.
+ *
+ * @remark Keep this in sync with the assembly version in timesupA.asm.
+ */
+typedef struct RTTIMENANOTSDATA
+{
+    /** Where the previous timestamp is stored.
+     * This is maintained to ensure that time doesn't go backwards or anything. */
+    uint64_t volatile   u64Prev;
+    /** Number of 1ns steps because of overshooting the period. */
+    uint32_t            c1nsSteps;
+    /** The number of times the interval expired (overflow). */
+    uint32_t            cExpired;
+    /** Number of "bad" previous values. */
+    uint32_t            cBadPrev;
+    /** The number of update races. */
+    uint32_t            cUpdateRaces;
+
+    /**
+     * Helper function that's used by the assembly routines when something goes bust.
+     *
+     * @param   pData           Pointer to this structure.
+     * @param   u64NanoTS       The calculated nano ts.
+     * @param   u64DeltaPrev    The delta relative to the previously returned timestamp.
+     * @param   u64PrevNanoTS   The previously returned timestamp (as it was read it).
+     */
+    DECLCALLBACKMEMBER(void, pfnBad)(PRTTIMENANOTSDATA pData, uint64_t u64NanoTS, uint64_t u64DeltaPrev, uint64_t u64PrevNanoTS);
+
+    /**
+     * Callback for when rediscovery is required.
+     *
+     * @returns Nanosecond timestamp.
+     * @param   pData           Pointer to this structure.
+     */
+    DECLCALLBACKMEMBER(uint64_t, pfnRediscover)(PRTTIMENANOTSDATA pData);
+} RTTIMENANOTSDATA;
+
+/** Internal RTTimeNanoTS worker (assembly). */
+typedef DECLCALLBACK(uint64_t) FNTIMENANOTSINTERNAL(PRTTIMENANOTSDATA pData);
+/** Pointer to an internal RTTimeNanoTS worker (assembly). */
+typedef FNTIMENANOTSINTERNAL *PFNTIMENANOTSINTERNAL;
+
+RTDECL(uint64_t) RTTimeNanoTSLegacySync(PRTTIMENANOTSDATA pData);
+RTDECL(uint64_t) RTTimeNanoTSLegacyAsync(PRTTIMENANOTSDATA pData);
+RTDECL(uint64_t) RTTimeNanoTSLFenceSync(PRTTIMENANOTSDATA pData);
+RTDECL(uint64_t) RTTimeNanoTSLFenceAsync(PRTTIMENANOTSDATA pData);
+/** @} */
+
 
 /**
Index: /trunk/src/VBox/Runtime/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Runtime/Makefile.kmk	(revision 5455)
+++ /trunk/src/VBox/Runtime/Makefile.kmk	(revision 5456)
@@ -189,4 +189,5 @@
 	common/time/time.cpp \
 	common/time/timeprog.cpp \
+	common/time/timesup.cpp \
 	generic/critsect-generic.cpp \
 	generic/env-generic.cpp \
@@ -206,5 +207,11 @@
 	r3/process.cpp \
 	r3/stream.cpp \
-	r3/tcp.cpp \
+	r3/tcp.cpp
+
+#if1of ($(BUILD_TARGET_ARCH),amd64 x86)
+# RuntimeR3_SOURCES += common/time/timesupA.asm
+#else
+ RuntimeR3_SOURCES += common/time/timesupref.cpp
+#endif
 
 ifdef IPRT_WITH_KLDR
@@ -235,5 +242,4 @@
 
 RuntimeR3_SOURCES.win = \
-	common/time/timesup.cpp \
 	generic/rand-stubs-generic.cpp \
 	generic/RTDirQueryInfo-generic.cpp \
@@ -267,5 +273,4 @@
 
 RuntimeR3_SOURCES.linux = \
-	common/time/timesup.cpp \
 	generic/pathhost-generic.cpp \
 	generic/RTDirQueryInfo-generic.cpp \
@@ -302,5 +307,4 @@
 
 RuntimeR3_SOURCES.os2   = \
-	common/time/timesup.cpp \
 	generic/pathhost-generic.cpp \
 	generic/rand-stubs-generic.cpp \
@@ -336,5 +340,4 @@
 
 RuntimeR3_SOURCES.darwin = \
-	common/time/timesup.cpp \
 	darwin/RTErrConvertFromDarwinCOM.cpp \
 	darwin/RTErrConvertFromDarwinIO.cpp \
@@ -370,5 +373,4 @@
 ## @todo Make BSD sched.
 RuntimeR3_SOURCES.freebsd = \
-	common/time/timesup.cpp \
 	generic/pathhost-generic.cpp \
 	generic/RTDirQueryInfo-generic.cpp \
@@ -401,5 +403,4 @@
 
 RuntimeR3_SOURCES.solaris = \
-	common/time/timesup.cpp \
 	generic/pathhost-generic.cpp \
 	generic/RTDirQueryInfo-generic.cpp \
@@ -446,5 +447,4 @@
 
 RuntimeR3L4_SOURCES = \
-	common/time/timesup.cpp \
 	generic/fs-stubs-generic.cpp \
 	generic/pathhost-generic.cpp \
@@ -680,4 +680,10 @@
 	VBox/strformat-vbox.cpp
 
+if1of ($(BUILD_TARGET_ARCH),amd64 x86)
+ RuntimeR0_SOURCES += common/time/timesupA.asm
+else
+ RuntimeR0_SOURCES += common/time/timesupref.cpp
+endif
+
 RuntimeR0_SOURCES.win.amd64 = $(RuntimeWin64ASM_SOURCES)
 
@@ -1004,6 +1010,12 @@
 	VBox/strformat-vbox.cpp \
 
+if1of ($(BUILD_TARGET_ARCH),amd64 x86)
+ RuntimeGC_SOURCES += common/time/timesupA.asm
+else
+ RuntimeGC_SOURCES += common/time/timesupref.cpp
+endif
+
 ifeq ($(VBOX_LDR_FMT32),lx)
-RuntimeGC_SOURCES += os2/sys0.asm
+ RuntimeGC_SOURCES += os2/sys0.asm
 endif
 
Index: /trunk/src/VBox/Runtime/common/time/timesup.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/time/timesup.cpp	(revision 5455)
+++ /trunk/src/VBox/Runtime/common/time/timesup.cpp	(revision 5456)
@@ -25,6 +25,20 @@
 #include <iprt/assert.h>
 #include <iprt/err.h>
-#include <VBox/sup.h>
+#include <iprt/log.h>
+#ifndef IN_GUEST
+# include <VBox/sup.h>
+# include <VBox/x86.h>
+#endif
 #include "internal/time.h"
+
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+#ifndef IN_GUEST
+static DECLCALLBACK(void)     rtTimeNanoTSInternalBitch(PRTTIMENANOTSDATA pData, uint64_t u64NanoTS, uint64_t u64DeltaPrev, uint64_t u64PrevNanoTS);
+static DECLCALLBACK(uint64_t) rtTimeNanoTSInternalFallback(PRTTIMENANOTSDATA pData);
+static DECLCALLBACK(uint64_t) rtTimeNanoTSInternalRediscover(PRTTIMENANOTSDATA pData);
+#endif
 
 
@@ -33,172 +47,115 @@
 *******************************************************************************/
 #ifndef IN_GUEST
-/** The previously returned nano TS.
- * This handles TSC drift on SMP systems and expired interval.
- * This is a valid range u64NanoTS to u64NanoTS + 1000000000 (ie. 1sec).
- */
-static uint64_t volatile    s_u64PrevNanoTS = 0;
-/**
- * Number of times we've had to resort to 1ns walking. */
-static uint32_t volatile    g_c1nsSteps = 0;
-#endif
-
-
-/**
- * Calculate NanoTS using the information in the global information page (GIP)
- * which the support library (SUPLib) exports.
- *
- * This function guarantees that the returned timestamp is later (in time) than
- * any previous calls in the same thread.
- *
- * @returns Nanosecond timestamp.
- *
- * @remark  The way the ever increasing time guarantee is currently implemented means
- *          that if you call this function at a freqency higher than 1GHz you're in for
- *          trouble. We currently assume that no idiot will do that for real life purposes.
- */
-DECLINLINE(uint64_t) rtTimeNanoTSInternal(void)
-{
-#ifndef IN_GUEST
-    uint64_t    u64Delta;
-    uint32_t    u32NanoTSFactor0;
-    uint64_t    u64TSC;
-    uint64_t    u64NanoTS;
-    uint32_t    u32UpdateIntervalTSC;
-    uint32_t    u32TransactionId;
-    PSUPGLOBALINFOPAGE pGip;
-
-    /*
-     * Read the data.
-     */
-    for (;;)
+/** The RTTimeNanoTS data structure that's passed down to the worker functions.  */
+static RTTIMENANOTSDATA g_TimeNanoTSData =
+{
+    /* .u64Prev       = */ 0,
+    /* .c1nsSteps     = */ 0,
+    /* .cExpired      = */ 0,
+    /* .cBadPrev      = */ 0,
+    /* .cUpdateRaces  = */ 0,
+    /* .pfnBad        = */ rtTimeNanoTSInternalBitch,
+    /* .pfnRediscover = */ rtTimeNanoTSInternalRediscover
+};
+
+/** The index into g_apfnWorkers for the function to use.
+ * This cannot be a pointer because that'll break down in GC due to code relocation. */
+static uint32_t             g_iWorker = 0;
+/** Array of rtTimeNanoTSInternal worker functions.
+ * This array is indexed by g_iWorker. */
+static const PFNTIMENANOTSINTERNAL g_apfnWorkers[] =
+{
+#define RTTIMENANO_WORKER_DETECT        0
+    rtTimeNanoTSInternalRediscover,
+#define RTTIMENANO_WORKER_SYNC_CPUID    1
+    RTTimeNanoTSLegacySync,
+#define RTTIMENANO_WORKER_ASYNC_CPUID   2
+    RTTimeNanoTSLegacyAsync,
+#define RTTIMENANO_WORKER_SYNC_LFENCE   3
+    RTTimeNanoTSLFenceSync,
+#define RTTIMENANO_WORKER_ASYNC_LFENCE  4
+    RTTimeNanoTSLFenceAsync,
+#define RTTIMENANO_WORKER_FALLBACK      5
+    rtTimeNanoTSInternalFallback,
+};
+
+
+/**
+ * Helper function that's used by the assembly routines when something goes bust.
+ *
+ * @param   pData           Pointer to the data structure.
+ * @param   u64NanoTS       The calculated nano ts.
+ * @param   u64DeltaPrev    The delta relative to the previously returned timestamp.
+ * @param   u64PrevNanoTS   The previously returned timestamp (as it was read it).
+ */
+static DECLCALLBACK(void) rtTimeNanoTSInternalBitch(PRTTIMENANOTSDATA pData, uint64_t u64NanoTS, uint64_t u64DeltaPrev, uint64_t u64PrevNanoTS)
+{
+    pData->cBadPrev++;
+    if ((int64_t)u64DeltaPrev < 0)
+        LogRel(("TM: u64DeltaPrev=%RI64 u64PrevNanoTS=0x%016RX64 u64NanoTS=0x%016RX64\n",
+                u64DeltaPrev, u64PrevNanoTS, u64NanoTS));
+    else
+        Log(("TM: u64DeltaPrev=%RI64 u64PrevNanoTS=0x%016RX64 u64NanoTS=0x%016RX64 (debugging?)\n",
+             u64DeltaPrev, u64PrevNanoTS, u64NanoTS));
+}
+
+/**
+ * Fallback function.
+ */
+static DECLCALLBACK(uint64_t) rtTimeNanoTSInternalFallback(PRTTIMENANOTSDATA pData)
+{
+    PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage;
+    if (    pGip
+        &&  pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC
+        &&  (   pGip->u32Mode == SUPGIPMODE_SYNC_TSC
+             || pGip->u32Mode == SUPGIPMODE_ASYNC_TSC))
+        return rtTimeNanoTSInternalRediscover(pData);
+    NOREF(pData);
+    return RTTimeSystemNanoTS();
+}
+
+
+/**
+ * Called the first time somebody asks for the time or when the GIP
+ * is mapped/unmapped.
+ */
+static DECLCALLBACK(uint64_t) rtTimeNanoTSInternalRediscover(PRTTIMENANOTSDATA pData)
+{
+    uint32_t iWorker;
+    PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage;
+    if (    pGip
+        &&  pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC
+        &&  (   pGip->u32Mode == SUPGIPMODE_SYNC_TSC
+             || pGip->u32Mode == SUPGIPMODE_ASYNC_TSC))
     {
-        pGip = g_pSUPGlobalInfoPage;
-#ifdef IN_RING3
-        if (!pGip || pGip->u32Magic != SUPGLOBALINFOPAGE_MAGIC)
-            return RTTimeSystemNanoTS();
-#endif
-
-        if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
-        {
-            u32TransactionId = pGip->aCPUs[0].u32TransactionId;
-#ifdef RT_OS_L4
-            Assert((u32TransactionId & 1) == 0);
-#endif
-            u32UpdateIntervalTSC = pGip->aCPUs[0].u32UpdateIntervalTSC;
-            u64NanoTS = pGip->aCPUs[0].u64NanoTS;
-            u64TSC = pGip->aCPUs[0].u64TSC;
-            u32NanoTSFactor0 = pGip->u32UpdateIntervalNS;
-            u64Delta = ASMReadTSC();
-            if (RT_UNLIKELY(    pGip->aCPUs[0].u32TransactionId != u32TransactionId
-                            ||  (u32TransactionId & 1)))
-                continue;
-        }
+        if (ASMCpuId_EDX(1) & X86_CPUID_FEATURE_EDX_SSE2)
+            iWorker = pGip->u32Mode == SUPGIPMODE_SYNC_TSC
+                    ? RTTIMENANO_WORKER_SYNC_LFENCE
+                    : RTTIMENANO_WORKER_ASYNC_LFENCE;
         else
-        {
-            /* SUPGIPMODE_ASYNC_TSC */
-            PSUPGIPCPU pGipCpu;
-
-            uint8_t u8ApicId = ASMGetApicId();
-            if (RT_LIKELY(u8ApicId < RT_ELEMENTS(pGip->aCPUs)))
-                pGipCpu = &pGip->aCPUs[u8ApicId];
-            else
-            {
-                AssertMsgFailed(("%x\n", u8ApicId));
-                pGipCpu = &pGip->aCPUs[0];
-            }
-
-            u32TransactionId = pGipCpu->u32TransactionId;
-#ifdef RT_OS_L4
-            Assert((u32TransactionId & 1) == 0);
-#endif
-            u32UpdateIntervalTSC = pGipCpu->u32UpdateIntervalTSC;
-            u64NanoTS = pGipCpu->u64NanoTS;
-            u64TSC = pGipCpu->u64TSC;
-            u32NanoTSFactor0 = pGip->u32UpdateIntervalNS;
-            u64Delta = ASMReadTSC();
-            if (RT_UNLIKELY(u8ApicId != ASMGetApicId()))
-                continue;
-            if (RT_UNLIKELY(    pGipCpu->u32TransactionId != u32TransactionId
-                            ||  (u32TransactionId & 1)))
-                continue;
-        }
-        break;
-    }
-
-    /*
-     * Calc NanoTS delta.
-     */
-    u64Delta -= u64TSC;
-    if (u64Delta > u32UpdateIntervalTSC)
-    {
-        /*
-         * We've expired the interval. Do 1ns per call until we've
-         * got valid TSC deltas again (s_u64PrevNanoTS takes care of this).
-         */
-        u64Delta = u32UpdateIntervalTSC;
-    }
-#if !defined(_MSC_VER) || defined(RT_ARCH_AMD64) /* GCC makes very pretty code from these two inline calls, while MSC cannot. */
-    u64Delta = ASMMult2xU32RetU64((uint32_t)u64Delta, u32NanoTSFactor0);
-    u64Delta = ASMDivU64ByU32RetU32(u64Delta, u32UpdateIntervalTSC);
-#else
-    __asm
-    {
-        mov     eax, dword ptr [u64Delta]
-        mul     dword ptr [u32NanoTSFactor0]
-        div     dword ptr [u32UpdateIntervalTSC]
-        mov     dword ptr [u64Delta], eax
-        xor     edx, edx
-        mov     dword ptr [u64Delta + 4], edx
-    }
-#endif
-
-    /*
-     * The most frequent case is that the delta is either too old
-     * or that our timestamp is higher (relative to u64NanoTS) than it.
-     */
-    uint64_t u64;
-    uint64_t u64PrevNanoTS = ASMAtomicReadU64(&s_u64PrevNanoTS);
-    uint64_t u64DeltaPrev = u64PrevNanoTS - u64NanoTS;
-    if (    u64DeltaPrev > 1000000000                       /* (invalid prev) */
-        ||  (uint32_t)u64DeltaPrev < (uint32_t)u64Delta)    /* (we're later) */
-    {
-        u64 = u64Delta + u64NanoTS;
-        if (ASMAtomicCmpXchgU64(&s_u64PrevNanoTS, u64, u64PrevNanoTS))
-            return u64;
+            iWorker = pGip->u32Mode == SUPGIPMODE_SYNC_TSC
+                    ? RTTIMENANO_WORKER_SYNC_CPUID
+                    : RTTIMENANO_WORKER_ASYNC_CPUID;
     }
     else
-    {
-        /*
-         * Our timestamp is lower than the last returned timestamp;
-         * advance 1ns beyond that.
-         */
-        u64Delta = u64DeltaPrev + 1;
-        u64 = u64Delta + u64NanoTS;
-        ASMAtomicIncU32(&g_c1nsSteps);
-    }
-
-    /*
-     * Attempt updating the previous value.
-     *      u64 == timestamp, u64Delta == delta relative to u64NanoTS.
-     */
-    for (int cTries = 100;;)
-    {
-        u64PrevNanoTS = ASMAtomicReadU64(&s_u64PrevNanoTS);
-        u64DeltaPrev = u64PrevNanoTS - u64NanoTS;
-        if (u64DeltaPrev > u64Delta)
-            break;
-        if (ASMAtomicCmpXchgU64(&s_u64PrevNanoTS, u64, u64PrevNanoTS))
-            break;
-        if (--cTries <= 0)
-        {
-            AssertBreakpoint(); /* (recursion) */
-            break;
-        }
-    }
-
-    return u64;
-#else /* IN_GUEST */
+        iWorker = RTTIMENANO_WORKER_FALLBACK;
+
+    ASMAtomicXchgU32((uint32_t volatile *)&g_iWorker, iWorker);
+    return g_apfnWorkers[iWorker](pData);
+}
+
+#endif /* !IN_GUEST */
+
+
+/**
+ * Internal worker for getting the current nanosecond timestamp.
+ */
+DECLINLINE(uint64_t) rtTimeNanoTSInternal(void)
+{
+#ifndef IN_GUEST
+    return g_apfnWorkers[g_iWorker](&g_TimeNanoTSData);
+#else
     return RTTimeSystemNanoTS();
-#endif /* IN_GUEST */
+#endif
 }
 
@@ -230,9 +187,42 @@
  * Debugging the time api.
  *
- * @returns the number of 1ns steps which has been applied by rtTimeNanoTSInternal().
- */
-RTDECL(uint32_t) RTTime1nsSteps(void)
-{
-    return g_c1nsSteps;
-}
-#endif
+ * @returns the number of 1ns steps which has been applied by RTTimeNanoTS().
+ */
+RTDECL(uint32_t) RTTimeDbgSteps(void)
+{
+    return g_TimeNanoTSData.c1nsSteps;
+}
+
+
+/**
+ * Debugging the time api.
+ *
+ * @returns the number of times the TSC interval expired RTTimeNanoTS().
+ */
+RTDECL(uint32_t) RTTimeDbgExpired(void)
+{
+    return g_TimeNanoTSData.cExpired;
+}
+
+
+/**
+ * Debugging the time api.
+ *
+ * @returns the number of bad previous values encountered by RTTimeNanoTS().
+ */
+RTDECL(uint32_t) RTTimeDbgBad(void)
+{
+    return g_TimeNanoTSData.cBadPrev;
+}
+
+
+/**
+ * Debugging the time api.
+ *
+ * @returns the number of update races in RTTimeNanoTS().
+ */
+RTDECL(uint32_t) RTTimeDbgRaces(void)
+{
+    return g_TimeNanoTSData.cUpdateRaces;
+}
+#endif
Index: /trunk/src/VBox/Runtime/common/time/timesupA.asm
===================================================================
--- /trunk/src/VBox/Runtime/common/time/timesupA.asm	(revision 5456)
+++ /trunk/src/VBox/Runtime/common/time/timesupA.asm	(revision 5456)
@@ -0,0 +1,78 @@
+; $Id$%ifndef IN_GUEST
+;; @file
+; innotek Portable Runtime - Time using SUPLib, the Assembly Implementation.
+;
+
+;
+; Copyright (C) 2006-2007 InnoTek Systemberatung GmbH
+;
+; 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 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 IN_GUEST
+
+%include "iprt/asmdefs.mac"
+%include "VBox/sup.mac"
+
+
+;; Keep this in sync with iprt/time.h.
+struc RTTIMENANOTSDATA
+    .u64Prev            resq 1
+    .c1nsSteps          resd 1
+    .cExpired           resd 1
+    .cBadPrev           resd 1
+    .cUpdateRaces       resd 1
+    .pfnBad             RTCCPTR_RES 1
+    .pfnRediscover      RTCCPTR_RES 1
+endstruc
+
+
+BEGINDATA
+extern NAME(g_pSUPGlobalInfoPage)
+
+BEGINCODE
+
+;
+; The default stuff that works everywhere.
+; Uses cpuid for serializing.
+;
+%undef  ASYNC_GIP
+%undef  USE_LFENCE
+%define NEED_TRANSACTION_ID
+%define NEED_TO_SAVE_REGS
+%define rtTimeNanoTSInternalAsm    RTTimeNanoTSLegacySync
+%include "timesupA.mac"
+
+%define ASYNC_GIP
+%ifdef IN_GC
+ %undef NEED_TRANSACTION_ID
+%endif
+%define rtTimeNanoTSInternalAsm    RTTimeNanoTSLegacyAsync
+%include "timesupA.mac"
+
+;
+; Alternative implementation that employs lfence instead of cpuid.
+;
+%undef  ASYNC_GIP
+%define USE_LFENCE
+%define NEED_TRANSACTION_ID
+%undef  NEED_TO_SAVE_REGS
+%define rtTimeNanoTSInternalAsm    RTTimeNanoTSLFenceSync
+%include "timesupA.mac"
+
+%define ASYNC_GIP
+;%ifdef IN_GC
+ %undef NEED_TRANSACTION_ID
+;%endif
+%define rtTimeNanoTSInternalAsm    RTTimeNanoTSLFenceAsync
+%include "timesupA.mac"
+
+
+%endif ; !IN_GUEST
Index: /trunk/src/VBox/Runtime/common/time/timesupA.mac
===================================================================
--- /trunk/src/VBox/Runtime/common/time/timesupA.mac	(revision 5456)
+++ /trunk/src/VBox/Runtime/common/time/timesupA.mac	(revision 5456)
@@ -0,0 +1,739 @@
+
+%ifdef RT_ARCH_X86
+;;
+; The x86 assembly implementation of the assembly routines.
+;
+; @returns Nanosecond timestamp.
+; @param   pData           Pointer to the nanosecond timestamp data.
+;
+BEGINPROC rtTimeNanoTSInternalAsm
+    ;
+    ; Variable definitions.
+    ;
+%define pData                   [ebp + 08h]
+%define u64RetNanoTS_Hi         [ebp - 04h]
+%define u64RetNanoTS            [ebp - 08h]
+%define u32UpdateIntervalNS     [ebp - 0ch]
+%define u32UpdateIntervalTSC    [ebp - 10h]
+%define u64TSC_Hi               [ebp - 14h]
+%define u64TSC                  [ebp - 18h]
+%define u64CurNanoTS_Hi         [ebp - 1ch]
+%define u64CurNanoTS            [ebp - 20h]
+%define u64PrevNanoTS_Hi        [ebp - 24h]
+%define u64PrevNanoTS           [ebp - 28h]
+%define u32TransactionId        [ebp - 2ch]
+%define u32ApicIdPlus           [ebp - 30h]
+%define TmpVar                  [ebp - 34h]
+%define SavedEBX                [ebp - 38h]
+%define SavedEDI                [ebp - 3ch]
+%define SavedESI                [ebp - 40h]
+
+    ;
+    ; Prolog.
+    ;
+    push    ebp
+    mov     ebp, esp
+    sub     esp, 40h
+    mov     SavedEBX, ebx
+    mov     SavedEDI, edi
+    mov     SavedESI, esi
+
+
+    ;;
+    ;; Read the GIP data and the previous value.
+    ;;
+.ReadGip:
+
+
+    ;
+    ; Load pGip and calc pGipCPU, setting u32ApicIdPlus if necessary.
+    ;
+    mov     esi, [NAME(g_pSUPGlobalInfoPage)]
+    or      esi, esi
+    jz      .Rediscover
+    cmp     dword [esi + SUPGLOBALINFOPAGE.u32Magic], SUPGLOBALINFOPAGE_MAGIC
+    jne     .Rediscover
+%ifdef ASYNC_GIP
+    ; u8ApicId = ASMGetApicId();
+    mov     eax, 1
+    cpuid                               ; expensive
+ %ifdef NEED_TRANSACTION_ID
+    mov     u32ApicIdPlus, ebx
+ %endif
+    ; pGipCpu = &pGip->aCPU[u8ApicId];
+    shr     ebx, 24
+    mov     eax, SUPGIPCPU_size
+    mul     ebx
+    lea     edi, [esi + eax + SUPGLOBALINFOPAGE.aCPUs]  ; edi == &pGip->aCPU[u8ApicId];
+%else
+    lea     edi, [esi + SUPGLOBALINFOPAGE.aCPUs]        ; edi == &pGip->aCPU[0];
+%endif
+
+%ifdef NEED_TRANSACTION_ID
+    ;
+    ; Serialized loading of u32TransactionId.
+    ;
+    mov     ebx, [edi + SUPGIPCPU.u32TransactionId]
+    mov     u32TransactionId, ebx
+ %ifdef USE_LFENCE
+    lfence
+ %else
+    lock xor dword TmpVar, 0
+ %endif
+%endif
+
+    ;
+    ; Load the data and TSC.
+    ;
+    mov     eax, [esi + SUPGLOBALINFOPAGE.u32UpdateIntervalNS]
+    mov     u32UpdateIntervalNS, eax    ; esi is now free
+    mov     edx, [edi + SUPGIPCPU.u32UpdateIntervalTSC]
+    mov     u32UpdateIntervalTSC, edx
+    rdtsc
+    mov     ecx, [edi + SUPGIPCPU.u64NanoTS]
+    mov     u64CurNanoTS, ecx
+    mov     esi, [edi + SUPGIPCPU.u64NanoTS + 4]
+    mov     u64CurNanoTS_Hi, esi
+    mov     ebx, [edi + SUPGIPCPU.u64TSC]
+    mov     u64TSC, ebx
+    mov     ecx, [edi + SUPGIPCPU.u64TSC + 4]
+    mov     u64TSC_Hi, ecx
+
+    ; u64PrevNanoTS = ASMAtomicReadU64(pu64Prev);
+    ;   This serializes load/save. And with the dependency on the
+    ;   RDTSC result, we try to make sure it has completed as well.
+    mov     esi, pData
+    mov     ebx, eax
+    mov     ecx, edx
+    lock cmpxchg8b [esi + RTTIMENANOTSDATA.u64Prev]
+    mov     u64PrevNanoTS, eax
+    mov     u64PrevNanoTS_Hi, edx
+
+%undef SAVED_u64RetNanoTS
+%ifdef NEED_TRANSACTION_ID
+    ;
+    ; Check that the GIP and CPU didn't change.
+    ; We've already serialized all the loads and stores at this point.
+    ;
+ %ifdef ASYNC_GIP
+    mov     u64RetNanoTS, ebx
+    mov     u64RetNanoTS_Hi, ecx
+  %define SAVED_u64RetNanoTS
+    mov     eax, 1
+    cpuid
+    cmp     u32ApicIdPlus, ebx
+    jne     .ReadGip
+ %endif
+    mov     esi, [edi + SUPGIPCPU.u32TransactionId]
+    cmp     esi, u32TransactionId
+    jne     .ReadGip
+    test    esi, 1
+    jnz     .ReadGip
+%endif ; NEED_TRANSACTION_ID
+%ifdef SAVED_u64RetNanoTS
+    mov     ebx, u64RetNanoTS
+    mov     ecx, u64RetNanoTS_Hi
+%endif
+
+    ;;
+    ;; Calc the timestamp.
+    ;;
+    ; u64RetNanoTS -= u64TSC;
+    sub     ebx, u64TSC
+    sbb     ecx, u64TSC_Hi
+
+    ; if (u64RetNanoTS > u32UpdateIntervalTSC) -> jump
+    or      ecx, ecx
+    jnz     .OverFlow
+    cmp     ebx, u32UpdateIntervalTSC
+    ja      .OverFlow
+    mov     eax, ebx
+.ContinueCalcs:                         ; eax <= u32UpdateIntervalTSC
+    mul     dword u32UpdateIntervalNS
+    div     dword u32UpdateIntervalTSC
+    xor     edx, edx
+
+    ; u64RetNanoTS += u64CurNanoTS;
+    add     eax, u64CurNanoTS
+    adc     edx, u64CurNanoTS_Hi
+
+    ;;
+    ;; Compare it with the previous one.
+    ;;
+    ; if (RT_LIKELY(   u64RetNanoTS > u64PrevNanoTS
+    ;               && u64RetNanoTS < u64PrevNanoTS + UINT64_C(86000000000000) /* 24h */))
+    ;; @todo optimize this compare (/me too tired).
+    mov     ecx, u64PrevNanoTS_Hi
+    mov     ebx, u64PrevNanoTS
+    cmp     edx, ecx
+    ja      .Compare2
+    jb      .DeltaPrevTooBig
+    cmp     eax, ebx
+    jbe     .DeltaPrevTooBig
+
+.Compare2:
+    add     ebx, 0x6F736000
+    adc     ecx, 0x00004E37
+    cmp     edx, ecx
+    jb      .CompareDone
+    ja      .DeltaPrevTooBig
+    cmp     eax, ebx
+    jae     .DeltaPrevTooBig
+.CompareDone:
+
+
+    ;;
+    ;; Update the previous value with the u64RetNanoTS value.
+    ;;
+.Update:
+    ; if (RT_LIKELY(ASMAtomicCmpXchgU64(&pData->u64Prev, u64RetNanoTS, u64PrevNanoTS)))
+    mov     ebx, eax
+    mov     ecx, edx
+    mov     esi, pData
+    mov     eax, u64PrevNanoTS
+    mov     edx, u64PrevNanoTS_Hi
+    lock cmpxchg8b [esi + RTTIMENANOTSDATA.u64Prev]
+    jnz     .UpdateFailed
+
+.Updated:
+    mov     eax, ebx
+    mov     edx, ecx
+
+.Done:
+    mov     esi, SavedESI
+    mov     edi, SavedEDI
+    mov     ebx, SavedEBX
+    leave
+    ret
+
+
+    ;;
+    ;; We've expired the interval, cap it. If we're here for the 2nd
+    ;; time without any GIP update inbetween, the checks against
+    ;; pData->u64Prev below will force 1ns stepping.
+    ;;
+.OverFlow:
+    ; u64Delta = u32UpdateIntervalTSC;
+    mov     esi, pData
+    inc     dword [esi + RTTIMENANOTSDATA.cExpired]
+    mov     eax, u32UpdateIntervalTSC
+    jmp     .ContinueCalcs
+
+
+    ;;
+    ;; u64DeltaPrev >= 24h
+    ;;
+    ;; eax:edx = u64RetNanoTS (to be adjusted)
+    ;;
+.DeltaPrevTooBig:
+    ; uint64_t u64DeltaPrev = u64RetNanoTS - u64PrevNanoTS;
+    mov     ebx, eax
+    sub     ebx, u64PrevNanoTS
+    mov     ecx, edx
+    sbb     ecx, u64PrevNanoTS_Hi       ; ebx:ecx = u64DeltaPrev
+
+    ; else if (   (int64_t)u64DeltaPrev <= 0
+    ;          && (int64_t)u64DeltaPrev + u32UpdateIntervalNS * 2 >= 0)
+    ; {
+    ;    /* Occasional - u64RetNanoTS is in the recent 'past' relative the previous call. */
+    ;     pData->c1nsSteps++;
+    ;     u64RetNanoTS = u64PrevNanoTS + 1;
+    ; }
+    mov     esi, u32UpdateIntervalNS
+    cmp     ecx, 0
+    jl      .PrevNotZero2ndTest
+    jg      .DeltaPrevNotInRecentPast
+    cmp     ebx, 0
+    ja      .DeltaPrevNotInRecentPast
+
+.PrevNotZero2ndTest:
+    add     esi, esi                    ; ASSUMES: u32UpdateIntervalNS * 2 <= 32-bit.
+    xor     edi, edi
+    add     esi, ebx
+    adc     edi, ecx
+    test    edi, edi
+    js      .DeltaPrevNotInRecentPast
+
+.DeltaPrevInRecentPast:
+    mov     esi, pData
+    inc     dword [esi + RTTIMENANOTSDATA.c1nsSteps]
+    mov     eax, u64PrevNanoTS
+    mov     edx, u64PrevNanoTS_Hi
+    add     eax, 1
+    adc     edx, 0
+    jmp     .Update
+
+.DeltaPrevNotInRecentPast:
+    ; else if (!u64PrevNanoTS) /* We're resuming (see TMVirtualResume). */
+    ;     /* do nothing */;
+    cmp     dword u64PrevNanoTS, 0
+    jne     .DeltaPrevNotZero
+    cmp     dword u64PrevNanoTS_Hi, 0
+    jne     .DeltaPrevNotZero
+    jmp     .Update
+
+.DeltaPrevNotZero:
+    ; else
+    ; {
+    ;     /* Something has gone bust, if negative offset it's real bad. */
+    ;     rtTimeNanoTSInternalBitch(pVM,
+    ; }
+
+    ; call C function that does the bitching.
+    mov     u64RetNanoTS, eax
+    mov     u64RetNanoTS_Hi, edx
+
+    mov     edi, u64PrevNanoTS_Hi
+    mov     esi, u64PrevNanoTS
+    push    edi
+    push    esi                         ; 4 - u64PrevNanoTS
+    push    ecx
+    push    ebx                         ; 3 - u64DeltaPrev
+    push    edx
+    push    eax                         ; 2 - u64RetNanoTS
+    mov     eax, pData
+    push    eax                         ; 1 - pData
+    call    dword [eax + RTTIMENANOTSDATA.pfnBad]
+    add     esp, 4*7
+
+    mov     eax, u64RetNanoTS
+    mov     edx, u64RetNanoTS_Hi
+    jmp     .Update
+
+
+    ;;
+    ;; Attempt updating the previous value, provided we're still ahead of it.
+    ;;
+    ;; There is no point in recalculating u64NanoTS because we got preemted or if
+    ;; we raced somebody while the GIP was updated, since these are events
+    ;; that might occure at any point in the return path as well.
+    ;;
+    ;; eax:edx = *pData->u64Prev
+    ;; ebx:ecx = u64RetNanoTS
+    ;;
+    ALIGNCODE(16)
+.UpdateFailed:
+    mov     edi, pData
+    lock inc dword [edi + RTTIMENANOTSDATA.cUpdateRaces]
+    ; for (i = 0; i < 10; i++)
+    mov     edi, 10
+.UpdateLoop:
+    ; if (u64PrevNanoTS >= u64NanoTS)
+    ;     break;
+    cmp     edx, ecx
+    jg      .Updated
+    jne     .UpdateLoopLess
+    cmp     eax, ebx
+    jae     .Updated
+.UpdateLoopLess:
+    ; retry
+    lock cmpxchg8b [esi]
+    jz      .Updated
+    dec     edi
+    jnz     .UpdateLoop
+    jmp     .Updated
+
+
+    ;;
+    ;; The GIP is seemingly invalid, redo the discovery.
+    ;;
+.Rediscover:
+    mov     eax, pData
+    push    eax
+    call    [eax + RTTIMENANOTSDATA.pfnRediscover]
+    add     esp, 4h
+    jmp     .Done
+
+    ;
+    ; Cleanup variables
+    ;
+%undef pData
+%undef u64Delta_Hi
+%undef u64Delta
+%undef u32UpdateIntervalNS
+%undef u32UpdateIntervalTSC
+%undef u64TSC_Hi
+%undef u64TSC
+%undef u64NanoTS_Hi
+%undef u64NanoTS
+%undef u64PrevNanoTS_Hi
+%undef u64PrevNanoTS
+%undef u32TransactionId
+%undef u8ApicId
+
+%else ; AMD64
+
+;;
+; The AMD64 assembly implementation of the assembly routines.
+;
+; @returns Nanosecond timestamp.
+; @param   pData    gcc:rdi  msc:rcx    Pointer to the nanosecond timestamp data.
+;
+BEGINPROC rtTimeNanoTSInternalAsm
+    ;
+    ; Define variables and stack frame.
+    ;
+%define SavedRBX                [rbp - 08h]
+%define SavedR12                [rbp - 10h]
+%define SavedR13                [rbp - 18h]
+%define SavedRDI                [rbp - 20h]
+%define SavedRSI                [rbp - 28h]
+%define TmpVar                  [rbp - 30h]
+%define TmpVar2                 [rbp - 38h]
+%ifdef NEED_TRANSACTION_ID
+ %ifdef ASYNC_GIP
+  %define SavedR14              [rbp - 40h]
+  %define SavedR15              [rbp - 48h]
+ %endif
+%endif
+
+%define pData                   rdi
+
+%define u64TSC                  rsi
+%define pGip                    rsi
+%define pGipCPU                 r8
+%define u32TransactionId        r9d
+%define u64CurNanoTS            r10
+%define u64PrevNanoTS           r11     ; not parameter register
+%define u32UpdateIntervalTSC    r12d
+%define u32UpdateIntervalTSC_64 r12
+%define u32UpdateIntervalNS     r13d
+%define u32UpdateIntervalNS_64  r13
+%undef u64SavedRetNanoTS
+%undef u32ApicIdPlus
+%ifdef NEED_TRANSACTION_ID
+ %ifdef ASYNC_GIP
+  %define u64SavedRetNanoTS     r14
+  %define u32ApicIdPlus         r15d
+ %endif
+%endif
+
+    ;
+    ; The prolog.
+    ;
+    push    rbp
+    mov     rbp, rsp
+%ifdef ASM_CALL64_MSC
+    sub     rsp, 50h+20h
+%else
+    sub     rsp, 50h
+%endif
+    mov     SavedRBX, rbx
+    mov     SavedR12, r12
+    mov     SavedR13, r13
+%ifdef ASM_CALL64_MSC
+    mov     SavedRDI, rdi
+    mov     SavedRSI, rsi
+    mov     pData, rcx
+%else
+    ;mov     pData, rdi - already in rdi.
+%endif
+%ifdef SavedR14
+    mov     SavedR14, r14
+%endif
+%ifdef SavedR15
+    mov     SavedR15, r15
+%endif
+
+
+    ;;
+    ;; Data fetch loop.
+    ;; We take great pain ensuring that data consitency here.
+    ;;
+.ReadGip:
+
+    ;
+    ; Load pGip and calc pGipCPU, setting u32ApicIdPlus if necessary.
+    ;
+%ifdef ASYNC_GIP
+    ; u8ApicId = ASMGetApicId();
+    mov     eax, 1
+    cpuid                               ; expensive
+ %ifdef NEED_TRANSACTION_ID
+    mov     u32ApicIdPlus, ebx
+ %endif
+    ; pGipCpu = &pGip->aCPU[u8ApicId];
+    shr     ebx, 24
+    mov     eax, SUPGIPCPU_size
+    mul     ebx
+    mov     pGip, [NAME(g_pSUPGlobalInfoPage) wrt rip]
+    lea     pGipCPU, [pGip + rax + SUPGLOBALINFOPAGE.aCPUs]
+;    lea     pGipCPU, [pGip + SUPGLOBALINFOPAGE.aCPUs]
+;    lea     pGipCPU, [pGipCPU + rax]
+%else
+    mov     pGip, [NAME(g_pSUPGlobalInfoPage) wrt rip]
+    lea     pGipCPU, [pGip + SUPGLOBALINFOPAGE.aCPUs]
+%endif
+    or      pGip, pGip
+    jz      .Rediscover
+    cmp     dword [pGip + SUPGLOBALINFOPAGE.u32Magic], SUPGLOBALINFOPAGE_MAGIC
+    jne     .Rediscover
+
+%ifdef NEED_TRANSACTION_ID
+    ;
+    ; Serialized loading of u32TransactionId.
+    ;
+    mov     u32TransactionId, [pGipCPU + SUPGIPCPU.u32TransactionId]
+ %ifdef USE_LFENCE
+    lfence
+ %else
+    lock xor dword TmpVar, 0
+ %endif
+%endif
+
+    ;
+    ; Load the data and TSC.
+    ;
+    mov     u32UpdateIntervalNS,  [pGip + SUPGLOBALINFOPAGE.u32UpdateIntervalNS] ; before u64TSC
+    mov     u32UpdateIntervalTSC, [pGipCPU + SUPGIPCPU.u32UpdateIntervalTSC]
+    rdtsc
+    mov     u64PrevNanoTS,        [pData + RTTIMENANOTSDATA.u64Prev]
+    shl     rdx, 32
+ %ifdef u64SavedRetNanoTS               ; doing this here saves a tick or so.
+    mov     u64SavedRetNanoTS, rax
+    or      u64SavedRetNanoTS, rdx
+ %else
+    or      rax, rdx                    ; rax is u64RetNanoTS.
+ %endif
+    mov     u64CurNanoTS,         [pGipCPU + SUPGIPCPU.u64NanoTS]
+    mov     u64TSC,               [pGipCPU + SUPGIPCPU.u64TSC]
+
+%ifdef NEED_TRANSACTION_ID
+    ;
+    ; Check that the GIP and CPU didn't change.
+    ;
+    ; It is crucial that the rdtsc instruction has completed before
+    ; we check the transaction id. The LOCK prefixed instruction with
+    ; dependency on the RDTSC result should do the trick, I think.
+    ; CPUID is serializing, so the async path is safe by default.
+    ;
+ %ifdef ASYNC_GIP
+    mov     eax, 1
+    cpuid
+    cmp     u32ApicIdPlus, ebx
+    jne     .ReadGip
+ %else
+    lock xor qword TmpVar, rax
+ %endif
+    cmp     u32TransactionId, [pGipCPU + SUPGIPCPU.u32TransactionId]
+    jne     .ReadGip
+    test    u32TransactionId, 1
+    jnz     .ReadGip
+ %ifdef u64SavedRetNanoTS
+    mov     rax, u64SavedRetNanoTS      ; rax is u64RetNanoTS.
+ %endif
+%endif ; NEED_TRANSACTION_ID
+
+
+    ;;
+    ;; Calc the timestamp.
+    ;;
+    ; u64RetNanoTS -= u64TSC;
+    sub     rax, u64TSC
+    xor     edx, edx
+
+    ; if (u64RetNanoTS > u32UpdateIntervalTSC) -> jump
+    cmp     rax, u32UpdateIntervalTSC_64
+    ja      .OverFlow
+.ContinueCalcs:                         ; edx = 0; eax <= u32UpdateIntervalTSC
+    mul     u32UpdateIntervalNS
+    div     u32UpdateIntervalTSC
+
+    ; u64RetNanoTS += u64CurNanoTS;
+    add     rax, u64CurNanoTS
+
+
+    ;;
+    ;; Compare it with the previous one.
+    ;;
+    ; if (RT_LIKELY(   u64RetNanoTS > u64PrevNanoTS
+    ;               && u64RetNanoTS < u64PrevNanoTS + UINT64_C(86000000000000) /* 24h */))
+    ;    /* Frequent - less than 24h since last call. */;
+    cmp     rax, u64PrevNanoTS
+    jbe     .DeltaPrevTooBig
+    mov     ecx, 5
+    shl     rcx, 44                     ; close enough
+    add     rcx, u64PrevNanoTS
+    cmp     rax, rcx
+    jae     .DeltaPrevTooBig
+
+
+    ;;
+    ;; Update the previous value.
+    ;;
+.Update:
+    ; if (RT_LIKELY(ASMAtomicCmpXchgU64(&pData->u64Prev, u64RetNanoTS, u64PrevNanoTS)))
+    mov     rcx, rax
+    mov     rax, u64PrevNanoTS
+    lock cmpxchg [pData + RTTIMENANOTSDATA.u64Prev], rcx
+    jnz     .UpdateFailed
+
+.Updated:
+    mov     rax, rcx
+
+.Done:
+    mov     rbx, SavedRBX
+    mov     r12, SavedR12
+    mov     r13, SavedR13
+%ifdef SavedR14
+    mov     r14, SavedR14
+%endif
+%ifdef SavedR15
+    mov     r15, SavedR15
+%endif
+%ifdef ASM_CALL64_MSC
+    mov     rdi, SavedRDI
+    mov     rsi, SavedRSI
+%endif
+    leave
+    ret
+
+
+    ;;
+    ;; We've expired the interval, cap it. If we're here for the 2nd
+    ;; time without any GIP update inbetween, the checks against
+    ;; pData->u64Prev below will force 1ns stepping.
+    ;;
+ALIGNCODE(16)
+.OverFlow:
+    ; u64RetNanoTS = u32UpdateIntervalTSC;
+    inc     dword [pData + RTTIMENANOTSDATA.cExpired]
+    mov     eax, u32UpdateIntervalTSC
+    jmp     .ContinueCalcs
+
+
+    ;;
+    ;; u64DeltaPrev >= 24h
+    ;;
+    ;; rax = u64RetNanoTS (to be adjusted)
+    ;;
+ALIGNCODE(16)
+.DeltaPrevTooBig:
+    ; uint64_t u64DeltaPrev = u64RetNanoTS - u64PrevNanoTS;
+    mov     rbx, rax
+    sub     rbx, u64PrevNanoTS
+
+    ; else if (   (int64_t)u64DeltaPrev <= 0
+    ;          && (int64_t)u64DeltaPrev + u32UpdateIntervalNS * 2 >= 0)
+    ; {
+    ;    /* Occasional - u64NanoTS is in the recent 'past' relative the previous call. */
+    ;     pData->c1nsSteps++;
+    ;     u64RetNanoTS = u64PrevNanoTS + 1;
+    ; }
+    test    rbx, rbx
+    jg      .DeltaPrevNotInRecentPast
+
+    lea     rdx, [u32UpdateIntervalNS_64 + u32UpdateIntervalNS_64]
+    add     rdx, rbx
+    js      .DeltaPrevNotInRecentPast
+
+    ; body
+    inc     dword [pData + RTTIMENANOTSDATA.c1nsSteps]
+    lea     rax, [u64PrevNanoTS + 1]
+    jmp     .Update
+
+    ; else if (!u64PrevNanoTS) /* We're resuming (see TMVirtualResume) / first call. */
+    ;     /* do nothing */;
+.DeltaPrevNotInRecentPast:
+    or      u64PrevNanoTS, u64PrevNanoTS
+    jz      .Update
+
+    ; else
+    ; {
+    ;     /* Something has gone bust, if negative offset it's real bad. */
+    ;     rtTimeNanoTSInternalBitch(pVM,
+    ; }
+
+    ; call C function that does the bitching.
+    mov     TmpVar, rax
+    mov     TmpVar2, pData
+
+%ifdef ASM_CALL64_MSC
+    mov     rcx, pData                  ; param 1 - pData
+    mov     rdx, rax                    ; param 2 - u64RetNanoTS
+    mov     r8, rbx                     ; param 3 - u64DeltaPrev
+    mov     r9, u64PrevNanoTS           ; param 4 - u64PrevNanoTS
+%else
+    ;mov     rdi, pData - already in rdi; param 1 - pData
+    mov     rsi, rax                    ; param 2 - u64RetNanoTS
+    mov     rdx, rbx                    ; param 3 - u64DeltaPrev
+    mov     rcx, u64PrevNanoTS          ; param 4 - u64PrevNanoTS
+%endif
+    call    qword [pData + RTTIMENANOTSDATA.pfnBad]
+
+    mov     rax, TmpVar
+    mov     pData, TmpVar2
+    jmp     .Update
+
+
+    ;;
+    ;; Attempt updating the previous value, provided we're still ahead of it.
+    ;;
+    ;; There is no point in recalculating u64NanoTS because we got preemted or if
+    ;; we raced somebody while the GIP was updated, since these are events
+    ;; that might occure at any point in the return path as well.
+    ;;
+    ;; rax = *pData->u64Prev;
+    ;; rcx = u64RetNanoTS
+    ;;
+ALIGNCODE(16)
+.UpdateFailed:
+    lock inc dword [pData + RTTIMENANOTSDATA.cUpdateRaces]
+    ; for (i = 0; i < 10; i++)
+    mov     ebx, 10
+.UpdateLoop:
+    ; if (u64PrevNanoTS >= u64RetNanoTS)
+    ;     break;
+    cmp     rax, rcx
+    jge     .Updated
+.UpdateLoopLess:
+    ; retry
+    lock cmpxchg [pData + RTTIMENANOTSDATA.u64Prev], rcx
+    jz      .Updated
+    dec     ebx
+    jnz     .UpdateLoop
+    jmp     .Updated
+
+
+    ;;
+    ;; The GIP is seemingly invalid, redo the discovery.
+    ;;
+.Rediscover:
+%ifdef ASM_CALL64_MSC
+    mov     rcx, pData
+%else
+    ; mov     rdi, pData - already in rdi
+%endif
+    call    [pData + RTTIMENANOTSDATA.pfnRediscover]
+    jmp     .Done
+
+
+    ;
+    ; Cleanup variables
+    ;
+%undef SavedRBX
+%undef SavedR12
+%undef SavedR13
+%undef SavedR14
+%undef SavedR15
+%undef SavedRDI
+%undef SavedRSI
+%undef pData
+%undef TmpVar
+%undef u64TSC
+%undef pGip
+%undef pGipCPU
+%undef u32TransactionId
+%undef u64CurNanoTS
+%undef u64PrevNanoTS
+%undef u32UpdateIntervalTSC
+%undef u32UpdateIntervalTSC_64
+%undef u32UpdateIntervalNS
+%undef u64SavedRetNanoTS
+%undef u32ApicIdPlus
+
+%endif  ; AMD64
+ENDPROC rtTimeNanoTSInternalAsm
+
+
+
Index: /trunk/src/VBox/Runtime/common/time/timesupref.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/time/timesupref.cpp	(revision 5456)
+++ /trunk/src/VBox/Runtime/common/time/timesupref.cpp	(revision 5456)
@@ -0,0 +1,68 @@
+/* $Id$ */
+/** @file
+ * innotek Portable Runtime - Time using SUPLib, the C Implementation.
+ */
+
+/*
+ * Copyright (C) 2006-2007 InnoTek Systemberatung GmbH
+ *
+ * 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 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 IN_GUEST
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <iprt/time.h>
+#include <iprt/asm.h>
+#include <VBox/sup.h>
+#include "internal/time.h"
+
+
+/*
+ * Use the CPUID instruction for some kind of serialization.
+ */
+#undef  ASYNC_GIP
+#undef  USE_LFENCE
+#define NEED_TRANSACTION_ID
+#define rtTimeNanoTSInternalRef RTTimeNanoTSLegacySync
+#include "timesupref.h"
+
+#define ASYNC_GIP
+#ifdef IN_GC
+# undef NEED_TRANSACTION_ID
+#endif
+#undef  rtTimeNanoTSInternalRef
+#define rtTimeNanoTSInternalRef RTTimeNanoTSLegacyAsync
+#include "timesupref.h"
+
+
+/*
+ * Use LFENCE for load serialization.
+ */
+#undef  ASYNC_GIP
+#define USE_LFENCE
+#undef  NEED_TRANSACTION_ID
+#define NEED_TRANSACTION_ID
+#undef  rtTimeNanoTSInternalRef
+#define rtTimeNanoTSInternalRef RTTimeNanoTSLFenceSync
+#include "timesupref.h"
+
+#define ASYNC_GIP
+#ifdef IN_GC
+# undef NEED_TRANSACTION_ID
+#endif
+#undef  rtTimeNanoTSInternalRef
+#define rtTimeNanoTSInternalRef RTTimeNanoTSLFenceAsync
+#include "timesupref.h"
+
+
+#endif /* !IN_GUEST */
Index: /trunk/src/VBox/Runtime/common/time/timesupref.h
===================================================================
--- /trunk/src/VBox/Runtime/common/time/timesupref.h	(revision 5456)
+++ /trunk/src/VBox/Runtime/common/time/timesupref.h	(revision 5456)
@@ -0,0 +1,166 @@
+/* $Id$ */
+/** @file
+ * innotek Portable Runtime - Time using SUPLib, the C Code Template.
+ */
+
+/*
+ * Copyright (C) 2006-2007 InnoTek Systemberatung GmbH
+ *
+ * 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 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 C reference implementation of the assembly routines.
+ *
+ * Calculate NanoTS using the information in the global information page (GIP)
+ * which the support library (SUPLib) exports.
+ *
+ * This function guarantees that the returned timestamp is later (in time) than
+ * any previous calls in the same thread.
+ *
+ * @remark  The way the ever increasing time guarantee is currently implemented means
+ *          that if you call this function at a freqency higher than 1GHz you're in for
+ *          trouble. We currently assume that no idiot will do that for real life purposes.
+ *
+ * @returns Nanosecond timestamp.
+ * @param   pData       Pointer to the data structure.
+ */
+RTDECL(uint64_t) rtTimeNanoTSInternalRef(PRTTIMENANOTSDATA pData)
+{
+    uint64_t    u64Delta;
+    uint32_t    u32NanoTSFactor0;
+    uint64_t    u64TSC;
+    uint64_t    u64NanoTS;
+    uint32_t    u32UpdateIntervalTSC;
+    uint64_t    u64PrevNanoTS;
+
+    /*
+     * Read the GIP data and the previous value.
+     */
+    for (;;)
+    {
+        PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage;
+#ifdef IN_RING3
+        if (RT_UNLIKELY(!pGip || pGip->u32Magic != SUPGLOBALINFOPAGE_MAGIC))
+            return pData->pfnRediscover(pData);
+#endif
+
+#ifdef ASYNC_GIP
+        uint8_t u8ApicId = ASMGetApicId();
+        PSUPGIPCPU pGipCpu = &pGip->aCPUs[u8ApicId];
+#else
+        PSUPGIPCPU pGipCpu = &pGip->aCPUs[0];
+#endif
+
+#ifdef NEED_TRANSACTION_ID
+        uint32_t u32TransactionId = pGipCpu->u32TransactionId;
+        uint32_t volatile Tmp1;
+        ASMAtomicXchgU32(&Tmp1, u32TransactionId);
+#endif
+
+        u32UpdateIntervalTSC = pGipCpu->u32UpdateIntervalTSC;
+        u64NanoTS = pGipCpu->u64NanoTS;
+        u64TSC = pGipCpu->u64TSC;
+        u32NanoTSFactor0 = pGip->u32UpdateIntervalNS;
+        u64Delta = ASMReadTSC();
+        u64PrevNanoTS = ASMAtomicReadU64(&pData->u64Prev);
+
+#ifdef NEED_TRANSACTION_ID
+# ifdef ASYNC_GIP
+        if (RT_UNLIKELY(u8ApicId != ASMGetApicId()))
+            continue;
+# elif !defined(RT_ARCH_X86)
+        uint32_t volatile Tmp2;
+        ASMAtomicXchgU32(&Tmp2, u64Delta);
+# endif
+        if (RT_UNLIKELY(    pGipCpu->u32TransactionId != u32TransactionId
+                        ||  (u32TransactionId & 1)))
+            continue;
+#endif
+        break;
+    }
+
+    /*
+     * Calc NanoTS delta.
+     */
+    u64Delta -= u64TSC;
+    if (RT_UNLIKELY(u64Delta > u32UpdateIntervalTSC))
+    {
+        /*
+         * We've expired the interval, cap it. If we're here for the 2nd
+         * time without any GIP update inbetween, the checks against
+         * *pu64Prev below will force 1ns stepping.
+         */
+        pData->cExpired++;
+        u64Delta = u32UpdateIntervalTSC;
+    }
+#if !defined(_MSC_VER) || defined(RT_ARCH_AMD64) /* GCC makes very pretty code from these two inline calls, while MSC cannot. */
+    u64Delta = ASMMult2xU32RetU64((uint32_t)u64Delta, u32NanoTSFactor0);
+    u64Delta = ASMDivU64ByU32RetU32(u64Delta, u32UpdateIntervalTSC);
+#else
+    __asm
+    {
+        mov     eax, dword ptr [u64Delta]
+        mul     dword ptr [u32NanoTSFactor0]
+        div     dword ptr [u32UpdateIntervalTSC]
+        mov     dword ptr [u64Delta], eax
+        xor     edx, edx
+        mov     dword ptr [u64Delta + 4], edx
+    }
+#endif
+
+    /*
+     * Calculate the time and compare it with the previously returned value.
+     */
+    u64NanoTS += u64Delta;
+    uint64_t u64DeltaPrev = u64NanoTS - u64PrevNanoTS;
+    if (RT_LIKELY(   u64DeltaPrev > 0
+                  && u64DeltaPrev < UINT64_C(86000000000000) /* 24h */))
+        /* Frequent - less than 24h since last call. */;
+    else if (RT_LIKELY(   (int64_t)u64DeltaPrev <= 0
+                       && (int64_t)u64DeltaPrev + u32NanoTSFactor0 * 2 >= 0))
+    {
+        /* Occasional - u64NanoTS is in the recent 'past' relative the previous call. */
+        ASMAtomicIncU32(&pData->c1nsSteps);
+        u64NanoTS = u64PrevNanoTS + 1;
+    }
+    else if (!u64PrevNanoTS)
+        /* We're resuming (see TMVirtualResume). */;
+    else
+    {
+        /* Something has gone bust, if negative offset it's real bad. */
+        ASMAtomicIncU32(&pData->cBadPrev);
+        pData->pfnBad(pData, u64NanoTS, u64DeltaPrev, u64PrevNanoTS);
+    }
+
+    if (RT_LIKELY(ASMAtomicCmpXchgU64(&pData->u64Prev, u64NanoTS, u64PrevNanoTS)))
+    {
+        /*
+         * Attempt updating the previous value, provided we're still ahead of it.
+         *
+         * There is no point in recalculating u64NanoTS because we got preemted or if
+         * we raced somebody while the GIP was updated, since these are events
+         * that might occure at any point in the return path as well.
+         */
+        pData->cUpdateRaces++;
+        for (int cTries = 25;;)
+        {
+            u64PrevNanoTS = ASMAtomicReadU64(&pData->u64Prev);
+            if (u64PrevNanoTS >= u64NanoTS)
+                break;
+            if (ASMAtomicCmpXchgU64(&pData->u64Prev, u64NanoTS, u64PrevNanoTS))
+                break;
+            AssertBreak(--cTries <= 0, );
+        }
+    }
+    return u64NanoTS;
+}
+
Index: /trunk/src/VBox/Runtime/testcase/tstTime-2.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstTime-2.cpp	(revision 5455)
+++ /trunk/src/VBox/Runtime/testcase/tstTime-2.cpp	(revision 5456)
@@ -19,13 +19,4 @@
 *   Header Files                                                               *
 *******************************************************************************/
-#ifdef RT_OS_WINDOWS
-# include <Windows.h>
-
-#elif defined RT_OS_L4
-
-#else /* posix */
-# include <sys/time.h>
-#endif
-
 #include <iprt/time.h>
 #include <iprt/stream.h>
@@ -33,24 +24,4 @@
 #include <iprt/thread.h>
 #include <VBox/sup.h>
-
-DECLINLINE(uint64_t) OSNanoTS(void)
-{
-#ifdef RT_OS_WINDOWS
-    uint64_t u64; /* manual say larger integer, should be safe to assume it's the same. */
-    GetSystemTimeAsFileTime((LPFILETIME)&u64);
-    return u64 * 100;
-
-#elif defined RT_OS_L4
-    /** @todo fix a different timesource on l4. */
-    return RTTimeNanoTS();
-
-#else /* posix */
-
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-    return (uint64_t)tv.tv_sec  * (uint64_t)(1000 * 1000 * 1000)
-         + (uint64_t)(tv.tv_usec * 1000);
-#endif
-}
 
 
@@ -61,5 +32,4 @@
     int i;
     RTR3Init();
-SUPInit();
     RTPrintf("tstTime-2: TESTING...\n");
 
@@ -69,7 +39,7 @@
      */
 
-    OSNanoTS(); RTTimeNanoTS(); RTThreadYield();
+    RTTimeSystemNanoTS(); RTTimeNanoTS(); RTThreadYield();
     uint64_t u64RTStartTS = RTTimeNanoTS();
-    uint64_t u64OSStartTS = OSNanoTS();
+    uint64_t u64OSStartTS = RTTimeSystemNanoTS();
 #define NUMBER_OF_CALLS (100*_1M)
 
@@ -78,5 +48,5 @@
 
     uint64_t u64RTElapsedTS = RTTimeNanoTS();
-    uint64_t u64OSElapsedTS = OSNanoTS();
+    uint64_t u64OSElapsedTS = RTTimeSystemNanoTS();
     u64RTElapsedTS -= u64RTStartTS;
     u64OSElapsedTS -= u64OSStartTS;
@@ -92,7 +62,10 @@
                  u64OSElapsedTS, u64RTElapsedTS, u64OSElapsedTS - u64RTElapsedTS);
 
-#if defined RT_OS_WINDOWS || defined RT_OS_LINUX
-    RTPrintf("tstTime-2: RTTime1nsSteps -> %u out of %u calls\n", RTTime1nsSteps(), NUMBER_OF_CALLS);
-#endif
+    RTPrintf("tstTime-2: %u calls to RTTimeNanoTS\n", NUMBER_OF_CALLS);
+    RTPrintf("tstTime-2: RTTimeDbgSteps   -> %u (%d ppt)\n", RTTimeDbgSteps(),   ((uint64_t)RTTimeDbgSteps() * 1000) / NUMBER_OF_CALLS);
+    RTPrintf("tstTime-2: RTTimeDbgExpired -> %u (%d ppt)\n", RTTimeDbgExpired(), ((uint64_t)RTTimeDbgExpired() * 1000) / NUMBER_OF_CALLS);
+    RTPrintf("tstTime-2: RTTimeDbgBad     -> %u (%d ppt)\n", RTTimeDbgBad(),     ((uint64_t)RTTimeDbgBad() * 1000) / NUMBER_OF_CALLS);
+    RTPrintf("tstTime-2: RTTimeDbgRaces   -> %u (%d ppt)\n", RTTimeDbgRaces(),   ((uint64_t)RTTimeDbgRaces() * 1000) / NUMBER_OF_CALLS);
+
     if (!cErrors)
         RTPrintf("tstTime-2: SUCCESS\n");
Index: /trunk/src/VBox/Runtime/testcase/tstTime.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstTime.cpp	(revision 5455)
+++ /trunk/src/VBox/Runtime/testcase/tstTime.cpp	(revision 5456)
@@ -19,39 +19,9 @@
 *   Header Files                                                               *
 *******************************************************************************/
-#ifdef RT_OS_WINDOWS
-# include <Windows.h>
-
-#elif defined RT_OS_L4
-
-#else /* posix */
-# include <sys/time.h>
-#endif
-
 #include <iprt/time.h>
 #include <iprt/stream.h>
-#include <iprt/runtime.h>
+#include <iprt/initterm.h>
 #include <iprt/thread.h>
 #include <VBox/sup.h>
-
-DECLINLINE(uint64_t) OSNanoTS(void)
-{
-#ifdef RT_OS_WINDOWS
-    uint64_t u64; /* manual say larger integer, should be safe to assume it's the same. */
-    GetSystemTimeAsFileTime((LPFILETIME)&u64);
-    return u64 * 100;
-
-#elif defined RT_OS_L4
-    /** @todo fix a different timesource on l4. */
-    return RTTimeNanoTS();
-
-#else /* posix */
-
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-    return (uint64_t)tv.tv_sec  * (uint64_t)(1000 * 1000 * 1000)
-         + (uint64_t)(tv.tv_usec * 1000);
-#endif
-}
-
 
 
@@ -61,5 +31,4 @@
     int i;
     RTR3Init();
-SUPInit();
     RTPrintf("tstTime: TESTING...\n");
 
@@ -69,7 +38,7 @@
      */
 
-    OSNanoTS(); RTTimeNanoTS(); RTThreadYield();
+    RTTimeSystemNanoTS(); RTTimeNanoTS(); RTThreadYield();
     uint64_t u64RTStartTS = RTTimeNanoTS();
-    uint64_t u64OSStartTS = OSNanoTS();
+    uint64_t u64OSStartTS = RTTimeSystemNanoTS();
 
     uint64_t u64Prev = RTTimeNanoTS();
@@ -101,7 +70,7 @@
     }
 
-    OSNanoTS(); RTTimeNanoTS(); RTThreadYield();
+    RTTimeSystemNanoTS(); RTTimeNanoTS(); RTThreadYield();
     uint64_t u64RTElapsedTS = RTTimeNanoTS();
-    uint64_t u64OSElapsedTS = OSNanoTS();
+    uint64_t u64OSElapsedTS = RTTimeSystemNanoTS();
     u64RTElapsedTS -= u64RTStartTS;
     u64OSElapsedTS -= u64OSStartTS;
@@ -117,5 +86,8 @@
                  u64OSElapsedTS, u64RTElapsedTS, u64OSElapsedTS - u64RTElapsedTS);
 
-    RTPrintf("RTTime1nsSteps -> %u (%d ppt)\n", RTTime1nsSteps(), (RTTime1nsSteps() * 1000) / i);
+    RTPrintf("RTTimeDbgSteps   -> %u (%d ppt)\n", RTTimeDbgSteps(),   ((uint64_t)RTTimeDbgSteps() * 1000) / i);
+    RTPrintf("RTTimeDbgExpired -> %u (%d ppt)\n", RTTimeDbgExpired(), ((uint64_t)RTTimeDbgExpired() * 1000) / i);
+    RTPrintf("RTTimeDbgBad     -> %u (%d ppt)\n", RTTimeDbgBad(),     ((uint64_t)RTTimeDbgBad() * 1000) / i);
+    RTPrintf("RTTimeDbgRaces   -> %u (%d ppt)\n", RTTimeDbgRaces(),   ((uint64_t)RTTimeDbgRaces() * 1000) / i);
     if (!cErrors)
         RTPrintf("tstTime: SUCCESS\n");
