Index: trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp	(revision 69916)
+++ trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp	(revision 69926)
@@ -78,4 +78,15 @@
     } while (0)
 
+/**
+ * Updates interrupt shadow for the current RIP.
+ */
+#define HMSVM_UPDATE_INTR_SHADOW(pVCpu, pCtx) \
+    do { \
+        /* Update interrupt shadow. */ \
+        if (   VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS) \
+            && pCtx->rip != EMGetInhibitInterruptsPC(pVCpu)) \
+            VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS); \
+    } while (0)
+
 /** Macro for upgrading a @a a_rc to VINF_EM_DBG_STEPPED after emulating an
  * instruction that exited. */
@@ -96,4 +107,18 @@
                                                         ("Illegal migration! Entered on CPU %u Current %u\n", \
                                                         pVCpu->hm.s.idEnteredCpu, RTMpCpuId()));
+
+/** Assert that we're not executing a nested-guest. */
+#ifdef VBOX_WITH_NESTED_HWVIRT
+# define HMSVM_ASSERT_NOT_IN_NESTED_GUEST(a_pCtx)       Assert(!CPUMIsGuestInSvmNestedHwVirtMode((a_pCtx)))
+#else
+# define HMSVM_ASSERT_NOT_IN_NESTED_GUEST(a_pCtx)       do { RT_NOREF((a_pCtx)); } while (0)
+#endif
+
+/** Assert that we're executing a nested-guest. */
+#ifdef VBOX_WITH_NESTED_HWVIRT
+# define HMSVM_ASSERT_IN_NESTED_GUEST(a_pCtx)           Assert(CPUMIsGuestInSvmNestedHwVirtMode((a_pCtx)))
+#else
+# define HMSVM_ASSERT_IN_NESTED_GUEST(a_pCtx)           do { RT_NOREF((a_pCtx)); } while (0)
+#endif
 
 /**
@@ -314,5 +339,4 @@
 static FNSVMEXITHANDLER hmR0SvmExitInvlpga;
 static FNSVMEXITHANDLER hmR0SvmExitVmrun;
-static FNSVMEXITHANDLER hmR0SvmNestedExitIret;
 static FNSVMEXITHANDLER hmR0SvmNestedExitXcptDB;
 static FNSVMEXITHANDLER hmR0SvmNestedExitXcptBP;
@@ -838,4 +862,23 @@
 
 /**
+ * Gets a pointer to the currently active guest or nested-guest VMCB.
+ *
+ * @returns Pointer to the current context VMCB.
+ * @param   pVCpu           The cross context virtual CPU structure.
+ * @param   pCtx            Pointer to the guest-CPU context.
+ */
+DECLINLINE(PSVMVMCB) hmR0SvmGetCurrentVmcb(PVMCPU pVCpu, PCPUMCTX pCtx)
+{
+#ifdef VBOX_WITH_NESTED_HWVIRT
+    if (CPUMIsGuestInSvmNestedHwVirtMode(pCtx))
+        return pCtx->hwvirt.svm.CTX_SUFF(pVmcb);
+#else
+    RT_NOREF(pCtx);
+#endif
+    return pVCpu->hm.s.svm.pVmcb;
+}
+
+
+/**
  * Invalidates a guest page by guest virtual address.
  *
@@ -857,5 +900,6 @@
         Log4(("SVMR0InvalidatePage %RGv\n", GCVirt));
 
-        PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
+        PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
+        PSVMVMCB pVmcb = hmR0SvmGetCurrentVmcb(pVCpu, pCtx);
         AssertMsgReturn(pVmcb, ("Invalid pVmcb!\n"), VERR_SVM_INVALID_PVMCB);
 
@@ -1748,14 +1792,14 @@
         pVmcbNstGst->ctrl.u16InterceptWrCRx |= pVmcb->ctrl.u16InterceptWrCRx;
 
-        /*
-         * CR3, CR4 reads and writes are intercepted as we modify them before
-         * hardware-assisted SVM execution. In addition, PGM needs to be up to date
-         * on paging mode changes in the nested-guest.
-         *
-         * CR0 writes are intercepted in case of paging mode changes. CR0 reads are not
-         * intercepted as we currently don't modify CR0 while executing the nested-guest.
-         */
-        pVmcbNstGst->ctrl.u16InterceptRdCRx |= RT_BIT(4) | RT_BIT(3);
-        pVmcbNstGst->ctrl.u16InterceptWrCRx |= RT_BIT(4) | RT_BIT(3) | RT_BIT(0);
+        /* Always intercept CR0, CR4 reads and writes as we alter them. */
+        pVmcbNstGst->ctrl.u16InterceptRdCRx |= RT_BIT(0) | RT_BIT(4);
+        pVmcbNstGst->ctrl.u16InterceptWrCRx |= RT_BIT(0) | RT_BIT(4);
+
+        /* Always intercept CR3 reads and writes without nested-paging as we load shadow page tables. */
+        if (!pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging)
+        {
+            pVmcbNstGst->ctrl.u16InterceptRdCRx |= RT_BIT(3);
+            pVmcbNstGst->ctrl.u16InterceptWrCRx |= RT_BIT(3);
+        }
 
         /** @todo Figure out debugging with nested-guests, till then just intercept
@@ -1767,4 +1811,5 @@
         pVmcbNstGst->ctrl.u64InterceptCtrl  |= pVmcb->ctrl.u64InterceptCtrl
                                             |  HMSVM_MANDATORY_NESTED_GUEST_CTRL_INTERCEPTS;
+
         /*
          * Remove control intercepts that we don't need while executing the nested-guest.
@@ -1949,4 +1994,6 @@
 static int hmR0SvmLoadGuestState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
 {
+    HMSVM_ASSERT_NOT_IN_NESTED_GUEST(pCtx);
+
     PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
     AssertMsgReturn(pVmcb, ("Invalid pVmcb\n"), VERR_SVM_INVALID_PVMCB);
@@ -2241,15 +2288,4 @@
     pMixedCtx->cr2        = pVmcb->guest.u64CR2;
 
-#ifdef VBOX_WITH_NESTED_GUEST
-    /*
-     * The nested hypervisor might not be intercepting these control registers,
-     */
-    if (CPUMIsGuestInNestedHwVirtMode(pMixedCtx))
-    {
-        pMixedCtx->cr4    = pVmcb->guest.u64CR4;
-        pMixedCtx->cr0    = pVmcb->guest.u64CR0;
-    }
-#endif
-
     /*
      * Guest MSRs.
@@ -2398,5 +2434,5 @@
     if (CPUMIsHyperDebugStateActive(pVCpu))
     {
-        PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
+        PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb; /** @todo nested-guest. */
         Assert(pVmcb->ctrl.u16InterceptRdDRx == 0xffff);
         Assert(pVmcb->ctrl.u16InterceptWrDRx == 0xffff);
@@ -3020,5 +3056,5 @@
     {
         pVmcb->ctrl.u64InterceptCtrl |= SVM_CTRL_INTERCEPT_IRET;
-        pVmcb->ctrl.u64VmcbCleanBits &= ~(HMSVM_VMCB_CLEAN_INTERCEPTS);
+        pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_INTERCEPTS;
 
         Log4(("Setting IRET intercept\n"));
@@ -3196,4 +3232,5 @@
 #endif
 
+
 /**
  * Evaluates the event to be delivered to the guest and sets it as the pending
@@ -3202,13 +3239,17 @@
  * @param   pVCpu       The cross context virtual CPU structure.
  * @param   pCtx        Pointer to the guest-CPU context.
+ *
+ * @remarks Don't use this function when we are actively executing a
+ *          nested-guest, use hmR0SvmEvaluatePendingEventNested instead.
  */
 static void hmR0SvmEvaluatePendingEvent(PVMCPU pVCpu, PCPUMCTX pCtx)
 {
+    HMSVM_ASSERT_NOT_IN_NESTED_GUEST(pCtx);
     Assert(!pVCpu->hm.s.Event.fPending);
 
 #ifdef VBOX_WITH_NESTED_HWVIRT
-    bool const fGif       = pCtx->hwvirt.svm.fGif;
+    bool const fGif = pCtx->hwvirt.svm.fGif;
 #else
-    bool const fGif       = true;
+    bool const fGif = true;
 #endif
     Log4Func(("fGif=%RTbool\n", fGif));
@@ -3372,4 +3413,5 @@
     NOREF(pCtx);
     HMSVM_ASSERT_PREEMPT_SAFE();
+    HMSVM_ASSERT_NOT_IN_NESTED_GUEST(pCtx);
     PCSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
 
@@ -3738,16 +3780,5 @@
 {
     HMSVM_ASSERT_PREEMPT_SAFE();
-    Assert(!CPUMIsGuestInSvmNestedHwVirtMode(pCtx));
-
-#ifdef VBOX_WITH_NESTED_HWVIRT_ONLY_IN_IEM
-    /* IEM only for executing nested guest, we shouldn't get here. */
-    /** @todo Make this into an assertion since HMR3CanExecuteGuest already checks
-     *        for it? */
-    if (CPUMIsGuestInSvmNestedHwVirtMode(pCtx))
-    {
-        Log2(("hmR0SvmPreRunGuest: Rescheduling to IEM due to nested-hwvirt or forced IEM exec -> VINF_EM_RESCHEDULE_REM\n"));
-        return VINF_EM_RESCHEDULE_REM;
-    }
-#endif
+    HMSVM_ASSERT_NOT_IN_NESTED_GUEST(pCtx);
 
     /* Check force flag actions that might require us to go back to ring-3. */
@@ -3871,4 +3902,5 @@
     Assert(VMMR0IsLogFlushDisabled(pVCpu));
     Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
+    HMSVM_ASSERT_IN_NESTED_GUEST(pCtx);
 
     VMCPU_ASSERT_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
@@ -3982,4 +4014,5 @@
     Assert(VMMR0IsLogFlushDisabled(pVCpu));
     Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
+    HMSVM_ASSERT_NOT_IN_NESTED_GUEST(pCtx);
 
     VMCPU_ASSERT_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
@@ -4188,5 +4221,7 @@
                                                                    guest-CPU context. */
 
+    /** @todo This could later be optimized. Not now. */
     HMSvmNstGstVmExitNotify(pVCpu, pMixedCtx);                  /* Restore modified VMCB fields for now, see @bugref{7243#c52} .*/
+    HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST);                  /* Ensure we re-modify the fields before next reentry. */
 }
 #endif
@@ -4215,5 +4250,5 @@
     ASMAtomicIncU32(&pVCpu->hm.s.cWorldSwitchExits);            /* Initialized in vmR3CreateUVM(): used for EMT poking. */
 
-    PSVMVMCB pVmcb =pVCpu->hm.s.svm.pVmcb;
+    PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
     pVmcb->ctrl.u64VmcbCleanBits = HMSVM_VMCB_CLEAN_ALL;        /* Mark the VMCB-state cache as unmodified by VMM. */
 
@@ -4466,5 +4501,5 @@
 static int hmR0SvmRunGuestCodeNested(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, uint32_t *pcLoops)
 {
-    Assert(CPUMIsGuestInSvmNestedHwVirtMode(pCtx));
+    HMSVM_ASSERT_IN_NESTED_GUEST(pCtx);
     Assert(pcLoops);
     Assert(*pcLoops <= pVM->hm.s.cMaxResumeLoops);
@@ -4514,5 +4549,5 @@
         HMSVM_EXITCODE_STAM_COUNTER_INC(SvmTransient.u64ExitCode);
         STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatExit1, &pVCpu->hm.s.StatExit2, x);
-        VBOXVMM_R0_HMSVM_VMEXIT(pVCpu, pCtx, SvmTransient.u64ExitCode, pVCpu->hm.s.svm.pVmcb);
+        VBOXVMM_R0_HMSVM_VMEXIT(pVCpu, pCtx, SvmTransient.u64ExitCode, pCtx->hwvirt.svm.CTX_SUFF(pVmcb));
         rc = hmR0SvmHandleExitNested(pVCpu, pCtx, &SvmTransient);
         STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit2, x);
@@ -4622,4 +4657,5 @@
 static int hmR0SvmHandleExitNested(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
 {
+    HMSVM_ASSERT_IN_NESTED_GUEST(pCtx);
     Assert(pSvmTransient->u64ExitCode != SVM_EXIT_INVALID);
     Assert(pSvmTransient->u64ExitCode <= SVM_EXIT_MAX);
@@ -4950,5 +4986,5 @@
                     if (HM_SVM_IS_CTRL_INTERCEPT_SET(pCtx, SVM_CTRL_INTERCEPT_IRET))
                         return HM_SVM_VMEXIT_NESTED(pVCpu, uExitCode, uExitInfo1, uExitInfo2);
-                    return hmR0SvmNestedExitIret(pVCpu, pCtx, pSvmTransient);
+                    return hmR0SvmExitIret(pVCpu, pCtx, pSvmTransient);
                 }
 
@@ -5261,5 +5297,4 @@
                     /** @todo r=ramshankar; We should be doing
                      *        HMSVM_CHECK_EXIT_DUE_TO_EVENT_DELIVERY here! */
-
                     PSVMVMCB pVmcb   = pVCpu->hm.s.svm.pVmcb;
                     SVMEVENT Event;
@@ -5524,5 +5559,5 @@
 {
     int rc = VINF_SUCCESS;
-    PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
+    PSVMVMCB pVmcb = hmR0SvmGetCurrentVmcb(pVCpu, pCtx);
 
     Log4(("EXITINTINFO: Pending vectoring event %#RX64 Valid=%RTbool ErrValid=%RTbool Err=%#RX32 Type=%u Vector=%u\n",
@@ -5793,13 +5828,45 @@
 
 /**
- * Updates interrupt shadow for the current RIP.
- */
-#define HMSVM_UPDATE_INTR_SHADOW(pVCpu, pCtx) \
-    do { \
-        /* Update interrupt shadow. */ \
-        if (   VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS) \
-            && pCtx->rip != EMGetInhibitInterruptsPC(pVCpu)) \
-            VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS); \
-    } while (0)
+ * Returns whether decode-assist feature is supported.
+ *
+ * @param   pVCpu       The cross context virtual CPU structure.
+ * @param   pCtx        Pointer to the guest-CPU context.
+ */
+DECLINLINE(bool) hmR0SvmSupportsDecodeAssist(PVMCPU pVCpu, PCPUMCTX pCtx)
+{
+    PVM pVM = pVCpu->CTX_SUFF(pVM);
+#ifdef VBOX_WITH_NESTED_HWVIRT
+    if (CPUMIsGuestInSvmNestedHwVirtMode(pCtx))
+    {
+        return    (pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_DECODE_ASSIST)
+               &&  pVM->cpum.ro.GuestFeatures.fSvmDecodeAssist;
+    }
+#else
+    RT_NOREF(pCtx);
+#endif
+    return RT_BOOL(pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_DECODE_ASSIST);
+}
+
+
+/**
+ * Returns whether NRIP_SAVE feature is supported.
+ *
+ * @param   pVCpu       The cross context virtual CPU structure.
+ * @param   pCtx        Pointer to the guest-CPU context.
+ */
+DECLINLINE(bool) hmR0SvmSupportsNextRipSave(PVMCPU pVCpu, PCPUMCTX pCtx)
+{
+    PVM pVM = pVCpu->CTX_SUFF(pVM);
+#ifdef VBOX_WITH_NESTED_HWVIRT
+    if (CPUMIsGuestInSvmNestedHwVirtMode(pCtx))
+    {
+        return    (pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_NRIP_SAVE)
+               &&  pVM->cpum.ro.GuestFeatures.fSvmNextRipSave;
+    }
+#else
+    RT_NOREF(pCtx);
+#endif
+    return RT_BOOL(pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_NRIP_SAVE);
+}
 
 
@@ -5819,7 +5886,8 @@
 DECLINLINE(void) hmR0SvmAdvanceRipHwAssist(PVMCPU pVCpu, PCPUMCTX pCtx, uint32_t cb)
 {
-    if (pVCpu->CTX_SUFF(pVM)->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_NRIP_SAVE)
-    {
-        PCSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
+    bool const fSupportsNextRipSave = hmR0SvmSupportsNextRipSave(pVCpu, pCtx);
+    if (fSupportsNextRipSave)
+    {
+        PCSVMVMCB pVmcb = hmR0SvmGetCurrentVmcb(pVCpu, pCtx);
         Assert(pVmcb->ctrl.u64NextRIP);
         AssertRelease(pVmcb->ctrl.u64NextRIP - pCtx->rip == cb);    /* temporary, remove later */
@@ -5845,7 +5913,8 @@
 {
     Assert(cbLikely <= 15);   /* See Intel spec. 2.3.11 "AVX Instruction Length" */
-    if (pVCpu->CTX_SUFF(pVM)->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_NRIP_SAVE)
-    {
-        PCSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
+    bool const fSupportsNextRipSave = hmR0SvmSupportsNextRipSave(pVCpu, pCtx);
+    if (fSupportsNextRipSave)
+    {
+        PCSVMVMCB pVmcb = hmR0SvmGetCurrentVmcb(pVCpu, pCtx);
         uint8_t const cbInstr = pVmcb->ctrl.u64NextRIP - pCtx->rip;
         Assert(cbInstr == cbLikely);
@@ -6038,8 +6107,10 @@
     STAM_COUNTER_INC(&pVCpu->hm.s.StatExitInvlpg);
 
-    if (pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_DECODE_ASSIST)
-    {
-        Assert(pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_NRIP_SAVE);
-        PCSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
+    bool const fSupportsDecodeAssist = hmR0SvmSupportsDecodeAssist(pVCpu, pCtx);
+    bool const fSupportsNextRipSave  = hmR0SvmSupportsNextRipSave(pVCpu, pCtx);
+    if (   fSupportsDecodeAssist
+        && fSupportsNextRipSave)
+    {
+        PCSVMVMCB pVmcb = hmR0SvmGetCurrentVmcb(pVCpu, pCtx);
         uint8_t const cbInstr   = pVmcb->ctrl.u64NextRIP - pCtx->rip;
         RTGCPTR const GCPtrPage = pVmcb->ctrl.u64ExitInfo1;
@@ -6160,9 +6231,10 @@
     STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCRxRead[pSvmTransient->u64ExitCode - SVM_EXIT_READ_CR0]);
 
-    PVM pVM = pVCpu->CTX_SUFF(pVM);
-    if (pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_DECODE_ASSIST)
-    {
-        Assert(pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_NRIP_SAVE);
-        PCSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
+    bool const fSupportsDecodeAssist = hmR0SvmSupportsDecodeAssist(pVCpu, pCtx);
+    bool const fSupportsNextRipSave  = hmR0SvmSupportsNextRipSave(pVCpu, pCtx);
+    if (   fSupportsDecodeAssist
+        && fSupportsNextRipSave)
+    {
+        PCSVMVMCB pVmcb = hmR0SvmGetCurrentVmcb(pVCpu, pCtx);
         bool const fMovCRx = RT_BOOL(pVmcb->ctrl.u64ExitInfo1 & SVM_EXIT1_MOV_CRX_MASK);
         if (fMovCRx)
@@ -6199,10 +6271,12 @@
 
     VBOXSTRICTRC rcStrict = VERR_SVM_IPE_5;
-    PVM pVM = pVCpu->CTX_SUFF(pVM);
-    bool fDecodedInstr = false;
-    if (pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_DECODE_ASSIST)
-    {
-        Assert(pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_NRIP_SAVE);
-        PCSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
+    PVM          pVM = pVCpu->CTX_SUFF(pVM);
+    bool         fDecodedInstr = false;
+    bool const   fSupportsDecodeAssist = hmR0SvmSupportsDecodeAssist(pVCpu, pCtx);
+    bool const   fSupportsNextRipSave  = hmR0SvmSupportsNextRipSave(pVCpu, pCtx);
+    if (   fSupportsDecodeAssist
+        && fSupportsNextRipSave)
+    {
+        PCSVMVMCB pVmcb = hmR0SvmGetCurrentVmcb(pVCpu, pCtx);
         bool const fMovCRx = RT_BOOL(pVmcb->ctrl.u64ExitInfo1 & SVM_EXIT1_MOV_CRX_MASK);
         if (fMovCRx)
@@ -6267,5 +6341,5 @@
 {
     HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
-    PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
+    PSVMVMCB pVmcb = hmR0SvmGetCurrentVmcb(pVCpu, pCtx);
     PVM      pVM   = pVCpu->CTX_SUFF(pVM);
 
@@ -6293,5 +6367,6 @@
         }
 
-        if (pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_NRIP_SAVE)
+        bool const fSupportsNextRipSave = hmR0SvmSupportsNextRipSave(pVCpu, pCtx);
+        if (fSupportsNextRipSave)
         {
             rc = EMInterpretWrmsr(pVM, pVCpu, CPUMCTX2CORE(pCtx));
@@ -6341,5 +6416,6 @@
         Log4(("MSR Read: idMsr=%#RX32\n", pCtx->ecx));
 
-        if (pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_NRIP_SAVE)
+        bool const fSupportsNextRipSave = hmR0SvmSupportsNextRipSave(pVCpu, pCtx);
+        if (fSupportsNextRipSave)
         {
             rc = EMInterpretRdmsr(pVM, pVCpu, CPUMCTX2CORE(pCtx));
@@ -6366,5 +6442,5 @@
     }
 
-    /* RIP has been updated by EMInterpret[Rd|Wr]msr(). */
+    /* RIP has been updated by EMInterpret[Rd|Wr]msr() or EMInterpretInstruction(). */
     return rc;
 }
@@ -6488,5 +6564,5 @@
 
     PVM      pVM   = pVCpu->CTX_SUFF(pVM);
-    PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
+    PSVMVMCB pVmcb = hmR0SvmGetCurrentVmcb(pVCpu, pCtx);
 
     /* Refer AMD spec. 15.10.2 "IN and OUT Behaviour" and Figure 15-2. "EXITINFO1 for IOIO Intercept" for the format. */
@@ -6530,5 +6606,6 @@
                        only enabling it for Bulldozer and later with NRIP.  OS/2 broke on
                        2384 Opterons when only checking NRIP. */
-                    if (   (pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_NRIP_SAVE)
+                    bool const fSupportsNextRipSave = hmR0SvmSupportsNextRipSave(pVCpu, pCtx);
+                    if (   fSupportsNextRipSave
                         && pVM->cpum.ro.GuestFeatures.enmMicroarch >= kCpumMicroarch_AMD_15h_First)
                     {
@@ -6699,4 +6776,6 @@
 {
     HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
+    HMSVM_ASSERT_NOT_IN_NESTED_GUEST(pCtx);
+
     PVM pVM = pVCpu->CTX_SUFF(pVM);
     Assert(pVM->hm.s.fNestedPaging);
@@ -6808,6 +6887,7 @@
 {
     HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
-
-    PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
+    HMSVM_ASSERT_NOT_IN_NESTED_GUEST(pCtx);
+
+    PSVMVMCB pVmcb = hmR0SvmGetCurrentVmcb(pVCpu, pCtx);
     pVmcb->ctrl.IntCtrl.n.u1VIrqPending = 0;  /* No virtual interrupts pending, we'll inject the current one/NMI before reentry. */
     pVmcb->ctrl.IntCtrl.n.u8VIntrVector = 0;
@@ -6908,5 +6988,5 @@
 
     /* Indicate that we no longer need to #VMEXIT when the guest is ready to receive NMIs, it is now ready. */
-    PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
+    PSVMVMCB pVmcb = hmR0SvmGetCurrentVmcb(pVCpu, pCtx);
     hmR0SvmClearIretIntercept(pVmcb);
 
@@ -6923,4 +7003,5 @@
 {
     HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
+    HMSVM_ASSERT_NOT_IN_NESTED_GUEST(pCtx);
 
     HMSVM_CHECK_EXIT_DUE_TO_EVENT_DELIVERY();
@@ -7285,5 +7366,5 @@
 
     /* See AMD spec. 15.12.15 "#PF (Page Fault)". */
-    PSVMVMCB       pVmcb         = pVCpu->hm.s.svm.pVmcb;
+    PSVMVMCB       pVmcb         = hmR0SvmGetCurrentVmcb(pVCpu, pCtx);
     uint32_t       u32ErrCode    = pVmcb->ctrl.u64ExitInfo1;
     uint64_t const uFaultAddress = pVmcb->ctrl.u64ExitInfo2;
@@ -7451,23 +7532,4 @@
 
 /**
- * Nested-guest \#VMEXIT handler for IRET (SVM_EXIT_VMRUN). Conditional \#VMEXIT.
- */
-HMSVM_EXIT_DECL hmR0SvmNestedExitIret(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
-{
-    HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
-
-    /* Clear NMI blocking. */
-    VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_BLOCK_NMIS);
-
-    /* Indicate that we no longer need to #VMEXIT when the guest is ready to receive NMIs, it is now ready. */
-    PSVMVMCB pVmcbNstGst = pCtx->hwvirt.svm.CTX_SUFF(pVmcb);
-    hmR0SvmClearIretIntercept(pVmcbNstGst);
-
-    /* Deliver the pending NMI via hmR0SvmEvaluatePendingEventNested() and resume guest execution. */
-    return VINF_SUCCESS;
-}
-
-
-/**
  * Nested-guest \#VMEXIT handler for debug exceptions (SVM_EXIT_EXCEPTION_1).
  * Unconditional \#VMEXIT.
