Index: /trunk/include/VBox/vmm/cpumctx.h
===================================================================
--- /trunk/include/VBox/vmm/cpumctx.h	(revision 74659)
+++ /trunk/include/VBox/vmm/cpumctx.h	(revision 74660)
@@ -644,6 +644,16 @@
                 uint32_t                uMsrBitmapR3;
 #endif
-                /** 0x378 - Padding. */
-                uint8_t             abPadding[0x3f0 - 0x378];
+                /** 0x378 - The I/O bitmap - R0 ptr. */
+                R0PTRTYPE(void *)       pvIoBitmapR0;
+#if HC_ARCH_BITS == 32
+                uint32_t                uIoBitmapR0;
+#endif
+                /** 0x380 - The I/O bitmap - R3 ptr. */
+                R3PTRTYPE(void *)       pvIoBitmapR3;
+#if HC_ARCH_BITS == 32
+                uint32_t                uIoBitmapR3;
+#endif
+                /** 0x388 - Padding. */
+                uint8_t             abPadding[0x3f0 - 0x388];
             } vmx;
         } CPUM_UNION_NM(s);
@@ -745,4 +755,8 @@
 AssertCompileMemberOffset(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.pAutoMsrAreaR0,         0x358);
 AssertCompileMemberOffset(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.pAutoMsrAreaR3,         0x360);
+AssertCompileMemberOffset(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.pvMsrBitmapR0,          0x368);
+AssertCompileMemberOffset(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.pvMsrBitmapR3,          0x370);
+AssertCompileMemberOffset(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.pvIoBitmapR0,           0x378);
+AssertCompileMemberOffset(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.pvIoBitmapR3,           0x380);
 AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.pVmcsR0,           8);
 AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.pShadowVmcsR0,     8);
@@ -752,4 +766,5 @@
 AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.pAutoMsrAreaR0,    8);
 AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.pvMsrBitmapR0,     8);
+AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.pvIoBitmapR0,      8);
 AssertCompileMemberOffset(CPUMCTX, hwvirt.enmHwvirt,           0x3f0);
 AssertCompileMemberOffset(CPUMCTX, hwvirt.fLocalForcedActions, 0x3f4);
Index: /trunk/include/VBox/vmm/hm.h
===================================================================
--- /trunk/include/VBox/vmm/hm.h	(revision 74659)
+++ /trunk/include/VBox/vmm/hm.h	(revision 74660)
@@ -150,6 +150,7 @@
 VMM_INT_DECL(int)               HMVmxEntryIntInfoInjectTrpmEvent(PVMCPU pVCpu, uint32_t uEntryIntInfo, uint32_t uErrCode,
                                                                  uint32_t cbInstr, RTGCUINTPTR GCPtrFaultAddress);
-VMM_INT_DECL(int)               HMVmxGetMsrPermission(void *pvMsrBitmap, uint32_t idMsr, PVMXMSREXITREAD penmRead,
+VMM_INT_DECL(int)               HMVmxGetMsrPermission(void const *pvMsrBitmap, uint32_t idMsr, PVMXMSREXITREAD penmRead,
                                                       PVMXMSREXITWRITE penmWrite);
+VMM_INT_DECL(bool)              HMVmxGetIoBitmapPermission(void const *pvIoBitmapA, void const *pvIoBitmapB, uint16_t uPort);
 /** @} */
 
Index: /trunk/include/VBox/vmm/hm_vmx.h
===================================================================
--- /trunk/include/VBox/vmm/hm_vmx.h	(revision 74659)
+++ /trunk/include/VBox/vmm/hm_vmx.h	(revision 74660)
@@ -2500,4 +2500,6 @@
 #define VMXINSTRID_VMREAD                                       (0x12 | VMXINSTRID_VALID)
 #define VMXINSTRID_VMWRITE                                      (0x13 | VMXINSTRID_VALID | VMXINSTRID_MODRM_PRIMARY_OP_W)
+#define VMXINSTRID_IO_IN                                        (0x14 | VMXINSTRID_VALID)
+#define VMXINSTRID_IO_OUT                                       (0x15 | VMXINSTRID_VALID)
 /** @} */
 
@@ -2726,5 +2728,24 @@
 /** 16-31: IO Port (0-0xffff). */
 #define VMX_EXIT_QUAL_IO_PORT(a)                                (((a) >> 16) & 0xffff)
-/* Rest reserved. */
+
+/** Bit fields for Exit qualification for I/O instructions. */
+#define VMX_BF_EXIT_QUAL_IO_WIDTH_SHIFT                         0
+#define VMX_BF_EXIT_QUAL_IO_WIDTH_MASK                          UINT64_C(0x0000000000000007)
+#define VMX_BF_EXIT_QUAL_IO_DIRECTION_SHIFT                     3
+#define VMX_BF_EXIT_QUAL_IO_DIRECTION_MASK                      UINT64_C(0x0000000000000008)
+#define VMX_BF_EXIT_QUAL_IO_IS_STRING_SHIFT                     4
+#define VMX_BF_EXIT_QUAL_IO_IS_STRING_MASK                      UINT64_C(0x0000000000000010)
+#define VMX_BF_EXIT_QUAL_IO_IS_REP_SHIFT                        5
+#define VMX_BF_EXIT_QUAL_IO_IS_REP_MASK                         UINT64_C(0x0000000000000020)
+#define VMX_BF_EXIT_QUAL_IO_ENCODING_SHIFT                      6
+#define VMX_BF_EXIT_QUAL_IO_ENCODING_MASK                       UINT64_C(0x0000000000000040)
+#define VMX_BF_EXIT_QUAL_IO_RSVD_7_15_SHIFT                     7
+#define VMX_BF_EXIT_QUAL_IO_RSVD_7_15_MASK                      UINT64_C(0x000000000000ff80)
+#define VMX_BF_EXIT_QUAL_IO_PORT_SHIFT                          16
+#define VMX_BF_EXIT_QUAL_IO_PORT_MASK                           UINT64_C(0x00000000ffff0000)
+#define VMX_BF_EXIT_QUAL_IO_RSVD_32_63_SHIFT                    32
+#define VMX_BF_EXIT_QUAL_IO_RSVD_32_63_MASK                     UINT64_C(0xffffffff00000000)
+RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_QUAL_IO_, UINT64_C(0), UINT64_MAX,
+                            (WIDTH, DIRECTION, IS_STRING, IS_REP, ENCODING, RSVD_7_15, PORT, RSVD_32_63));
 /** @} */
 
@@ -3078,4 +3099,14 @@
 #define VMX_V_MSR_BITMAP_PAGES                                  1
 
+/** The size of I/O bitmap A (in bytes). */
+#define VMX_V_IO_BITMAP_A_SIZE                                  X86_PAGE_4K_SIZE
+/** The size of I/O bitmap A (in pages). */
+#define VMX_V_IO_BITMAP_A_PAGES                                 1
+
+/** The size of I/O bitmap B (in bytes). */
+#define VMX_V_IO_BITMAP_B_SIZE                                  X86_PAGE_4K_SIZE
+/** The size of I/O bitmap B (in pages). */
+#define VMX_V_IO_BITMAP_B_PAGES                                 1
+
 /** The size of the auto-load/store MSR area (in bytes). */
 #define VMX_V_AUTOMSR_AREA_SIZE                                 ((512 * (VMX_V_AUTOMSR_COUNT_MAX + 1)) * sizeof(VMXAUTOMSR))
@@ -3120,4 +3151,5 @@
 typedef const VMXVEXITINFO *PCVMXVEXITINFO;
 AssertCompileMemberAlignment(VMXVEXITINFO, u64Qual, 8);
+
 
 /**
Index: /trunk/src/VBox/VMM/VMMAll/HMVMXAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/HMVMXAll.cpp	(revision 74659)
+++ /trunk/src/VBox/VMM/VMMAll/HMVMXAll.cpp	(revision 74660)
@@ -890,5 +890,5 @@
  *                          NULL.
  */
-VMM_INT_DECL(int) HMVmxGetMsrPermission(void *pvMsrBitmap, uint32_t idMsr, PVMXMSREXITREAD penmRead,
+VMM_INT_DECL(int) HMVmxGetMsrPermission(void const *pvMsrBitmap, uint32_t idMsr, PVMXMSREXITREAD penmRead,
                                         PVMXMSREXITWRITE penmWrite)
 {
@@ -896,5 +896,5 @@
 
     int32_t iBit;
-    uint8_t *pbMsrBitmap = (uint8_t *)pvMsrBitmap;
+    uint8_t const *pbMsrBitmap = (uint8_t *)pvMsrBitmap;
 
     /*
@@ -955,2 +955,23 @@
 }
 
+
+/**
+ * Gets the permission bits for the specified I/O port from the given I/O bitmaps.
+ *
+ * @returns @c true if the I/O port access must cause a VM-exit, @c false otherwise.
+ * @param   pvIoBitmapA     Pointer to I/O bitmap A.
+ * @param   pvIoBitmapB     Pointer to I/O bitmap B.
+ * @param   uPort           The I/O port being accessed.
+ */
+VMM_INT_DECL(bool) HMVmxGetIoBitmapPermission(void const *pvIoBitmapA, void const *pvIoBitmapB, uint16_t uPort)
+{
+    /* If the port is 0 or ffff ("wrap around"), we cause a VM-exit. */
+    if (   uPort == 0x0000
+        || uPort == 0xffff)
+        return true;
+
+    /* Read the appropriate bit from the corresponding IO bitmap. */
+    void const *pvIoBitmap = uPort < 0x8000 ? pvIoBitmapA : pvIoBitmapB;
+    return ASMBitTest(pvIoBitmap, uPort);
+}
+
Index: /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h	(revision 74659)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h	(revision 74660)
@@ -2861,4 +2861,37 @@
 
 /**
+ * Checks whether an I/O instruction for the given port is intercepted (causes a
+ * VM-exit)  or not.
+ *
+ * @returns @c true if the instruction is intercepted, @c false otherwise.
+ * @param   pVCpu           The cross context virtual CPU structure.
+ * @param   uPort           The I/O port being accessed by the instruction.
+ */
+IEM_STATIC bool iemVmxIsIoInterceptSet(PVMCPU pVCpu, uint16_t uPort)
+{
+    PCVMXVVMCS pVmcs = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
+    Assert(pVmcs);
+
+    /*
+     * Check whether the IO instruction must cause a VM-exit or not.
+     * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally".
+     */
+    if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_UNCOND_IO_EXIT)
+        return true;
+
+    if (pVmcs->u32ProcCtls & VMX_PROC_CTLS_USE_IO_BITMAPS)
+    {
+        uint8_t const *pbIoBitmapA = (uint8_t const *)pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvIoBitmap);
+        uint8_t const *pbIoBitmapB = (uint8_t const *)pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvIoBitmap) + VMX_V_IO_BITMAP_A_SIZE;
+        Assert(pbIoBitmapA);
+        Assert(pbIoBitmapB);
+        return HMVmxGetIoBitmapPermission(pbIoBitmapA, pbIoBitmapB, uPort);
+    }
+
+    return false;
+}
+
+
+/**
  * VMX VM-exit handler for VM-exits due to INVLPG.
  *
Index: /trunk/src/VBox/VMM/VMMR3/CPUM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/CPUM.cpp	(revision 74659)
+++ /trunk/src/VBox/VMM/VMMR3/CPUM.cpp	(revision 74660)
@@ -934,4 +934,9 @@
             pVCpu->cpum.s.Guest.hwvirt.vmx.pVmcsR3 = NULL;
         }
+        if (pVCpu->cpum.s.Guest.hwvirt.vmx.pShadowVmcsR3)
+        {
+            SUPR3PageFreeEx(pVCpu->cpum.s.Guest.hwvirt.vmx.pShadowVmcsR3, VMX_V_VMCS_PAGES);
+            pVCpu->cpum.s.Guest.hwvirt.vmx.pShadowVmcsR3 = NULL;
+        }
         if (pVCpu->cpum.s.Guest.hwvirt.vmx.pvVirtApicPageR3)
         {
@@ -958,4 +963,9 @@
             SUPR3PageFreeEx(pVCpu->cpum.s.Guest.hwvirt.vmx.pvMsrBitmapR3, VMX_V_MSR_BITMAP_PAGES);
             pVCpu->cpum.s.Guest.hwvirt.vmx.pvMsrBitmapR3 = NULL;
+        }
+        if (pVCpu->cpum.s.Guest.hwvirt.vmx.pvIoBitmapR3)
+        {
+            SUPR3PageFreeEx(pVCpu->cpum.s.Guest.hwvirt.vmx.pvIoBitmapR3, VMX_V_IO_BITMAP_A_PAGES + VMX_V_IO_BITMAP_B_PAGES);
+            pVCpu->cpum.s.Guest.hwvirt.vmx.pvIoBitmapR3 = NULL;
         }
     }
@@ -995,4 +1005,18 @@
 
         /*
+         * Allocate the nested-guest shadow VMCS.
+         */
+        Assert(VMX_V_VMCS_PAGES == 1);
+        Assert(!pVCpu->cpum.s.Guest.hwvirt.vmx.pShadowVmcsR3);
+        rc = SUPR3PageAllocEx(VMX_V_VMCS_PAGES, 0 /* fFlags */, (void **)&pVCpu->cpum.s.Guest.hwvirt.vmx.pShadowVmcsR3,
+                              &pVCpu->cpum.s.Guest.hwvirt.vmx.pShadowVmcsR0, NULL /* paPages */);
+        if (RT_FAILURE(rc))
+        {
+            Assert(!pVCpu->cpum.s.Guest.hwvirt.vmx.pShadowVmcsR3);
+            LogRel(("CPUM%u: Failed to alloc %u pages for the nested-guest's shadow VMCS\n", pVCpu->idCpu, VMX_V_VMCS_PAGES));
+            break;
+        }
+
+        /*
          * Allocate the Virtual-APIC page.
          */
@@ -1062,4 +1086,19 @@
             LogRel(("CPUM%u: Failed to alloc %u pages for the nested-guest's MSR bitmap\n", pVCpu->idCpu,
                     VMX_V_MSR_BITMAP_PAGES));
+            break;
+        }
+
+        /*
+         * Allocate the I/O bitmaps (A and B).
+         */
+        Assert(!pVCpu->cpum.s.Guest.hwvirt.vmx.pvIoBitmapR3);
+        rc = SUPR3PageAllocEx(VMX_V_IO_BITMAP_A_PAGES + VMX_V_IO_BITMAP_B_PAGES, 0 /* fFlags */,
+                              (void **)&pVCpu->cpum.s.Guest.hwvirt.vmx.pvIoBitmapR3,
+                              &pVCpu->cpum.s.Guest.hwvirt.vmx.pvIoBitmapR0, NULL /* paPages */);
+        if (RT_FAILURE(rc))
+        {
+            Assert(!pVCpu->cpum.s.Guest.hwvirt.vmx.pvIoBitmapR3);
+            LogRel(("CPUM%u: Failed to alloc %u pages for the nested-guest's I/O bitmaps\n", pVCpu->idCpu,
+                    VMX_V_IO_BITMAP_A_PAGES + VMX_V_IO_BITMAP_B_PAGES));
             break;
         }
