Index: trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 48249)
+++ trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 48250)
@@ -316,4 +316,5 @@
 static void               hmR0VmxFlushEpt(PVMCPU pVCpu, VMX_FLUSH_EPT enmFlush);
 static void               hmR0VmxFlushVpid(PVM pVM, PVMCPU pVCpu, VMX_FLUSH_VPID enmFlush, RTGCPTR GCPtr);
+static void               hmR0VmxClearEventVmcs(PVMCPU pVCpu, PCPUMCTX pMixedCtx);
 static int                hmR0VmxInjectEventVmcs(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint64_t u64IntrInfo, uint32_t cbInstr,
                                                  uint32_t u32ErrCode, RTGCUINTREG GCPtrFaultAddress, uint32_t *puIntrState);
@@ -6475,9 +6476,10 @@
  *                          out-of-sync. Make sure to update the required fields
  *                          before using them.
- *
- * @remarks No-long-jump zone!!!
  */
 static int hmR0VmxInjectPendingEvent(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
 {
+    HMVMX_ASSERT_PREEMPT_SAFE();
+    Assert(VMMRZCallRing3IsEnabled(pVCpu));
+
     /* Get the current interruptibility-state of the guest and then figure out what can be injected. */
     uint32_t uIntrState = hmR0VmxGetGuestIntrState(pVCpu, pMixedCtx);
@@ -6515,6 +6517,4 @@
                                     pVCpu->hm.s.Event.u32ErrCode, pVCpu->hm.s.Event.GCPtrFaultAddress, &uIntrState);
         AssertRCReturn(rc, rc);
-
-        pVCpu->hm.s.Event.fPending = false;
 
         /* Update the interruptibility-state as it could have been changed by
@@ -6733,6 +6733,6 @@
  *                              necessary. This cannot not be NULL.
  *
+ * @remarks Requires CR0!
  * @remarks No-long-jump zone!!!
- * @remarks Requires CR0!
  */
 static int hmR0VmxInjectEventVmcs(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint64_t u64IntrInfo, uint32_t cbInstr,
@@ -6872,4 +6872,8 @@
                 }
                 Log4(("Injecting real-mode: u32IntrInfo=%#x u32ErrCode=%#x instrlen=%#x\n", u32IntrInfo, u32ErrCode, cbInstr));
+
+                /* The event has been truly dispatched. Mark it as no longer pending so we don't attempt to 'undo'
+                   it, if we are returning to ring-3 before executing guest code. */
+                pVCpu->hm.s.Event.fPending = false;
             }
             Assert(rc == VINF_SUCCESS || rc == VINF_EM_RESET);
@@ -6908,4 +6912,36 @@
     AssertRCReturn(rc, rc);
     return rc;
+}
+
+
+/**
+ * Clears the current event in the VMCS.
+ *
+ * @returns VBox status code.
+ * @param   pVCpu         Pointer to the VMCPU.
+ *
+ * @remarks Use this function only to clear events that have not yet been
+ *          delivered to the guest but are injected in the VMCS!
+ * @remarks No-long-jump zone!!!
+ */
+static void hmR0VmxClearEventVmcs(PVMCPU pVCpu)
+{
+    if (!pVCpu->hm.s.Event.fPending)
+        return;
+
+#ifdef VBOX_STRICT
+    uint32_t u32EntryInfo;
+    int rc2 = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &u32EntryInfo);
+    AssertRC(rc2);
+    Assert(VMX_ENTRY_INTERRUPTION_INFO_VALID(u32EntryInfo));
+#endif
+
+    /* Clear the entry-interruption field (including the valid bit). */
+    int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, 0);
+    AssertRC(rc);
+
+    /* Clear the pending debug exception field. */
+    rc = VMXWriteVmcs32(VMX_VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS, 0);
+    AssertRC(rc);
 }
 
@@ -7350,4 +7386,15 @@
     else if (!pVCpu->hm.s.Event.fPending)
         hmR0VmxEvaluatePendingEvent(pVCpu, pMixedCtx);
+
+    /*
+     * Event injection may take locks (currently the PGM lock for real-on-v86 case) and thus needs to be done with
+     * longjmps or interrupts + preemption enabled. Event injection might also result in triple-faulting the VM.
+     */
+    rc = hmR0VmxInjectPendingEvent(pVCpu, pMixedCtx);
+    if (RT_UNLIKELY(rc != VINF_SUCCESS))
+    {
+        Assert(rc == VINF_EM_RESET);
+        return rc;
+    }
 
     /*
@@ -7372,4 +7419,5 @@
         || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
     {
+        hmR0VmxClearEventVmcs(pVCpu);
         ASMSetFlags(pVmxTransient->uEflags);
         VMMRZCallRing3Enable(pVCpu);
@@ -7379,4 +7427,5 @@
     if (RTThreadPreemptIsPending(NIL_RTTHREAD))
     {
+        hmR0VmxClearEventVmcs(pVCpu);
         ASMSetFlags(pVmxTransient->uEflags);
         VMMRZCallRing3Enable(pVCpu);
@@ -7385,15 +7434,6 @@
     }
 
-    /*
-     * Event injection might result in triple-faulting the VM (real-on-v86 case), which is why it's
-     * done here and not in hmR0VmxPreRunGuestCommitted() which doesn't expect failures.
-     */
-    rc = hmR0VmxInjectPendingEvent(pVCpu, pMixedCtx);
-    if (RT_UNLIKELY(rc != VINF_SUCCESS))
-    {
-        ASMSetFlags(pVmxTransient->uEflags);
-        VMMRZCallRing3Enable(pVCpu);
-        return rc;
-    }
+    /* We've injected any pending events. This is really the point of no return (to ring-3). */
+    pVCpu->hm.s.Event.fPending = false;
 
     return VINF_SUCCESS;
