Index: trunk/include/VBox/err.h
===================================================================
--- trunk/include/VBox/err.h	(revision 72545)
+++ trunk/include/VBox/err.h	(revision 72546)
@@ -2849,4 +2849,6 @@
 /** Get register caller must update the APIC base. */
 #define VINF_NEM_UPDATE_APIC_BASE                   (6811)
+/** NEM failed to set TSC. */
+#define VERR_NEM_SET_TSC                            (-6812)
 
 /** NEM internal processing error \#0. */
Index: trunk/include/VBox/vmm/nem.h
===================================================================
--- trunk/include/VBox/vmm/nem.h	(revision 72545)
+++ trunk/include/VBox/vmm/nem.h	(revision 72546)
@@ -93,4 +93,5 @@
 VMMR0_INT_DECL(int)  NEMR0ImportState(PGVM pGVM, PVM pVM, VMCPUID idCpu, uint64_t fWhat);
 VMMR0_INT_DECL(int)  NEMR0QueryCpuTick(PGVM pGVM, PVM pVM, VMCPUID idCpu);
+VMMR0_INT_DECL(int)  NEMR0ResumeCpuTickOnAll(PGVM pGVM, PVM pVM, VMCPUID idCpu, uint64_t uPausedTscValue);
 VMMR0_INT_DECL(VBOXSTRICTRC) NEMR0RunGuestCode(PGVM pGVM, VMCPUID idCpu);
 VMMR0_INT_DECL(int)  NEMR0UpdateStatistics(PGVM pGVM, PVM pVM, VMCPUID idCpu);
@@ -126,4 +127,6 @@
 
 VMM_INT_DECL(int) NEMHCQueryCpuTick(PVMCPU pVCpu, uint64_t *pcTicks, uint32_t *puAux);
+VMM_INT_DECL(int) NEMHCResumeCpuTickOnAll(PVM pVM, PVMCPU pVCpu, uint64_t uPausedTscValue);
+
 /** @} */
 
Index: trunk/include/VBox/vmm/vmm.h
===================================================================
--- trunk/include/VBox/vmm/vmm.h	(revision 72545)
+++ trunk/include/VBox/vmm/vmm.h	(revision 72546)
@@ -445,4 +445,6 @@
     /** Call NEMR0QueryCpuTick() (host specific). */
     VMMR0_DO_NEM_QUERY_CPU_TICK,
+    /** Call NEMR0ResumeCpuTickOnAll() (host specific). */
+    VMMR0_DO_NEM_RESUME_CPU_TICK_ON_ALL,
     /** Call NEMR0UpdateStatistics() (host specific). */
     VMMR0_DO_NEM_UPDATE_STATISTICS,
Index: trunk/src/VBox/VMM/VMMAll/NEMAll.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/NEMAll.cpp	(revision 72545)
+++ trunk/src/VBox/VMM/VMMAll/NEMAll.cpp	(revision 72546)
@@ -131,4 +131,5 @@
 #endif
 
+
 #ifndef VBOX_WITH_NATIVE_NEM
 VMM_INT_DECL(int) NEMHCQueryCpuTick(PVMCPU pVCpu, uint64_t *pcTicks, uint32_t *puAux)
@@ -140,2 +141,12 @@
 #endif
 
+
+#ifndef VBOX_WITH_NATIVE_NEM
+VMM_INT_DECL(int) NEMHCResumeCpuTickOnAll(PVM pVM, PVMCPU pVCpu, uint64_t uPausedTscValue)
+{
+    RT_NOREF(pVM, pVCpu, uPausedTscValue);
+    AssertFailed();
+    return VERR_NEM_IPE_9;
+}
+#endif
+
Index: trunk/src/VBox/VMM/VMMAll/NEMAllNativeTemplate-win.cpp.h
===================================================================
--- trunk/src/VBox/VMM/VMMAll/NEMAllNativeTemplate-win.cpp.h	(revision 72545)
+++ trunk/src/VBox/VMM/VMMAll/NEMAllNativeTemplate-win.cpp.h	(revision 72546)
@@ -1150,4 +1150,71 @@
     return rc;
 #endif /* IN_RING0 */
+}
+
+
+/**
+ * Resumes CPU clock (TSC) on all virtual CPUs.
+ *
+ * This is called by TM when the VM is started, restored, resumed or similar.
+ *
+ * @returns VBox status code.
+ * @param   pVM             The cross context VM structure.
+ * @param   pVCpu           The cross context CPU structure of the calling EMT.
+ * @param   uPausedTscValue The TSC value at the time of pausing.
+ */
+VMM_INT_DECL(int) NEMHCResumeCpuTickOnAll(PVM pVM, PVMCPU pVCpu, uint64_t uPausedTscValue)
+{
+#ifdef IN_RING0
+    /** @todo improve and secure this translation */
+    PGVM pGVM = GVMMR0ByHandle(pVM->hSelf);
+    AssertReturn(pGVM, VERR_INVALID_VMCPU_HANDLE);
+    VMCPUID idCpu = pVCpu->idCpu;
+    ASMCompilerBarrier();
+    AssertReturn(idCpu < pGVM->cCpus, VERR_INVALID_VMCPU_HANDLE);
+
+    return nemR0WinResumeCpuTickOnAll(pGVM, &pGVM->aCpus[idCpu], uPausedTscValue);
+#else  /* IN_RING3 */
+    VMCPU_ASSERT_EMT_RETURN(pVCpu, VERR_VM_THREAD_NOT_EMT);
+    AssertReturn(VM_IS_NEM_ENABLED(pVM), VERR_NEM_IPE_9);
+
+# ifdef NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS
+    /* Call ring-0 and do it all there. */
+    return VMMR3CallR0Emt(pVM, pVCpu, VMMR0_DO_NEM_RESUME_CPU_TICK_ON_ALL, uPausedTscValue, NULL);
+
+# else
+    /*
+     * Call the offical API to do the job.
+     */
+    if (pVM->cCpus > 1)
+        RTThreadYield(); /* Try decrease the chance that we get rescheduled in the middle. */
+
+    /* Start with the first CPU. */
+    WHV_REGISTER_NAME  enmName   = WHvX64RegisterTsc;
+    WHV_REGISTER_VALUE Value     = {0, 0};
+    aValue.Reg64 = uPausedTscValue;
+    uint64_t const     uFirstTsc = ASMReadTSC();
+    HRESULT hrc = WHvSetVirtualProcessorRegisters(pVM->nem.s.hPartition, 0 /*iCpu*/, &enmName, 1, &Value);
+    AssertLogRelMsgReturn(SUCCEEDED(hrc),
+                          ("WHvSetVirtualProcessorRegisters(%p, 0,{tsc},2,%#RX64) -> %Rhrc (Last=%#x/%u)\n",
+                           pVM->nem.s.hPartition, uPausedTscValue, hrc, RTNtLastStatusValue(), RTNtLastErrorValue())
+                          , VERR_NEM_SET_TSC);
+
+    /* Do the other CPUs, adjusting for elapsed TSC and keeping finger crossed
+       that we don't introduce too much drift here. */
+    for (VMCPUID iCpu = 1; iCpu < pVM->cCpus; iCpu++)
+    {
+        Assert(enmName == WHvX64RegisterTsc);
+        const uint64_t offDelta = (ASMReadTSC() - uFirstTsc);
+        aValue.Reg64 = uPausedTscValue + offDelta;
+        HRESULT hrc = WHvSetVirtualProcessorRegisters(pVM->nem.s.hPartition, iCpu, &enmName, 1, &Value);
+        AssertLogRelMsgReturn(SUCCEEDED(hrc),
+                              ("WHvSetVirtualProcessorRegisters(%p, 0,{tsc},2,%#RX64 + %#RX64) -> %Rhrc (Last=%#x/%u)\n",
+                               pVM->nem.s.hPartition, iCpu, uPausedTscValue, offDelta, hrc, RTNtLastStatusValue(), RTNtLastErrorValue())
+                              , VERR_NEM_SET_TSC);
+    }
+
+    return VINF_SUCCESS;
+# endif
+#endif /* IN_RING3 */
 }
 
Index: trunk/src/VBox/VMM/VMMAll/TMAllCpu.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/TMAllCpu.cpp	(revision 72545)
+++ trunk/src/VBox/VMM/VMMAll/TMAllCpu.cpp	(revision 72546)
@@ -95,4 +95,5 @@
             case TMTSCMODE_NATIVE_API:
                 pVCpu->tm.s.offTSCRawSrc = 0; /** @todo ?? */
+                /* Looks like this is only used by weird modes and MSR TSC writes.  We cannot support either on NEM/win. */
                 break;
             default:
@@ -140,11 +141,19 @@
                     break;
                 case TMTSCMODE_NATIVE_API:
-                    pVCpu->tm.s.offTSCRawSrc = 0; /** @todo ?? */
+                {
+#ifndef IN_RC
+                    int rc = NEMHCResumeCpuTickOnAll(pVM, pVCpu, pVM->tm.s.u64LastPausedTSC);
+                    AssertRCReturn(rc, rc);
+                    pVCpu->tm.s.offTSCRawSrc = offTSCRawSrcOld = 0;
+#else
+                    AssertFailedReturn(VERR_INTERNAL_ERROR_2);
+#endif
                     break;
+                }
                 default:
                     AssertFailedReturn(VERR_IPE_NOT_REACHED_DEFAULT_CASE);
             }
 
-            /* Calculate the offset for other VCPUs to use. */
+            /* Calculate the offset addendum for other VCPUs to use. */
             pVM->tm.s.offTSCPause = pVCpu->tm.s.offTSCRawSrc - offTSCRawSrcOld;
         }
Index: trunk/src/VBox/VMM/VMMR0/NEMR0Native-win.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR0/NEMR0Native-win.cpp	(revision 72545)
+++ trunk/src/VBox/VMM/VMMR0/NEMR0Native-win.cpp	(revision 72546)
@@ -84,4 +84,5 @@
 NEM_TMPL_STATIC int  nemR0WinImportState(PGVM pGVM, PGVMCPU pGVCpu, PCPUMCTX pCtx, uint64_t fWhat);
 NEM_TMPL_STATIC int  nemR0WinQueryCpuTick(PGVM pGVM, PGVMCPU pGVCpu, uint64_t *pcTicks, uint32_t *pcAux);
+NEM_TMPL_STATIC int  nemR0WinResumeCpuTickOnAll(PGVM pGVM, PGVMCPU pGVCpu, uint64_t uPausedTscValue);
 DECLINLINE(NTSTATUS) nemR0NtPerformIoControl(PGVM pGVM, uint32_t uFunction, void *pvInput, uint32_t cbInput,
                                              void *pvOutput, uint32_t cbOutput);
@@ -595,4 +596,5 @@
     HV_INPUT_SET_VP_REGISTERS *pInput = (HV_INPUT_SET_VP_REGISTERS *)pGVCpu->nem.s.HypercallData.pbPage;
     AssertPtrReturn(pInput, VERR_INTERNAL_ERROR_3);
+    AssertReturn(g_pfnHvlInvokeHypercall, VERR_NEM_MISSING_KERNEL_API);
 
     pInput->PartitionId = pGVM->nem.s.idHvPartition;
@@ -1304,4 +1306,5 @@
     HV_INPUT_GET_VP_REGISTERS *pInput = (HV_INPUT_GET_VP_REGISTERS *)pGVCpu->nem.s.HypercallData.pbPage;
     AssertPtrReturn(pInput, VERR_INTERNAL_ERROR_3);
+    AssertReturn(g_pfnHvlInvokeHypercall, VERR_NEM_MISSING_KERNEL_API);
 
     fWhat &= pCtx->fExtrn;
@@ -2222,4 +2225,5 @@
     HV_INPUT_GET_VP_REGISTERS *pInput = (HV_INPUT_GET_VP_REGISTERS *)pGVCpu->nem.s.HypercallData.pbPage;
     AssertPtrReturn(pInput, VERR_INTERNAL_ERROR_3);
+    AssertReturn(g_pfnHvlInvokeHypercall, VERR_NEM_MISSING_KERNEL_API);
 
     pInput->PartitionId = pGVM->nem.s.idHvPartition;
@@ -2280,4 +2284,106 @@
         rc = nemR0WinQueryCpuTick(pGVM, pGVCpu, &pVCpu->nem.s.Hypercall.QueryCpuTick.cTicks,
                                   &pVCpu->nem.s.Hypercall.QueryCpuTick.uAux);
+    }
+    return rc;
+}
+
+
+/**
+ * Worker for NEMR0ResumeCpuTickOnAll and the ring-0 NEMHCResumeCpuTickOnAll.
+ *
+ * @returns VBox status code.
+ * @param   pGVM            The ring-0 VM handle.
+ * @param   pGVCpu          The ring-0 VCPU handle.
+ * @param   uPausedTscValue The TSC value at the time of pausing.
+ */
+NEM_TMPL_STATIC int nemR0WinResumeCpuTickOnAll(PGVM pGVM, PGVMCPU pGVCpu, uint64_t uPausedTscValue)
+{
+    AssertReturn(g_pfnHvlInvokeHypercall, VERR_NEM_MISSING_KERNEL_API);
+
+    /*
+     * Set up the hypercall parameters.
+     */
+    HV_INPUT_SET_VP_REGISTERS *pInput = (HV_INPUT_SET_VP_REGISTERS *)pGVCpu->nem.s.HypercallData.pbPage;
+    AssertPtrReturn(pInput, VERR_INTERNAL_ERROR_3);
+
+    pInput->PartitionId = pGVM->nem.s.idHvPartition;
+    pInput->VpIndex     = 0;
+    pInput->RsvdZ       = 0;
+    pInput->Elements[0].Name  = HvX64RegisterTsc;
+    pInput->Elements[0].Pad0  = 0;
+    pInput->Elements[0].Pad1  = 0;
+    pInput->Elements[0].Value.Reg128.High64 = 0;
+    pInput->Elements[0].Value.Reg64 = uPausedTscValue;
+
+    /*
+     * Disable interrupts and do the first virtual CPU.
+     */
+    RTCCINTREG const fSavedFlags = ASMIntDisableFlags();
+    uint64_t const   uFirstTsc   = ASMReadTSC();
+    uint64_t uResult = g_pfnHvlInvokeHypercall(HV_MAKE_CALL_INFO(HvCallSetVpRegisters, 1),
+                                               pGVCpu->nem.s.HypercallData.HCPhysPage, 0 /* no output */);
+    AssertLogRelMsgReturnStmt(uResult == HV_MAKE_CALL_REP_RET(1), ("uResult=%RX64 uTsc=%#RX64\n", uResult, uPausedTscValue),
+                              ASMSetFlags(fSavedFlags), VERR_NEM_SET_TSC);
+
+    /*
+     * Do secondary processors, adjusting for elapsed TSC and keeping finger crossed
+     * that we don't introduce too much drift here.
+     */
+    for (VMCPUID iCpu = 1; iCpu < pGVM->cCpus; iCpu++)
+    {
+        Assert(pInput->PartitionId == pGVM->nem.s.idHvPartition);
+        Assert(pInput->RsvdZ       == 0);
+        Assert(pInput->Elements[0].Name == HvX64RegisterTsc);
+        Assert(pInput->Elements[0].Pad0 == 0);
+        Assert(pInput->Elements[0].Pad1 == 0);
+        Assert(pInput->Elements[0].Value.Reg128.High64 == 0);
+
+        pInput->VpIndex = iCpu;
+        const uint64_t offDelta = (ASMReadTSC() - uFirstTsc);
+        pInput->Elements[0].Value.Reg64 = uPausedTscValue + offDelta;
+
+        uResult = g_pfnHvlInvokeHypercall(HV_MAKE_CALL_INFO(HvCallSetVpRegisters, 1),
+                                          pGVCpu->nem.s.HypercallData.HCPhysPage, 0 /* no output */);
+        AssertLogRelMsgReturnStmt(uResult == HV_MAKE_CALL_REP_RET(1),
+                                  ("uResult=%RX64 uTsc=%#RX64 + %#RX64\n", uResult, uPausedTscValue, offDelta),
+                                  ASMSetFlags(fSavedFlags), VERR_NEM_SET_TSC);
+    }
+
+    /*
+     * Done.
+     */
+    ASMSetFlags(fSavedFlags);
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Sets the TSC register to @a uPausedTscValue on all CPUs.
+ *
+ * @returns VBox status code
+ * @param   pGVM            The ring-0 VM handle.
+ * @param   pVM             The cross context VM handle.
+ * @param   idCpu           The calling EMT.  Necessary for getting the
+ *                          hypercall page and arguments.
+ * @param   uPausedTscValue The TSC value at the time of pausing.
+ */
+VMMR0_INT_DECL(int) NEMR0ResumeCpuTickOnAll(PGVM pGVM, PVM pVM, VMCPUID idCpu, uint64_t uPausedTscValue)
+{
+    /*
+     * Validate the call.
+     */
+    int rc = GVMMR0ValidateGVMandVMandEMT(pGVM, pVM, idCpu);
+    if (RT_SUCCESS(rc))
+    {
+        PVMCPU  pVCpu  = &pVM->aCpus[idCpu];
+        PGVMCPU pGVCpu = &pGVM->aCpus[idCpu];
+        AssertReturn(g_pfnHvlInvokeHypercall, VERR_NEM_MISSING_KERNEL_API);
+
+        /*
+         * Call worker.
+         */
+        pVCpu->nem.s.Hypercall.QueryCpuTick.cTicks = 0;
+        pVCpu->nem.s.Hypercall.QueryCpuTick.uAux   = 0;
+        rc = nemR0WinResumeCpuTickOnAll(pGVM, pGVCpu, uPausedTscValue);
     }
     return rc;
@@ -2387,5 +2493,5 @@
     if (RT_SUCCESS(rc))
     {
-        AssertPtrReturn(g_pfnHvlInvokeHypercall, VERR_INTERNAL_ERROR_3);
+        AssertReturn(g_pfnHvlInvokeHypercall, VERR_NEM_MISSING_KERNEL_API);
 
         PGVMCPU pGVCpu = &pGVM->aCpus[idCpu];
Index: trunk/src/VBox/VMM/VMMR0/VMMR0.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR0/VMMR0.cpp	(revision 72545)
+++ trunk/src/VBox/VMM/VMMR0/VMMR0.cpp	(revision 72546)
@@ -2070,4 +2070,11 @@
             break;
 
+        case VMMR0_DO_NEM_RESUME_CPU_TICK_ON_ALL:
+            if (pReqHdr || idCpu == NIL_VMCPUID)
+                return VERR_INVALID_PARAMETER;
+            rc = NEMR0ResumeCpuTickOnAll(pGVM, pVM, idCpu, u64Arg);
+            VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+            break;
+
         case VMMR0_DO_NEM_UPDATE_STATISTICS:
             if (u64Arg || pReqHdr)
Index: trunk/src/VBox/VMM/VMMR3/NEMR3Native-win.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR3/NEMR3Native-win.cpp	(revision 72545)
+++ trunk/src/VBox/VMM/VMMR3/NEMR3Native-win.cpp	(revision 72546)
@@ -2614,8 +2614,9 @@
  *
  *
- * - How do we modify the TSC offset (or bias if you like).
- *
- *   This is a show stopper as it breaks both pausing the VM and restoring
- *   of saved state.
+ * - We need a way to directly modify the TSC offset (or bias if you like).
+ *
+ *   The current approach of setting the WHvX64RegisterTsc register one by one
+ *   on each virtual CPU in sequence will introduce random inaccuracies,
+ *   especially if the thread doing the job is reschduled at a bad time.
  *
  *
