Index: /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 74750)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 74751)
@@ -431,6 +431,6 @@
  * Invokes the VMX VM-exit handler for a task switch.
  */
-# define IEM_VMX_VMEXIT_TASK_SWITCH_RET(a_pVCpu, a_enmTaskSwitch, a_SelNewTss) \
-    do { return iemVmxVmexitTaskSwitch((a_pVCpu), (a_enmTaskSwitch), (a_SelNewTss)); } while (0)
+# define IEM_VMX_VMEXIT_TASK_SWITCH_RET(a_pVCpu, a_enmTaskSwitch, a_SelNewTss, a_cbInstr) \
+    do { return iemVmxVmexitTaskSwitch((a_pVCpu), (a_enmTaskSwitch), (a_SelNewTss), (a_cbInstr)); } while (0)
 
 /**
@@ -440,14 +440,21 @@
     do { return iemVmxVmexitInstrMwait((a_pVCpu), (a_fMonitorArmed), (a_cbInstr)); } while (0)
 
+/**
+ * Invokes the VMX VM-exit handle for triple faults.
+ */
+# define IEM_VMX_VMEXIT_TRIPLE_FAULT_RET(a_pVCpu) \
+    do { return iemVmxVmexitTripleFault(a_pVCpu); } while (0)
+
 #else
-# define IEM_VMX_IS_ROOT_MODE(a_pVCpu)                                  (false)
-# define IEM_VMX_IS_NON_ROOT_MODE(a_pVCpu)                              (false)
-# define IEM_VMX_IS_PINCTLS_SET(a_pVCpu, a_cbInstr)                     (false)
-# define IEM_VMX_IS_PROCCTLS_SET(a_pVCpu, a_cbInstr)                    (false)
-# define IEM_VMX_IS_PROCCTLS2_SET(a_pVCpu, a_cbInstr)                   (false)
+# define IEM_VMX_IS_ROOT_MODE(a_pVCpu)                                          (false)
+# define IEM_VMX_IS_NON_ROOT_MODE(a_pVCpu)                                      (false)
+# define IEM_VMX_IS_PINCTLS_SET(a_pVCpu, a_cbInstr)                             (false)
+# define IEM_VMX_IS_PROCCTLS_SET(a_pVCpu, a_cbInstr)                            (false)
+# define IEM_VMX_IS_PROCCTLS2_SET(a_pVCpu, a_cbInstr)                           (false)
 # define IEM_VMX_VMEXIT_INSTR_RET(a_pVCpu, a_uExitReason, a_cbInstr)            do { return VERR_VMX_IPE_1; } while (0)
-# define IEM_VMX_VMEXIT_INSTR_NEEDS_INFO_RET(a_pVCpu, a_uExitReason, a_uInstrId, a_cbInstr)     do { return VERR_VMX_IPE_1; } while (0)
-# define IEM_VMX_VMEXIT_TASK_SWITCH_RET(a_pVCpu, a_enmTaskSwitch, a_SelNewTss)  do { return VERR_VMX_IPE_1; } while (0)
+# define IEM_VMX_VMEXIT_INSTR_NEEDS_INFO_RET(a_pVCpu, a_uExitReason, a_uInstrId, a_cbInstr)  do { return VERR_VMX_IPE_1; } while (0)
+# define IEM_VMX_VMEXIT_TASK_SWITCH_RET(a_pVCpu, a_enmTaskSwitch, a_SelNewTss, a_cbInstr)    do { return VERR_VMX_IPE_1; } while (0)
 # define IEM_VMX_VMEXIT_MWAIT_RET(a_pVCpu, a_fMonitorArmed, a_cbInstr)          do { return VERR_VMX_IPE_1; } while (0)
+# define IEM_VMX_VMEXIT_TRIPLE_FAULT_RET(a_pVCpu)                               do { return VERR_VMX_IPE_1; } while (0)
 
 #endif
@@ -967,11 +974,14 @@
 
 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX
-IEM_STATIC VBOXSTRICTRC     iemVmxVmexitTaskSwitch(PVMCPU pVCpu, IEMTASKSWITCH enmTaskSwitch, RTSEL SelNewTss);
-IEM_STATIC VBOXSTRICTRC     iemVmxVmexitEvent(PVMCPU pVCpu, uint8_t uVector, uint32_t fFlags, uint32_t uErrCode, uint64_t uCr2);
+IEM_STATIC VBOXSTRICTRC     iemVmxVmexitTaskSwitch(PVMCPU pVCpu, IEMTASKSWITCH enmTaskSwitch, RTSEL SelNewTss, uint8_t cbInstr);
+IEM_STATIC VBOXSTRICTRC     iemVmxVmexitEvent(PVMCPU pVCpu, uint8_t uVector, uint32_t fFlags, uint32_t uErrCode, uint64_t uCr2,
+                                              uint8_t cbInstr);
+IEM_STATIC VBOXSTRICTRC     iemVmxVmexitTripleFault(PVMCPU pVCpu);
 #endif
 
 #ifdef VBOX_WITH_NESTED_HWVIRT_SVM
 IEM_STATIC VBOXSTRICTRC     iemSvmVmexit(PVMCPU pVCpu, uint64_t uExitCode, uint64_t uExitInfo1, uint64_t uExitInfo2);
-IEM_STATIC VBOXSTRICTRC     iemHandleSvmEventIntercept(PVMCPU pVCpu, uint8_t u8Vector, uint32_t fFlags, uint32_t uErr, uint64_t uCr2);
+IEM_STATIC VBOXSTRICTRC     iemHandleSvmEventIntercept(PVMCPU pVCpu, uint8_t u8Vector, uint32_t fFlags, uint32_t uErr,
+                                                       uint64_t uCr2);
 #endif
 
@@ -3464,4 +3474,7 @@
 IEM_STATIC VBOXSTRICTRC iemInitiateCpuShutdown(PVMCPU pVCpu)
 {
+    if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
+        IEM_VMX_VMEXIT_TRIPLE_FAULT_RET(pVCpu);
+
     if (IEM_SVM_IS_CTRL_INTERCEPT_SET(pVCpu, SVM_CTRL_INTERCEPT_SHUTDOWN))
     {
@@ -4043,5 +4056,5 @@
     {
         Log(("iemTaskSwitch: Guest intercept (source=%u, sel=%#x) -> VM-exit.\n", enmTaskSwitch, SelTSS));
-        IEM_VMX_VMEXIT_TASK_SWITCH_RET(pVCpu, enmTaskSwitch, SelTSS);
+        IEM_VMX_VMEXIT_TASK_SWITCH_RET(pVCpu, enmTaskSwitch, SelTSS, uNextEip - pVCpu->cpum.GstCtx.eip);
     }
 
@@ -5514,5 +5527,5 @@
     if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
     {
-        VBOXSTRICTRC rcStrict0 = iemVmxVmexitEvent(pVCpu, u8Vector, fFlags, uErr, uCr2);
+        VBOXSTRICTRC rcStrict0 = iemVmxVmexitEvent(pVCpu, u8Vector, fFlags, uErr, uCr2, cbInstr);
         if (rcStrict0 != VINF_VMX_INTERCEPT_NOT_ACTIVE)
             return rcStrict0;
@@ -5579,4 +5592,5 @@
             u8Vector = X86_XCPT_DF;
             uErr     = 0;
+            /** @todo NSTVMX: Do we need to do something here for VMX? */
             /* SVM nested-guest #DF intercepts need to be checked now. See AMD spec. 15.12 "Exception Intercepts". */
             if (IEM_SVM_IS_XCPT_INTERCEPT_SET(pVCpu, X86_XCPT_DF))
Index: /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h	(revision 74750)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h	(revision 74751)
@@ -19,7 +19,5 @@
 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX
 /** @todo NSTVMX: The following VM-exit intercepts are pending:
- *  VMX_EXIT_XCPT_OR_NMI
- *  VMX_EXIT_EXT_INT
- *  VMX_EXIT_TRIPLE_FAULT
+ *  VMX_EXIT_EXT_INT ("acknowledge interrupt on exit" behavior pending)
  *  VMX_EXIT_INIT_SIGNAL
  *  VMX_EXIT_SIPI
@@ -3547,26 +3545,36 @@
  * @param   enmTaskSwitch   The cause of the task switch.
  * @param   SelNewTss       The selector of the new TSS.
- */
-IEM_STATIC VBOXSTRICTRC iemVmxVmexitTaskSwitch(PVMCPU pVCpu, IEMTASKSWITCH enmTaskSwitch, RTSEL SelNewTss)
-{
-    /*
-     * Task-switch VM-exits are unconditional and only provide the
-     * VM-exit qualification.
+ * @param   cbInstr         The instruction length in bytes.
+ */
+IEM_STATIC VBOXSTRICTRC iemVmxVmexitTaskSwitch(PVMCPU pVCpu, IEMTASKSWITCH enmTaskSwitch, RTSEL SelNewTss, uint8_t cbInstr)
+{
+    /*
+     * Task-switch VM-exits are unconditional and provide the VM-exit qualification.
+     *
+     * If the the cause of the task switch is due to execution of CALL, IRET or the JMP
+     * instruction or delivery of the exception generated by one of these instructions
+     * lead to a task switch through a task gate in the IDT, we need to provide the
+     * VM-exit instruction length. Any other means of invoking a task switch VM-exit
+     * leaves the VM-exit instruction length field undefined.
      *
      * See Intel spec. 25.2 "Other Causes Of VM Exits".
-     */
-    uint32_t uTaskSwitchSrc;
+     * See Intel spec. 27.2.4 "Information for VM Exits Due to Instruction Execution".
+     */
+    Assert(cbInstr <= 15);
+
+    uint8_t uType;
     switch (enmTaskSwitch)
     {
-        case IEMTASKSWITCH_CALL:     uTaskSwitchSrc = 0; break;
-        case IEMTASKSWITCH_IRET:     uTaskSwitchSrc = 1; break;
-        case IEMTASKSWITCH_JUMP:     uTaskSwitchSrc = 2; break;
-        case IEMTASKSWITCH_INT_XCPT: uTaskSwitchSrc = 3; break;
+        case IEMTASKSWITCH_CALL:        uType = VMX_EXIT_QUAL_TASK_SWITCH_TYPE_CALL; break;
+        case IEMTASKSWITCH_IRET:        uType = VMX_EXIT_QUAL_TASK_SWITCH_TYPE_IRET; break;
+        case IEMTASKSWITCH_JUMP:        uType = VMX_EXIT_QUAL_TASK_SWITCH_TYPE_JMP;  break;
+        case IEMTASKSWITCH_INT_XCPT:    uType = VMX_EXIT_QUAL_TASK_SWITCH_TYPE_IDT;  break;
         IEM_NOT_REACHED_DEFAULT_CASE_RET();
     }
 
     uint64_t const uExitQual = RT_BF_MAKE(VMX_BF_EXIT_QUAL_TASK_SWITCH_NEW_TSS, SelNewTss)
-                             | RT_BF_MAKE(VMX_BF_EXIT_QUAL_TASK_SWITCH_SOURCE,  uTaskSwitchSrc);
+                             | RT_BF_MAKE(VMX_BF_EXIT_QUAL_TASK_SWITCH_SOURCE,  uType);
     iemVmxVmcsSetExitQual(pVCpu, uExitQual);
+    iemVmxVmcsSetExitInstrLen(pVCpu, cbInstr);
     return iemVmxVmexit(pVCpu, VMX_EXIT_TASK_SWITCH);
 }
@@ -3582,6 +3590,8 @@
  * @param   uErrCode    The error code associated with the event.
  * @param   uCr2        The CR2 value in case of a \#PF exception.
- */
-IEM_STATIC VBOXSTRICTRC iemVmxVmexitEvent(PVMCPU pVCpu, uint8_t uVector, uint32_t fFlags, uint32_t uErrCode, uint64_t uCr2)
+ * @param   cbInstr     The instruction length in bytes.
+ */
+IEM_STATIC VBOXSTRICTRC iemVmxVmexitEvent(PVMCPU pVCpu, uint8_t uVector, uint32_t fFlags, uint32_t uErrCode, uint64_t uCr2,
+                                          uint8_t cbInstr)
 {
     PCVMXVVMCS pVmcs = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
@@ -3689,4 +3699,16 @@
         iemVmxVmcsSetExitIntErrCode(pVCpu, uErrCode);
         iemVmxVmcsSetExitQual(pVCpu, uExitQual);
+
+        /*
+         * For VM exits due to software exceptions (those generated by INT3 or INTO) or privileged
+         * software exceptions (those generated by INT1/ICEBP) we need to supply the VM-exit instruction
+         * length.
+         */
+        if (   (fFlags & IEM_XCPT_FLAGS_T_SOFT_INT)
+            && (fFlags & (IEM_XCPT_FLAGS_BP_INSTR | IEM_XCPT_FLAGS_OF_INSTR | IEM_XCPT_FLAGS_ICEBP_INSTR)))
+            iemVmxVmcsSetExitInstrLen(pVCpu, cbInstr);
+        else
+            iemVmxVmcsSetExitInstrLen(pVCpu, 0);
+
         return iemVmxVmexit(pVCpu, uExitReason);
     }
@@ -3712,4 +3734,19 @@
     ExitInfo.u64Qual = fMonitorHwArmed;
     return iemVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
+}
+
+
+/**
+ * VMX VM-exit handler for VM-exits due to a triple fault.
+ *
+ * @returns VBox strict status code.
+ * @param   pVCpu               The cross context virtual CPU structure.
+ */
+IEM_STATIC VBOXSTRICTRC iemVmxVmexitTripleFault(PVMCPU pVCpu)
+{
+    PCVMXVVMCS pVmcs = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
+    Assert(pVmcs);
+    iemVmxVmcsSetExitQual(pVCpu, 0);
+    return iemVmxVmexit(pVCpu, VMX_EXIT_TRIPLE_FAULT);
 }
 
