Index: /trunk/include/VBox/vmm/hm_vmx.h
===================================================================
--- /trunk/include/VBox/vmm/hm_vmx.h	(revision 78480)
+++ /trunk/include/VBox/vmm/hm_vmx.h	(revision 78481)
@@ -1839,5 +1839,5 @@
 #define VMX_VMCS_RO_EXIT_QUALIFICATION                          0x6400
 #define VMX_VMCS_RO_IO_RCX                                      0x6402
-#define VMX_VMCS_RO_IO_RSX                                      0x6404
+#define VMX_VMCS_RO_IO_RSI                                      0x6404
 #define VMX_VMCS_RO_IO_RDI                                      0x6406
 #define VMX_VMCS_RO_IO_RIP                                      0x6408
@@ -2833,6 +2833,6 @@
  * @{
  */
-/** 0-2:   IO operation width. */
-#define VMX_EXIT_QUAL_IO_WIDTH(a)                               ((a) & 7)
+/** 0-2:   IO operation size 0(=1 byte), 1(=2 bytes) and 3(=4 bytes). */
+#define VMX_EXIT_QUAL_IO_SIZE(a)                                ((a) & 7)
 /** 3:     IO operation direction. */
 #define VMX_EXIT_QUAL_IO_DIRECTION(a)                           (((a) >> 3) & 1)
Index: /trunk/include/VBox/vmm/iem.h
===================================================================
--- /trunk/include/VBox/vmm/iem.h	(revision 78480)
+++ /trunk/include/VBox/vmm/iem.h	(revision 78481)
@@ -337,4 +337,6 @@
 VMM_INT_DECL(VBOXSTRICTRC)  IEMExecVmxVmexitNmi(PVMCPU pVCpu);
 VMM_INT_DECL(VBOXSTRICTRC)  IEMExecVmxVmexitStartupIpi(PVMCPU pVCpu, uint8_t uVector);
+VMM_INT_DECL(VBOXSTRICTRC)  IEMExecVmxVmexitInstrWithInfo(PVMCPU pVCpu, PCVMXVEXITINFO pExitInfo);
+VMM_INT_DECL(VBOXSTRICTRC)  IEMExecVmxVmexitInstr(PVMCPU pVCpu, uint32_t uExitReason, uint8_t cbInstr);
 VMM_INT_DECL(VBOXSTRICTRC)  IEMExecVmxVmexit(PVMCPU pVCpu, uint32_t uExitReason);
 VMM_INT_DECL(VBOXSTRICTRC)  IEMExecDecodedVmread(PVMCPU pVCpu, PCVMXVEXITINFO pExitInfo);
Index: /trunk/src/VBox/VMM/VMMAll/HMVMXAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/HMVMXAll.cpp	(revision 78480)
+++ /trunk/src/VBox/VMM/VMMAll/HMVMXAll.cpp	(revision 78481)
@@ -1217,9 +1217,24 @@
  * @param   pVCpu   The cross context virtual CPU structure.
  * @param   pCtx    Pointer to the guest-CPU context.
+ *
+ * @remarks Can be called from ring-0 as well as ring-3.
  */
 VMM_INT_DECL(void) HMNotifyVmxNstGstVmexit(PVMCPU pVCpu, PCPUMCTX pCtx)
 {
     NOREF(pCtx);
+
+    /*
+     * Make sure we need to merge the nested-guest VMCS on next nested-guest
+     * VM entry (if we VM-exit in ring-0 and continue in ring-0 till the next
+     * nested-guest VM-entry).
+     */
     pVCpu->hm.s.vmx.fMergedNstGstCtls = false;
+
+    CPUMImportGuestStateOnDemand(pVCpu, CPUMCTX_EXTRN_ALL);
+    AssertMsg(!(pVCpu->cpum.GstCtx.fExtrn & CPUMCTX_EXTRN_ALL),
+              ("fExtrn=%#RX64 fExtrnMbz=%#RX64\n", pVCpu->cpum.GstCtx.fExtrn, CPUMCTX_EXTRN_ALL));
+    ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
+
+
 }
 # endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
Index: /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 78480)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 78481)
@@ -982,9 +982,4 @@
 IEM_STATIC VBOXSTRICTRC     iemVmxVmexitEventDoubleFault(PVMCPU pVCpu);
 IEM_STATIC VBOXSTRICTRC     iemVmxVmexitTripleFault(PVMCPU pVCpu);
-IEM_STATIC VBOXSTRICTRC     iemVmxVmexitPreemptTimer(PVMCPU pVCpu);
-IEM_STATIC VBOXSTRICTRC     iemVmxVmexitExtInt(PVMCPU pVCpu, uint8_t uVector, bool fIntPending);
-IEM_STATIC VBOXSTRICTRC     iemVmxVmexitNmi(PVMCPU pVCpu);
-IEM_STATIC VBOXSTRICTRC     iemVmxVmexitStartupIpi(PVMCPU pVCpu, uint8_t uVector);
-IEM_STATIC VBOXSTRICTRC     iemVmxVmexit(PVMCPU pVCpu, uint32_t uExitReason);
 IEM_STATIC VBOXSTRICTRC     iemVmxVirtApicAccessMem(PVMCPU pVCpu, uint16_t offAccess, size_t cbAccess, void *pvData, uint32_t fAccess);
 IEM_STATIC VBOXSTRICTRC     iemVmxVmexitApicAccess(PVMCPU pVCpu, uint16_t offAccess, uint32_t fAccess);
@@ -15932,4 +15927,45 @@
 
 /**
+ * Interface for HM and EM to emulate a VM-exit due to an instruction.
+ *
+ * This is meant to be used for those instructions that VMX provides additional
+ * decoding information beyond just the instruction length!
+ *
+ * @returns Strict VBox status code.
+ * @param   pVCpu       The cross context virtual CPU structure of the calling EMT.
+ * @param   pExitInfo   Pointer to the VM-exit information struct.
+ * @thread  EMT(pVCpu)
+ */
+VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitInstrWithInfo(PVMCPU pVCpu, PCVMXVEXITINFO pExitInfo)
+{
+    VBOXSTRICTRC rcStrict = iemVmxVmexitInstrWithInfo(pVCpu, pExitInfo);
+    if (pVCpu->iem.s.cActiveMappings)
+        iemMemRollback(pVCpu);
+    return iemExecStatusCodeFiddling(pVCpu, rcStrict);
+}
+
+
+/**
+ * Interface for HM and EM to emulate a VM-exit due to an instruction.
+ *
+ * This is meant to be used for those instructions that VMX provides only the
+ * instruction length.
+ *
+ * @returns Strict VBox status code.
+ * @param   pVCpu       The cross context virtual CPU structure of the calling EMT.
+ * @param   pExitInfo   The VM-exit reason.
+ * @param   cbInstr     The instruction length in bytes.
+ * @thread  EMT(pVCpu)
+ */
+VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitInstr(PVMCPU pVCpu, uint32_t uExitReason, uint8_t cbInstr)
+{
+    VBOXSTRICTRC rcStrict = iemVmxVmexitInstr(pVCpu, uExitReason, cbInstr);
+    if (pVCpu->iem.s.cActiveMappings)
+        iemMemRollback(pVCpu);
+    return iemExecStatusCodeFiddling(pVCpu, rcStrict);
+}
+
+
+/**
  * Interface for HM and EM to emulate the VMREAD instruction.
  *
Index: /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h	(revision 78480)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h	(revision 78481)
@@ -660,5 +660,5 @@
         case VMX_VMCS_RO_EXIT_QUALIFICATION:
         case VMX_VMCS_RO_IO_RCX:
-        case VMX_VMCS_RO_IO_RSX:
+        case VMX_VMCS_RO_IO_RSI:
         case VMX_VMCS_RO_IO_RDI:
         case VMX_VMCS_RO_IO_RIP:
@@ -1089,16 +1089,4 @@
 {
     return CPUMSetGuestVmxVmFailInvalid(&pVCpu->cpum.GstCtx);
-}
-
-
-/**
- * Implements VMFailValid for VMX instruction failure.
- *
- * @param   pVCpu       The cross context virtual CPU structure.
- * @param   enmInsErr   The VM instruction error.
- */
-DECL_FORCE_INLINE(void) iemVmxVmFailValid(PVMCPU pVCpu, VMXINSTRERR enmInsErr)
-{
-    return CPUMSetGuestVmxVmFailValid(&pVCpu->cpum.GstCtx, enmInsErr);
 }
 
@@ -2785,4 +2773,10 @@
     }
 
+    /* The following VMCS fields are unsupported since we don't injecting SMIs into a guest. */
+    Assert(pVmcs->u64RoIoRcx.u == 0);
+    Assert(pVmcs->u64RoIoRsi.u == 0);
+    Assert(pVmcs->u64RoIoRdi.u == 0);
+    Assert(pVmcs->u64RoIoRip.u == 0);
+
     /*
      * Save the guest state back into the VMCS.
@@ -2886,5 +2880,5 @@
  * @param   pExitInfo       Pointer to the VM-exit instruction information struct.
  */
-DECLINLINE(VBOXSTRICTRC) iemVmxVmexitInstrWithInfo(PVMCPU pVCpu, PCVMXVEXITINFO pExitInfo)
+IEM_STATIC VBOXSTRICTRC iemVmxVmexitInstrWithInfo(PVMCPU pVCpu, PCVMXVEXITINFO pExitInfo)
 {
     /*
Index: /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 78480)
+++ /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 78481)
@@ -7615,4 +7615,65 @@
                     }
                 }
+
+#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
+# if 0
+                /** @todo NSTVMX: We handle each of these fields individually by passing it to IEM
+                 *        VM-exit handlers. We might handle it differently when using the fast path. */
+                /*
+                 * The hardware virtualization state currently consists of VMCS fields that may be
+                 * modified by execution of the nested-guest (that are not part of the general
+                 * guest state) and is visible to guest software. Hence, it is technically part of
+                 * the guest-CPU state when executing a nested-guest.
+                 */
+                if (   (fWhat & CPUMCTX_EXTRN_HWVIRT)
+                    && CPUMIsGuestInVmxNonRootMode(pCtx))
+                {
+                    PVMXVVMCS pGstVmcs = pCtx->hwvirt.vmx.CTX_SUFF(pVmcs);
+                    rc  = VMXReadVmcs32(VMX_VMCS32_RO_EXIT_REASON,        &pGstVmcs->u32RoExitReason);
+                    rc |= VMXReadVmcsGstN(VMX_VMCS_RO_EXIT_QUALIFICATION, &pGstVmcs->u64RoExitQual.u);
+                    VMXLOCAL_BREAK_RC(rc);
+
+                    /*
+                     * VM-entry can fail due to invalid-guest state, machine-check events and
+                     * MSR loading failures. Other than VM-exit reason and VM-exit qualification
+                     * all other VMCS fields are left unmodified on VM-entry failure.
+                     *
+                     * See Intel spec. 26.7 "VM-entry Failures During Or After Loading Guest State".
+                     */
+                    bool const fEntryFailed = VMX_EXIT_REASON_HAS_ENTRY_FAILED(pGstVmcs->u32RoExitReason);
+                    if (!fEntryFailed)
+                    {
+                        /*
+                         * Some notes on VMCS fields that may need importing when the fast path
+                         * is implemented. Currently we fully emulate VMLAUNCH/VMRESUME in IEM.
+                         *
+                         * Requires fixing up when using hardware-assisted VMX:
+                         *   - VM-exit interruption info: Shouldn't reflect host interrupts/NMIs.
+                         *   - VM-exit interruption error code: Cleared to 0 when not appropriate.
+                         *   - IDT-vectoring info: Think about this.
+                         *   - IDT-vectoring error code: Think about this.
+                         *
+                         * Emulated:
+                         *   - Guest-interruptiblity state: Derived from FFs and RIP.
+                         *   - Guest pending debug exceptions: Derived from DR6.
+                         *   - Guest activity state: Emulated from EM state.
+                         *   - Guest PDPTEs: Currently all 0s since we don't support nested EPT.
+                         *   - Entry-interrupt info: Emulated, cleared to 0.
+                         */
+                        rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO,       &pGstVmcs->u32RoExitIntInfo);
+                        rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE, &pGstVmcs->u32RoExitIntErrCode);
+                        rc |= VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_INFO,           &pGstVmcs->u32RoIdtVectoringInfo);
+                        rc |= VMXReadVmcs32(VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE,     &pGstVmcs->u32RoIdtVectoringErrCode);
+                        rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_LENGTH,            &pGstVmcs->u32RoExitInstrLen);
+                        rc |= VMXReadVmcs32(VMX_VMCS32_RO_EXIT_INSTR_INFO,              &pGstVmcs->u32RoExitIntInfo);
+                        rc |= VMXReadVmcs64(VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL,         &pGstVmcs->u64RoGuestPhysAddr.u);
+                        rc |= VMXReadVmcsGstN(VMX_VMCS_RO_GUEST_LINEAR_ADDR,            &pGstVmcs->u64RoGuestLinearAddr.u);
+                        /** @todo NSTVMX: Save and adjust preemption timer value. */
+                    }
+
+                    VMXLOCAL_BREAK_RC(rc);
+                }
+# endif
+#endif
             }
         } while (0);
@@ -10669,4 +10730,7 @@
      * Check if VMLAUNCH/VMRESUME succeeded.
      * If this failed, we cause a guru meditation and cease further execution.
+     *
+     * However, if we are executing a nested-guest we might fail if we use the
+     * fast path rather than fully emulating VMLAUNCH/VMRESUME instruction in IEM.
      */
     if (RT_LIKELY(rcVMRun == VINF_SUCCESS))
@@ -10734,4 +10798,23 @@
         }
     }
+#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
+    else if (pVmxTransient->fIsNestedGuest)
+    {
+# if 0
+        /*
+         * Copy the VM-instruction error field to the guest VMCS.
+         */
+        /** @todo NSTVMX: Verify we're using the fast path. */
+        uint32_t u32RoVmInstrError;
+        rc = VMXReadVmcs32(VMX_VMCS32_RO_VM_INSTR_ERROR, &u32RoVmInstrError);
+        AssertRCReturn(rc, rc);
+        PVMXVVMCS pGstVmcs = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
+        pGstVmcs->u32RoVmInstrError = u32RoVmInstrError;
+        /** @todo NSTVMX: Advance guest RIP and other fast path related restoration.  */
+# else
+        AssertMsgFailed(("VMLAUNCH/VMRESUME failed but shouldn't happen when VMLAUNCH/VMRESUME was emulated in IEM!\n"));
+# endif
+    }
+#endif
     else
         Log4Func(("VM-entry failure: rcVMRun=%Rrc fVMEntryFailed=%RTbool\n", rcVMRun, pVmxTransient->fVMEntryFailed));
@@ -12433,10 +12516,46 @@
 DECLINLINE(VBOXSTRICTRC) hmR0VmxHandleExitNested(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
 {
+    VBOXSTRICTRC   rcStrict = VINF_SUCCESS;
     uint32_t const rcReason = pVmxTransient->uExitReason;
     switch (rcReason)
     {
         case VMX_EXIT_EPT_MISCONFIG:
+            rcStrict = hmR0VmxExitEptMisconfig(pVCpu, pVmxTransient);
+            break;
+
         case VMX_EXIT_EPT_VIOLATION:
+            rcStrict = hmR0VmxExitEptViolation(pVCpu, pVmxTransient);
+            break;
+
         case VMX_EXIT_IO_INSTR:
+        {
+            int rc = hmR0VmxReadExitQualVmcs(pVCpu, pVmxTransient);
+            AssertRCReturn(rc, rc);
+
+            uint32_t const uIOPort = VMX_EXIT_QUAL_IO_PORT(pVmxTransient->uExitQual);
+            uint8_t  const uIOSize = VMX_EXIT_QUAL_IO_SIZE(pVmxTransient->uExitQual);
+            AssertReturn(uIOSize <= 3 && uIOSize != 2, VERR_VMX_IPE_1);
+
+            /* Size of the I/O accesses in bytes. */
+            static uint32_t const s_aIOSizes[4] = { 1, 2, 0, 4 };
+            uint8_t const cbAccess = s_aIOSizes[uIOSize];
+
+            if (CPUMIsGuestVmxIoInterceptSet(pVCpu, uIOPort, cbAccess))
+            {
+                rc = hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
+                AssertRCReturn(rc, rc);
+
+                VMXVEXITINFO ExitInfo;
+                RT_ZERO(ExitInfo);
+                ExitInfo.uReason = pVmxTransient->uExitReason;
+                ExitInfo.cbInstr = pVmxTransient->cbInstr;
+                ExitInfo.u64Qual = pVmxTransient->uExitQual;
+                rcStrict = IEMExecVmxVmexitInstrWithInfo(pVCpu, &ExitInfo);
+            }
+            else
+                rcStrict = hmR0VmxExitIoInstr(pVCpu, pVmxTransient);
+            break;
+        }
+
         case VMX_EXIT_CPUID:
         case VMX_EXIT_RDTSC:
@@ -12503,5 +12622,6 @@
             return hmR0VmxExitErrUndefined(pVCpu, pVmxTransient);
     }
-#undef VMEXIT_CALL_RET
+
+    return rcStrict;
 }
 #endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
@@ -14083,11 +14203,11 @@
 
     /* Refer Intel spec. 27-5. "Exit Qualifications for I/O Instructions" for the format. */
-    uint32_t uIOPort      = VMX_EXIT_QUAL_IO_PORT(pVmxTransient->uExitQual);
-    uint8_t  uIOWidth     = VMX_EXIT_QUAL_IO_WIDTH(pVmxTransient->uExitQual);
-    bool     fIOWrite     = (VMX_EXIT_QUAL_IO_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_IO_DIRECTION_OUT);
-    bool     fIOString    = VMX_EXIT_QUAL_IO_IS_STRING(pVmxTransient->uExitQual);
-    bool     fGstStepping = RT_BOOL(pCtx->eflags.Bits.u1TF);
-    bool     fDbgStepping = pVCpu->hm.s.fSingleInstruction;
-    AssertReturn(uIOWidth <= 3 && uIOWidth != 2, VERR_VMX_IPE_1);
+    uint32_t const uIOPort      = VMX_EXIT_QUAL_IO_PORT(pVmxTransient->uExitQual);
+    uint8_t  const uIOSize      = VMX_EXIT_QUAL_IO_SIZE(pVmxTransient->uExitQual);
+    bool     const fIOWrite     = (VMX_EXIT_QUAL_IO_DIRECTION(pVmxTransient->uExitQual) == VMX_EXIT_QUAL_IO_DIRECTION_OUT);
+    bool     const fIOString    = VMX_EXIT_QUAL_IO_IS_STRING(pVmxTransient->uExitQual);
+    bool     const fGstStepping = RT_BOOL(pCtx->eflags.Bits.u1TF);
+    bool     const fDbgStepping = pVCpu->hm.s.fSingleInstruction;
+    AssertReturn(uIOSize <= 3 && uIOSize != 2, VERR_VMX_IPE_1);
 
     /*
@@ -14112,5 +14232,5 @@
         static uint32_t const s_aIOSizes[4] = { 1, 2, 0, 4 };                    /* Size of the I/O accesses. */
         static uint32_t const s_aIOOpAnd[4] = { 0xff, 0xffff, 0, 0xffffffff };   /* AND masks for saving result in AL/AX/EAX. */
-        uint32_t const cbValue  = s_aIOSizes[uIOWidth];
+        uint32_t const cbValue  = s_aIOSizes[uIOSize];
         uint32_t const cbInstr  = pVmxTransient->cbInstr;
         bool fUpdateRipAlready  = false; /* ugly hack, should be temporary. */
@@ -14161,5 +14281,5 @@
              */
             Log4Func(("cs:rip=%04x:%08RX64 %#06x/%u %c\n", pCtx->cs.Sel, pCtx->rip, uIOPort, cbValue, fIOWrite ? 'w' : 'r'));
-            uint32_t const uAndVal = s_aIOOpAnd[uIOWidth];
+            uint32_t const uAndVal = s_aIOOpAnd[uIOSize];
             Assert(!VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual));
             if (fIOWrite)
@@ -14288,5 +14408,5 @@
               pVCpu->idCpu, pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip,
               VMX_EXIT_QUAL_IO_IS_REP(pVmxTransient->uExitQual) ? "REP " : "",
-              fIOWrite ? "OUT" : "IN", fIOString ? "S" : "", uIOPort, uIOWidth));
+              fIOWrite ? "OUT" : "IN", fIOString ? "S" : "", uIOPort, uIOSize));
 
         rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
