Index: /trunk/include/VBox/vmm/cpum.h
===================================================================
--- /trunk/include/VBox/vmm/cpum.h	(revision 70055)
+++ /trunk/include/VBox/vmm/cpum.h	(revision 70056)
@@ -1208,4 +1208,5 @@
 VMM_INT_DECL(void)      CPUMSvmVmExitRestoreHostState(PVMCPU pVCpu, PCPUMCTX pCtx);
 VMM_INT_DECL(void)      CPUMSvmVmRunSaveHostState(PCPUMCTX pCtx, uint8_t cbInstr);
+VMM_INT_DECL(uint64_t)  CPUMApplyNestedGuestTscOffset(PVMCPU pVCpu, uint64_t uTicks);
 /** @} */
 
Index: /trunk/include/VBox/vmm/hm_svm.h
===================================================================
--- /trunk/include/VBox/vmm/hm_svm.h	(revision 70055)
+++ /trunk/include/VBox/vmm/hm_svm.h	(revision 70056)
@@ -991,4 +991,6 @@
     /** Cache of MSRPM nested-guest physical address. */
     uint64_t            u64MSRPMPhysAddr;
+    /** Cache of the TSC offset. */
+    uint64_t            u64TSCOffset;
     /** Cache of the VMCB clean bits. */
     uint64_t            u64VmcbCleanBits;
Index: /trunk/src/VBox/VMM/VMMAll/CPUMAllMsrs.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/CPUMAllMsrs.cpp	(revision 70055)
+++ /trunk/src/VBox/VMM/VMMAll/CPUMAllMsrs.cpp	(revision 70056)
@@ -184,4 +184,7 @@
     RT_NOREF_PV(pVCpu); RT_NOREF_PV(idMsr); RT_NOREF_PV(pRange);
     *puValue = TMCpuTickGet(pVCpu);
+#ifdef VBOX_WITH_NESTED_HWVIRT
+    *puValue = CPUMApplyNestedGuestTscOffset(pVCpu, *puValue);
+#endif
     return VINF_SUCCESS;
 }
@@ -342,4 +345,7 @@
      *        what we want? */
     *puValue = TMCpuTickGet(pVCpu);
+#ifdef VBOX_WITH_NESTED_HWVIRT
+    *puValue = CPUMApplyNestedGuestTscOffset(pVCpu, *puValue);
+#endif
     return VINF_SUCCESS;
 }
@@ -362,4 +368,7 @@
      *        what we want? */
     *puValue = TMCpuTickGet(pVCpu);
+#ifdef VBOX_WITH_NESTED_HWVIRT
+    *puValue = CPUMApplyNestedGuestTscOffset(pVCpu, *puValue);
+#endif
     return VINF_SUCCESS;
 }
Index: /trunk/src/VBox/VMM/VMMAll/CPUMAllRegs.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/CPUMAllRegs.cpp	(revision 70055)
+++ /trunk/src/VBox/VMM/VMMAll/CPUMAllRegs.cpp	(revision 70056)
@@ -2695,2 +2695,28 @@
 }
 
+
+/**
+ * Applies the TSC offset of a nested-guest if any and returns the new TSC
+ * value for the guest.
+ *
+ * @returns The TSC offset after applying any nested-guest TSC offset.
+ * @param   pVCpu       The cross context virtual CPU structure of the calling EMT.
+ * @param   uTicks      The guest TSC.
+ */
+VMM_INT_DECL(uint64_t) CPUMApplyNestedGuestTscOffset(PVMCPU pVCpu, uint64_t uTicks)
+{
+#ifndef IN_RC
+    PCCPUMCTX pCtx  = &pVCpu->cpum.s.Guest;
+    if (CPUMIsGuestInSvmNestedHwVirtMode(pCtx))
+    {
+        PCSVMVMCB pVmcb = pCtx->hwvirt.svm.CTX_SUFF(pVmcb);
+        return uTicks + pVmcb->ctrl.u64TSCOffset;
+    }
+
+    /** @todo Intel. */
+#else
+    RT_NOREF(pVCpu);
+#endif
+    return uTicks;
+}
+
Index: /trunk/src/VBox/VMM/VMMAll/EMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/EMAll.cpp	(revision 70055)
+++ /trunk/src/VBox/VMM/VMMAll/EMAll.cpp	(revision 70056)
@@ -1315,4 +1315,7 @@
 
     uint64_t uTicks = TMCpuTickGet(pVCpu);
+#ifdef VBOX_WITH_NESTED_HWVIRT
+    uTicks = CPUMApplyNestedGuestTscOffset(pVCpu, uTicks);
+#endif
 
     /* Same behaviour in 32 & 64 bits mode */
@@ -1351,4 +1354,7 @@
 
     uint64_t uTicks = TMCpuTickGet(pVCpu);
+#ifdef VBOX_WITH_NESTED_HWVIRT
+    uTicks = CPUMApplyNestedGuestTscOffset(pVCpu, uTicks);
+#endif
 
     /* Same behaviour in 32 & 64 bits mode */
Index: /trunk/src/VBox/VMM/VMMAll/HMSVMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/HMSVMAll.cpp	(revision 70055)
+++ /trunk/src/VBox/VMM/VMMAll/HMSVMAll.cpp	(revision 70056)
@@ -366,4 +366,5 @@
         pVmcbNstGstCtrl->u64IOPMPhysAddr          = pNstGstVmcbCache->u64IOPMPhysAddr;
         pVmcbNstGstCtrl->u64MSRPMPhysAddr         = pNstGstVmcbCache->u64MSRPMPhysAddr;
+        pVmcbNstGstCtrl->u64TSCOffset             = pNstGstVmcbCache->u64TSCOffset;
         pVmcbNstGstCtrl->IntCtrl.n.u1VIntrMasking = pNstGstVmcbCache->fVIntrMasking;
         pVmcbNstGstCtrl->TLBCtrl                  = pNstGstVmcbCache->TLBCtrl;
Index: /trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp	(revision 70055)
+++ /trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp	(revision 70056)
@@ -2156,4 +2156,5 @@
         pNstGstVmcbCache->u64IOPMPhysAddr   = pVmcbNstGstCtrl->u64IOPMPhysAddr;
         pNstGstVmcbCache->u64MSRPMPhysAddr  = pVmcbNstGstCtrl->u64MSRPMPhysAddr;
+        pNstGstVmcbCache->u64TSCOffset      = pVmcbNstGstCtrl->u64TSCOffset;
         pNstGstVmcbCache->u64VmcbCleanBits  = pVmcbNstGstCtrl->u64VmcbCleanBits;
         pNstGstVmcbCache->fVIntrMasking     = pVmcbNstGstCtrl->IntCtrl.n.u1VIntrMasking;
@@ -2707,4 +2708,64 @@
     return rcExit;
 }
+
+
+#ifdef VBOX_WITH_NESTED_HWVIRT
+/**
+ * Updates the use of TSC offsetting mode for the CPU and adjusts the necessary
+ * intercepts for the nested-guest.
+ *
+ * @param   pVM             The cross context VM structure.
+ * @param   pVCpu           The cross context virtual CPU structure.
+ * @param   pCtx            Pointer to the nested guest-CPU context.
+ * @param   pVmcbNstGst     Pointer to the nested-guest VM control block.
+ *
+ * @remarks No-long-jump zone!!!
+ */
+static void hmR0SvmUpdateTscOffsettingNested(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, PSVMVMCB pVmcbNstGst)
+{
+    Assert(CPUMIsGuestInSvmNestedHwVirtMode(pCtx));
+
+    bool                 fParavirtTsc;
+    uint64_t             uTscOffset;
+    bool fCanUseRealTsc = TMCpuTickCanUseRealTSC(pVM, pVCpu, &uTscOffset, &fParavirtTsc);
+
+    PCSVMNESTEDVMCBCACHE pVmcbNstGstCache = &pVCpu->hm.s.svm.NstGstVmcbCache;
+    PSVMVMCBCTRL         pVmcbNstGstCtrl  = &pVmcbNstGst->ctrl;
+
+    /*
+     * Only avoid intercepting if we determined the host TSC (++) is stable enough
+     * to not intercept -and- the nested-hypervisor itself does not want to intercept it.
+     */
+    if (    fCanUseRealTsc
+        && !(pVmcbNstGstCache->u64InterceptCtrl & (SVM_CTRL_INTERCEPT_RDTSC | SVM_CTRL_INTERCEPT_RDTSCP)))
+    {
+        pVmcbNstGstCtrl->u64InterceptCtrl &= ~SVM_CTRL_INTERCEPT_RDTSC;
+        pVmcbNstGstCtrl->u64InterceptCtrl &= ~SVM_CTRL_INTERCEPT_RDTSCP;
+        STAM_COUNTER_INC(&pVCpu->hm.s.StatTscOffset);
+    }
+    else
+    {
+        pVmcbNstGstCtrl->u64InterceptCtrl |= SVM_CTRL_INTERCEPT_RDTSC;
+        pVmcbNstGstCtrl->u64InterceptCtrl |= SVM_CTRL_INTERCEPT_RDTSCP;
+        STAM_COUNTER_INC(&pVCpu->hm.s.StatTscIntercept);
+    }
+
+    /* Apply the nested-guest VMCB's TSC offset over the guest one. */
+    uTscOffset = CPUMApplyNestedGuestTscOffset(pVCpu, uTscOffset);
+
+    /* Update the nested-guest VMCB with the combined TSC offset (of guest and nested-guest). */
+    pVmcbNstGstCtrl->u64TSCOffset = uTscOffset;
+
+    /* Finally update the VMCB clean bits since we touched the intercepts as well as the TSC offset. */
+    pVmcbNstGstCtrl->u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_INTERCEPTS;
+
+    if (fParavirtTsc)
+    {
+        /* Currently neither Hyper-V nor KVM need to update their paravirt. TSC
+           information before every VM-entry, hence disable it for performance sake. */
+        STAM_COUNTER_INC(&pVCpu->hm.s.StatTscParavirt);
+    }
+}
+#endif
 
 
@@ -3960,5 +4021,5 @@
         || idCurrentCpu != pVCpu->hm.s.idLastCpu)
     {
-        hmR0SvmUpdateTscOffsetting(pVM, pVCpu, pVmcbNstGst);
+        hmR0SvmUpdateTscOffsettingNested(pVM, pVCpu, pCtx, pVmcbNstGst);
         pSvmTransient->fUpdateTscOffsetting = false;
     }
@@ -4213,8 +4274,16 @@
 
     /* TSC read must be done early for maximum accuracy. */
-    PSVMVMCB     pVmcbNstGst     = pMixedCtx->hwvirt.svm.CTX_SUFF(pVmcb);
-    PSVMVMCBCTRL pVmcbNstGstCtrl = &pVmcbNstGst->ctrl;
+    PSVMVMCB             pVmcbNstGst     = pMixedCtx->hwvirt.svm.CTX_SUFF(pVmcb);
+    PSVMVMCBCTRL         pVmcbNstGstCtrl = &pVmcbNstGst->ctrl;
+    PCSVMNESTEDVMCBCACHE pVmcbNstGstCache = &pVCpu->hm.s.svm.NstGstVmcbCache;
     if (!(pVmcbNstGstCtrl->u64InterceptCtrl & SVM_CTRL_INTERCEPT_RDTSC))
-        TMCpuTickSetLastSeen(pVCpu, ASMReadTSC() + pVmcbNstGstCtrl->u64TSCOffset);
+    {
+        /*
+         * Undo what we did in hmR0SvmUpdateTscOffsettingNested() but don't restore the
+         * nested-guest VMCB TSC offset here. It shall eventually be restored on #VMEXIT
+         * later by HMSvmNstGstVmExitNotify().
+         */
+        TMCpuTickSetLastSeen(pVCpu, ASMReadTSC() + pVmcbNstGstCtrl->u64TSCOffset - pVmcbNstGstCache->u64TSCOffset);
+    }
 
     if (pSvmTransient->fRestoreTscAuxMsr)
