Index: trunk/include/VBox/vmm/hm_vmx.h
===================================================================
--- trunk/include/VBox/vmm/hm_vmx.h	(revision 74682)
+++ trunk/include/VBox/vmm/hm_vmx.h	(revision 74683)
@@ -2687,4 +2687,16 @@
 /** Task switch caused by an interrupt gate. */
 #define VMX_EXIT_QUAL_TASK_SWITCH_TYPE_IDT                      3
+
+/** Bit fields for Exit qualification for task switches. */
+#define VMX_BF_EXIT_QUAL_TASK_SWITCH_NEW_TSS_SHIFT              0
+#define VMX_BF_EXIT_QUAL_TASK_SWITCH_NEW_TSS_MASK               UINT64_C(0x000000000000ffff)
+#define VMX_BF_EXIT_QUAL_TASK_SWITCH_RSVD_16_29_SHIFT           16
+#define VMX_BF_EXIT_QUAL_TASK_SWITCH_RSVD_16_29_MASK            UINT64_C(0x000000003fff0000)
+#define VMX_BF_EXIT_QUAL_TASK_SWITCH_SOURCE_SHIFT               30
+#define VMX_BF_EXIT_QUAL_TASK_SWITCH_SOURCE_MASK                UINT64_C(0x00000000c0000000)
+#define VMX_BF_EXIT_QUAL_TASK_SWITCH_RSVD_32_63_SHIFT           32
+#define VMX_BF_EXIT_QUAL_TASK_SWITCH_RSVD_32_63_MASK            UINT64_C(0xffffffff00000000)
+RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_QUAL_TASK_SWITCH_, UINT64_C(0), UINT64_MAX,
+                            (NEW_TSS, RSVD_16_29, SOURCE, RSVD_32_63));
 /** @} */
 
Index: trunk/src/VBox/VMM/VMMAll/IEMAll.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 74682)
+++ trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 74683)
@@ -397,4 +397,23 @@
 
 /**
+ * Check if the nested-guest has the given Pin-based VM-execution control set.
+ */
+# define IEM_VMX_IS_PINCTLS_SET(a_pVCpu, a_PinCtl) \
+    (CPUMIsGuestVmxPinCtlsSet((a_pVCpu), IEM_GET_CTX(a_pVCpu), (a_PinCtl)))
+
+/**
+ * Check if the nested-guest has the given Processor-based VM-execution control set.
+ */
+#define IEM_VMX_IS_PROCCTLS_SET(a_pVCpu, a_ProcCtl) \
+    (CPUMIsGuestVmxProcCtlsSet((a_pVCpu), IEM_GET_CTX(a_pVCpu), (a_ProcCtl)))
+
+/**
+ * Check if the nested-guest has the given Secondary Processor-based VM-execution
+ * control set.
+ */
+#define IEM_VMX_IS_PROCCTLS2_SET(a_pVCpu, a_ProcCtl2) \
+    (CPUMIsGuestVmxProcCtls2Set((a_pVCpu), IEM_GET_CTX(a_pVCpu), (a_ProcCtl2)))
+
+/**
  * Invokes the VMX VM-exit handler for an instruction intercept.
  */
@@ -410,21 +429,8 @@
 
 /**
- * Check if the nested-guest has the given Pin-based VM-execution control set.
- */
-# define IEM_VMX_IS_PINCTLS_SET(a_pVCpu, a_PinCtl) \
-    (CPUMIsGuestVmxPinCtlsSet((a_pVCpu), IEM_GET_CTX(a_pVCpu), (a_PinCtl)))
-
-/**
- * Check if the nested-guest has the given Processor-based VM-execution control set.
- */
-#define IEM_VMX_IS_PROCCTLS_SET(a_pVCpu, a_ProcCtl) \
-    (CPUMIsGuestVmxProcCtlsSet((a_pVCpu), IEM_GET_CTX(a_pVCpu), (a_ProcCtl)))
-
-/**
- * Check if the nested-guest has the given Secondary Processor-based VM-execution
- * control set.
- */
-#define IEM_VMX_IS_PROCCTLS2_SET(a_pVCpu, a_ProcCtl2) \
-    (CPUMIsGuestVmxProcCtls2Set((a_pVCpu), IEM_GET_CTX(a_pVCpu), (a_ProcCtl2)))
+ * 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)
 
 #else
@@ -434,5 +440,6 @@
 # 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_TASK_SWITCH_RET(a_pVCpu, a_enmTaskSwitch, a_SelNewTss)  do { return VERR_VMX_IPE_1; } while (0)
+# 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)
 
@@ -951,4 +958,8 @@
 IEM_STATIC uint16_t         iemSRegFetchU16(PVMCPU pVCpu, uint8_t iSegReg);
 IEM_STATIC uint64_t         iemSRegBaseFetchU64(PVMCPU pVCpu, uint8_t iSegReg);
+
+#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
+IEM_STATIC VBOXSTRICTRC     iemVmxVmexitTaskSwitch(PVMCPU pVCpu, IEMTASKSWITCH enmTaskSwitch, RTSEL SelNewTss);
+#endif
 
 #ifdef VBOX_WITH_NESTED_HWVIRT_SVM
@@ -3961,5 +3972,5 @@
  * @returns VBox strict status code.
  * @param   pVCpu           The cross context virtual CPU structure of the calling thread.
- * @param   enmTaskSwitch   What caused this task switch.
+ * @param   enmTaskSwitch   The cause of the task switch.
  * @param   uNextEip        The EIP effective after the task switch.
  * @param   fFlags          The flags, see IEM_XCPT_FLAGS_XXX.
@@ -4012,4 +4023,17 @@
              enmTaskSwitch, uNewTSSLimit, uNewTSSLimitMin));
         return iemRaiseTaskSwitchFaultWithErr(pVCpu, SelTSS & X86_SEL_MASK_OFF_RPL);
+    }
+
+    /*
+     * Task switches in VMX non-root mode always cause task switches.
+     * The new TSS must have been read and validated (DPL, limits etc.) before a
+     * task-switch VM-exit commences.
+     *
+     * See Intel spec. 25.4.2 ".Treatment of Task Switches"
+     */
+    if (IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
+    {
+        Log(("iemTaskSwitch: Guest intercept (source=%u, sel=%#x) -> VM-exit.\n", enmTaskSwitch, SelTSS));
+        IEM_VMX_VMEXIT_TASK_SWITCH_RET(pVCpu, enmTaskSwitch, SelTSS);
     }
 
@@ -4037,5 +4061,4 @@
         RT_NOREF2(uExitInfo1, uExitInfo2);
     }
-    /** @todo Nested-VMX task-switch intercept. */
 
     /*
@@ -4118,5 +4141,7 @@
         Log(("iemTaskSwitch: Switching to the same TSS! enmTaskSwitch=%u GCPtr[Cur|New]TSS=%#RGv\n", enmTaskSwitch, GCPtrCurTSS));
         Log(("uCurCr3=%#x uCurEip=%#x uCurEflags=%#x uCurEax=%#x uCurEsp=%#x uCurEbp=%#x uCurCS=%#04x uCurSS=%#04x uCurLdt=%#x\n",
-             pVCpu->cpum.GstCtx.cr3, pVCpu->cpum.GstCtx.eip, pVCpu->cpum.GstCtx.eflags.u32, pVCpu->cpum.GstCtx.eax, pVCpu->cpum.GstCtx.esp, pVCpu->cpum.GstCtx.ebp, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.ss.Sel, pVCpu->cpum.GstCtx.ldtr.Sel));
+             pVCpu->cpum.GstCtx.cr3, pVCpu->cpum.GstCtx.eip, pVCpu->cpum.GstCtx.eflags.u32, pVCpu->cpum.GstCtx.eax,
+             pVCpu->cpum.GstCtx.esp, pVCpu->cpum.GstCtx.ebp, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.ss.Sel,
+             pVCpu->cpum.GstCtx.ldtr.Sel));
     }
     if (fIsNewTSS386)
@@ -4420,5 +4445,5 @@
     else
     {
-        Assert(!pVCpu->cpum.GstCtx.ldtr.Attr.n.u1Present);       /* Ensures that LDT.TI check passes in iemMemFetchSelDesc() below. */
+        Assert(!pVCpu->cpum.GstCtx.ldtr.Attr.n.u1Present);   /* Ensures that LDT.TI check passes in iemMemFetchSelDesc() below. */
 
         IEMSELDESC DescNewLdt;
@@ -4705,5 +4730,6 @@
     }
 
-    Log(("iemTaskSwitch: Success! New CS:EIP=%#04x:%#x SS=%#04x\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.eip, pVCpu->cpum.GstCtx.ss.Sel));
+    Log(("iemTaskSwitch: Success! New CS:EIP=%#04x:%#x SS=%#04x\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.eip,
+         pVCpu->cpum.GstCtx.ss.Sel));
     return fFlags & IEM_XCPT_FLAGS_T_CPU_XCPT ? VINF_IEM_RAISED_XCPT : VINF_SUCCESS;
 }
@@ -4864,5 +4890,7 @@
 
         /* Do the actual task switch. */
-        return iemTaskSwitch(pVCpu, IEMTASKSWITCH_INT_XCPT, (fFlags & IEM_XCPT_FLAGS_T_SOFT_INT) ? pVCpu->cpum.GstCtx.eip + cbInstr : pVCpu->cpum.GstCtx.eip, fFlags, uErr, uCr2, SelTSS, &DescTSS);
+        return iemTaskSwitch(pVCpu, IEMTASKSWITCH_INT_XCPT,
+                             (fFlags & IEM_XCPT_FLAGS_T_SOFT_INT) ? pVCpu->cpum.GstCtx.eip + cbInstr : pVCpu->cpum.GstCtx.eip,
+                             fFlags, uErr, uCr2, SelTSS, &DescTSS);
     }
 
Index: trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h
===================================================================
--- trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h	(revision 74682)
+++ trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h	(revision 74683)
@@ -28,10 +28,8 @@
  *  VMX_EXIT_INT_WINDOW
  *  VMX_EXIT_NMI_WINDOW
- *  VMX_EXIT_TASK_SWITCH
  *  VMX_EXIT_GETSEC
  *  VMX_EXIT_INVD
  *  VMX_EXIT_RSM
  *  VMX_EXIT_MOV_DRX
- *  VMX_EXIT_IO_INSTR
  *  VMX_EXIT_MWAIT
  *  VMX_EXIT_MTF
@@ -2727,5 +2725,6 @@
      *
      * The VM-exit instruction length is mandatory for all VM-exits that are caused by
-     * instruction execution.
+     * instruction execution. For VM-exits that are not due to instruction execution this
+     * field is undefined.
      *
      * In our implementation in IEM, all undefined fields are generally cleared. However,
@@ -3373,4 +3372,37 @@
 
     return VINF_VMX_INTERCEPT_NOT_ACTIVE;
+}
+
+
+/**
+ * VMX VM-exit handler for VM-exits due to task switches.
+ *
+ * @returns VBox strict status code.
+ * @param   pVCpu           The cross context virtual CPU structure.
+ * @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.
+     *
+     * See Intel spec. 25.2 "Other Causes Of VM Exits".
+     */
+    uint8_t uTaskSwitchSrc;
+    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;
+        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);
+    iemVmxVmcsSetExitQual(pVCpu, uExitQual);
+    return iemVmxVmexit(pVCpu, VMX_EXIT_TASK_SWITCH);
 }
 
