Index: /trunk/include/VBox/vmm/vm.h
===================================================================
--- /trunk/include/VBox/vmm/vm.h	(revision 75630)
+++ /trunk/include/VBox/vmm/vm.h	(revision 75631)
@@ -569,5 +569,6 @@
 #define VMCPU_FF_EXTERNAL_HALTED_MASK           (  VMCPU_FF_UPDATE_APIC | VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC \
                                                  | VMCPU_FF_REQUEST     | VMCPU_FF_INTERRUPT_NMI  | VMCPU_FF_INTERRUPT_SMI \
-                                                 | VMCPU_FF_UNHALT      | VMCPU_FF_TIMER          | VMCPU_FF_DBGF )
+                                                 | VMCPU_FF_UNHALT      | VMCPU_FF_TIMER          | VMCPU_FF_DBGF \
+                                                 | VMCPU_FF_INTERRUPT_NESTED_GUEST)
 
 /** High priority VM pre-execution actions. */
Index: /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 75630)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 75631)
@@ -16044,22 +16044,29 @@
     RT_NOREF4(pVM, pvPhys, enmOrigin, pvUser);
 
-    Assert(CPUMIsGuestInVmxNonRootMode(IEM_GET_CTX(pVCpu)));
-    Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, IEM_GET_CTX(pVCpu), VMX_PROC_CTLS2_VIRT_APIC_ACCESS));
-
-#ifdef VBOX_STRICT
-    RTGCPHYS const GCPhysApicBase   = CPUMGetGuestVmxApicAccessPageAddr(pVCpu, IEM_GET_CTX(pVCpu));
     RTGCPHYS const GCPhysAccessBase = GCPhysFault & ~(RTGCPHYS)PAGE_OFFSET_MASK;
-    Assert(GCPhysApicBase == GCPhysAccessBase);
-#endif
-
-    uint16_t const offAccess = GCPhysFault & PAGE_OFFSET_MASK;
-    uint32_t const fAccess   = enmAccessType == PGMACCESSTYPE_WRITE ? IEM_ACCESS_TYPE_WRITE : IEM_ACCESS_TYPE_READ;
-
-    VBOXSTRICTRC rcStrict = iemVmxVirtApicAccessMem(pVCpu, offAccess, cbBuf, pvBuf, fAccess);
-    if (RT_FAILURE(rcStrict))
-        return rcStrict;
-
-    /* Any access on this APIC-access page has been handled, caller should not carry out the access. */
-    return VINF_SUCCESS;
+    if (CPUMIsGuestInVmxNonRootMode(IEM_GET_CTX(pVCpu)))
+    {
+        Assert(CPUMIsGuestVmxProcCtls2Set(pVCpu, IEM_GET_CTX(pVCpu), VMX_PROC_CTLS2_VIRT_APIC_ACCESS));
+        Assert(CPUMGetGuestVmxApicAccessPageAddr(pVCpu, IEM_GET_CTX(pVCpu)) == GCPhysAccessBase);
+
+        /** @todo NSTVMX: How are we to distinguish instruction fetch accesses here?
+         *        Currently they will go through as read accesses. */
+        uint32_t const fAccess   = enmAccessType == PGMACCESSTYPE_WRITE ? IEM_ACCESS_TYPE_WRITE : IEM_ACCESS_TYPE_READ;
+        uint16_t const offAccess = GCPhysFault & PAGE_OFFSET_MASK;
+        VBOXSTRICTRC rcStrict = iemVmxVirtApicAccessMem(pVCpu, offAccess, cbBuf, pvBuf, fAccess);
+        if (RT_FAILURE(rcStrict))
+            return rcStrict;
+
+        /* Any access on this APIC-access page has been handled, caller should not carry out the access. */
+        return VINF_SUCCESS;
+    }
+
+    Log(("iemVmxApicAccessPageHandler: Access outside VMX non-root mode, deregistering page at %#RGp\n", GCPhysAccessBase));
+    int rc = PGMHandlerPhysicalDeregister(pVM, GCPhysAccessBase);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    /* Instruct the caller of this handler to perform the read/write as normal memory. */
+    return VINF_PGM_HANDLER_DO_DEFAULT;
 }
 
Index: /trunk/src/VBox/VMM/VMMAll/IEMAllCImpl.cpp.h
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAllCImpl.cpp.h	(revision 75630)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAllCImpl.cpp.h	(revision 75631)
@@ -5912,4 +5912,5 @@
                  */
                 uint32_t const uTpr = (uNewCrX & 0xf) << 4;
+                Log(("iemCImpl_load_Cr%#x: Virtualizing TPR (%#x) write\n", iCrReg, uTpr));
                 iemVmxVirtApicWriteRaw32(pVCpu, XAPIC_OFF_TPR, uTpr);
                 iemVmxVirtApicSetPendingWrite(pVCpu, XAPIC_OFF_TPR);
Index: /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h	(revision 75630)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h	(revision 75631)
@@ -2182,5 +2182,4 @@
              *
              * If Delta >= VmcsPreemptTimer * RT_BIT(PreemptTimerShift) cause a VMX-preemption timer VM-exit.
-             *
              * The saved VMX-preemption timer value is calculated as follows:
              * PreemptTimerVal = VmcsPreemptTimer - (Delta / (VmcsPreemptTimer * RT_BIT(PreemptTimerShift)))
@@ -2750,20 +2749,4 @@
     /* Clear address range monitoring. */
     EMMonitorWaitClear(pVCpu);
-
-    /* De-register the handler for the APIC-access page. */
-    if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
-    {
-        PVM pVM = pVCpu->CTX_SUFF(pVM);
-        RTGCPHYS const GCPhysApicAccess = pVmcs->u64AddrApicAccess.u;
-        if (PGMHandlerPhysicalIsRegistered(pVM, GCPhysApicAccess))
-        {
-            /** @todo NSTVMX: This is broken! We cannot simply deregister the handler for the
-             *        physical address as other VCPUs executing other nested-VCPUs might have
-             *        it registered! */
-            int rc = PGMHandlerPhysicalDeregister(pVM, GCPhysApicAccess);
-            if (RT_FAILURE(rc))
-                return rc;
-        }
-    }
 
     /* Perform the VMX transition (PGM updates). */
@@ -4638,6 +4621,17 @@
     Assert(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY);
 
-    /** @todo NSTVMX: evaluate pending virtual interrupts. */
-    RT_NOREF(pVCpu);
+    if (!(pVmcs->u32ProcCtls & VMX_PROC_CTLS_INT_WINDOW_EXIT))
+    {
+        uint8_t const uRvi = RT_LO_U8(pVmcs->u16GuestIntStatus);
+        uint8_t const uPpr = iemVmxVirtApicReadRaw32(pVCpu, XAPIC_OFF_PPR);
+
+        if ((uRvi >> 4) > (uPpr >> 4))
+        {
+            Log2(("eval_virt_intrs: uRvi=%#x uPpr=%#x - Signaling pending interrupt\n", uRvi, uPpr));
+            VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST);
+        }
+        else
+            Log2(("eval_virt_intrs: uRvi=%#x uPpr=%#x - Nothing to do\n", uRvi, uPpr));
+    }
 }
 
@@ -4663,13 +4657,14 @@
      */
     uint32_t const uTpr = iemVmxVirtApicReadRaw32(pVCpu, XAPIC_OFF_TPR);
-    uint32_t const uSvi  = RT_HI_U8(pVmcs->u16GuestIntStatus);
-
-    uint32_t uVPpr;
+    uint32_t const uSvi = RT_HI_U8(pVmcs->u16GuestIntStatus);
+
+    uint32_t uPpr;
     if (((uTpr >> 4) & 0xf) >= ((uSvi >> 4) & 0xf))
-        uVPpr = uTpr & 0xff;
+        uPpr = uTpr & 0xff;
     else
-        uVPpr = uSvi & 0xf0;
-    iemVmxVirtApicWriteRaw32(pVCpu, XAPIC_OFF_PPR, uVPpr);
-    Log2(("ppr_virt: uTpr=%u uSvi=%u -> VM-exit\n", uTpr, uSvi));
+        uPpr = uSvi & 0xf0;
+
+    Log2(("ppr_virt: uTpr=%#x uSvi=%#x uPpr=%#x\n", uTpr, uSvi, uPpr));
+    iemVmxVirtApicWriteRaw32(pVCpu, XAPIC_OFF_PPR, uPpr);
 }
 
@@ -4763,4 +4758,5 @@
     uint8_t const uRvi = RT_LO_U8(pVmcs->u16GuestIntStatus);
     uint8_t const uSvi = RT_HI_U8(pVmcs->u16GuestIntStatus);
+    Log2(("eoi_virt: uRvi=%#x uSvi=%#x\n", uRvi, uSvi));
 
     uint8_t uVector = uSvi;
@@ -4769,4 +4765,9 @@
     uVector = 0;
     iemVmxVirtApicGetHighestSetBitInReg(pVCpu, XAPIC_OFF_ISR0, &uVector);
+
+    if (uVector)
+        Log2(("eoi_virt: next interrupt %#x\n", uVector));
+    else
+        Log2(("eoi_virt: no interrupt pending in ISR\n"));
 
     /* Update guest-interrupt status SVI (leave RVI portion as it is) in the VMCS. */
@@ -4799,6 +4800,6 @@
      * See Intel spec. 29.1.5 "Self-IPI Virtualization".
      */
-    uint8_t const uVector = iemVmxVirtApicReadRaw32(pVCpu, X2APIC_OFF_SELF_IPI);
-
+    uint8_t const uVector = iemVmxVirtApicReadRaw32(pVCpu, XAPIC_OFF_ICR_LO);
+    Log2(("self_ipi_virt: uVector=%#x\n", uVector));
     iemVmxVirtApicSetVector(pVCpu, XAPIC_OFF_IRR0, uVector);
     uint8_t const uRvi = RT_LO_U8(pVmcs->u16GuestIntStatus);
@@ -4837,4 +4838,5 @@
             uTpr         &= UINT32_C(0x000000ff);
             iemVmxVirtApicWriteRaw32(pVCpu, XAPIC_OFF_TPR, uTpr);
+            Log2(("iemVmxApicWriteEmulation: TPR write %#x\n", uTpr));
             rcStrict = iemVmxTprVirtualization(pVCpu);
             break;
@@ -4847,4 +4849,5 @@
                 /* Clear VEOI and perform EOI virtualization. */
                 iemVmxVirtApicWriteRaw32(pVCpu, XAPIC_OFF_EOI, 0);
+                Log2(("iemVmxApicWriteEmulation: EOI write\n"));
                 rcStrict = iemVmxEoiVirtualization(pVCpu);
             }
@@ -4864,5 +4867,8 @@
                 if (   !(uIcrLo & fIcrLoMb0)
                     &&  (uIcrLo & fIcrLoMb1))
+                {
+                    Log2(("iemVmxApicWriteEmulation: Self-IPI virtualization with vector %#x\n", (uIcrLo & 0xff)));
                     rcStrict = iemVmxSelfIpiVirtualization(pVCpu);
+                }
                 else
                     rcStrict = iemVmxVmexitApicWrite(pVCpu, offApicWrite);
@@ -6403,5 +6409,17 @@
         }
 
-        /* Register the handler for the APIC-access page. */
+        /*
+         * Register the handler for the APIC-access page.
+         *
+         * We don't deregister the APIC-access page handler during the VM-exit as a different
+         * nested-VCPU might be using the same guest-physical address for its APIC-access page.
+         *
+         * We leave the page registered until the first access that happens outside VMX non-root
+         * mode. Guest software is allowed to access structures such as the APIC-access page
+         * only when no logical processor with a current VMCS references it in VMX non-root mode,
+         * otherwise it can lead to unpredictable behavior including guest triple-faults.
+         *
+         * See Intel spec. 24.11.4 "Software Access to Related Structures".
+         */
         int rc = PGMHandlerPhysicalRegister(pVCpu->CTX_SUFF(pVM), GCPhysApicAccess, GCPhysApicAccess,
                                             pVCpu->iem.s.hVmxApicAccessPage, NIL_RTR3PTR /* pvUserR3 */,
