Index: /trunk/Config.kmk
===================================================================
--- /trunk/Config.kmk	(revision 91359)
+++ /trunk/Config.kmk	(revision 91360)
@@ -452,4 +452,6 @@
   endif
  endif
+ # Enables guest EPT support for VMX nested hardware virtualization.
+ VBOX_WITH_NESTED_HWVIRT_VMX_EPT = 1
 endif
 # Enable native NEM on windows.
Index: /trunk/include/VBox/vmm/hm_vmx.h
===================================================================
--- /trunk/include/VBox/vmm/hm_vmx.h	(revision 91359)
+++ /trunk/include/VBox/vmm/hm_vmx.h	(revision 91360)
@@ -1779,8 +1779,15 @@
 #define VMX_BF_EPTP_RSVD_8_11_SHIFT                             8
 #define VMX_BF_EPTP_RSVD_8_11_MASK                              UINT64_C(0x0000000000000f00)
-#define VMX_BF_EPTP_PML4_ADDR_SHIFT                             12
-#define VMX_BF_EPTP_PML4_ADDR_MASK                              UINT64_C(0xfffffffffffff000)
+#define VMX_BF_EPTP_PML4_TABLE_ADDR_SHIFT                       12
+#define VMX_BF_EPTP_PML4_TABLE_ADDR_MASK                        UINT64_C(0xfffffffffffff000)
 RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EPTP_, UINT64_C(0), UINT64_MAX,
-                            (MEMTYPE, PAGE_WALK_LENGTH, ACCESS_DIRTY, SUPER_SHW_STACK, RSVD_8_11, PML4_ADDR));
+                            (MEMTYPE, PAGE_WALK_LENGTH, ACCESS_DIRTY, SUPER_SHW_STACK, RSVD_8_11, PML4_TABLE_ADDR));
+
+/* Mask of valid EPTP bits sans physically non-addressable bits. */
+#define VMX_EPTP_VALID_MASK                                     (  VMX_BF_EPTP_MEMTYPE_MASK          \
+                                                                 | VMX_BF_EPTP_PAGE_WALK_LENGTH_MASK \
+                                                                 | VMX_BF_EPTP_ACCESS_DIRTY_MASK     \
+                                                                 | VMX_BF_EPTP_SUPER_SHW_STACK_MASK  \
+                                                                 | VMX_BF_EPTP_PML4_TABLE_ADDR_MASK)
 /** @} */
 
@@ -4148,4 +4155,8 @@
     kVmxVDiag_Vmentry_EntryIntInfoTypeVecRsvd,
     kVmxVDiag_Vmentry_EntryXcptErrCodeRsvd,
+    kVmxVDiag_Vmentry_EptpAccessDirty,
+    kVmxVDiag_Vmentry_EptpPageWalkLength,
+    kVmxVDiag_Vmentry_EptpMemType,
+    kVmxVDiag_Vmentry_EptpRsvd,
     kVmxVDiag_Vmentry_ExitCtlsAllowed1,
     kVmxVDiag_Vmentry_ExitCtlsDisallowed0,
Index: /trunk/src/VBox/VMM/Config.kmk
===================================================================
--- /trunk/src/VBox/VMM/Config.kmk	(revision 91359)
+++ /trunk/src/VBox/VMM/Config.kmk	(revision 91360)
@@ -35,4 +35,7 @@
 ifdef VBOX_WITH_NESTED_HWVIRT_VMX
  VMM_COMMON_DEFS += VBOX_WITH_NESTED_HWVIRT_VMX
+endif
+ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
+ VMM_COMMON_DEFS += VBOX_WITH_NESTED_HWVIRT_VMX_EPT
 endif
 ifdef VBOX_WITH_NESTED_HWVIRT_ONLY_IN_IEM
Index: /trunk/src/VBox/VMM/VMMAll/HMVMXAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/HMVMXAll.cpp	(revision 91359)
+++ /trunk/src/VBox/VMM/VMMAll/HMVMXAll.cpp	(revision 91360)
@@ -169,4 +169,8 @@
     VMXV_DIAG_DESC(kVmxVDiag_Vmentry_EntryIntInfoTypeVecRsvd  , "EntryIntInfoTypeVecRsvd"   ),
     VMXV_DIAG_DESC(kVmxVDiag_Vmentry_EntryXcptErrCodeRsvd     , "EntryXcptErrCodeRsvd"      ),
+    VMXV_DIAG_DESC(kVmxVDiag_Vmentry_EptpAccessDirty          , "EptpAccessDirty"           ),
+    VMXV_DIAG_DESC(kVmxVDiag_Vmentry_EptpPageWalkLength       , "EptpPageWalkLength"        ),
+    VMXV_DIAG_DESC(kVmxVDiag_Vmentry_EptpMemType              , "EptpMemType"               ),
+    VMXV_DIAG_DESC(kVmxVDiag_Vmentry_EptpRsvd                 , "EptpRsvd"                  ),
     VMXV_DIAG_DESC(kVmxVDiag_Vmentry_ExitCtlsAllowed1         , "ExitCtlsAllowed1"          ),
     VMXV_DIAG_DESC(kVmxVDiag_Vmentry_ExitCtlsDisallowed0      , "ExitCtlsDisallowed0"       ),
Index: /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h	(revision 91359)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h	(revision 91360)
@@ -6078,6 +6078,51 @@
             IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_Vpid);
 
+#ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
+        /* Extended Page Tables Pointer (EPTP). */
+        if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_EPT)
+        {
+            /* Reserved bits. */
+            uint8_t const cMaxPhysAddrWidth = IEM_GET_GUEST_CPU_FEATURES(pVCpu)->cMaxPhysAddrWidth;
+            uint64_t const fValidMask       = VMX_EPTP_VALID_MASK & ~(UINT64_MAX << cMaxPhysAddrWidth);
+            if (pVmcs->u64EptpPtr.u & fValidMask)
+            { /* likely */ }
+            else
+                IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_EptpRsvd);
+
+            /* Memory Type. */
+            uint64_t const fCaps    = pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs.u64EptVpidCaps;
+            uint8_t const  fMemType = RT_BF_GET(pVmcs->u64EptpPtr.u, VMX_BF_EPTP_MEMTYPE);
+            if (   (   fMemType == VMX_EPTP_MEMTYPE_WB
+                    && RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_MEMTYPE_WB))
+                || (   fMemType == VMX_EPTP_MEMTYPE_UC
+                    && RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_MEMTYPE_UC)))
+            { /* likely */ }
+            else
+                IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_EptpMemType);
+
+            /*
+             * Page walk length (PML4).
+             * Intel used to specify bit 7 of IA32_VMX_EPT_VPID_CAP as page walk length
+             * of 5 but that seems to be removed from the latest specs. leaving only PML4
+             * as the maximum supported page-walk level hence we hardcode it as 3 (1 less than 4)
+             */
+            Assert(RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_PAGE_WALK_LENGTH_4));
+            if (RT_BF_GET(pVmcs->u64EptpPtr.u, VMX_BF_EPTP_PAGE_WALK_LENGTH) == 3)
+            { /* likely */ }
+            else
+                IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_EptpPageWalkLength);
+
+            /* Access and dirty bits support in EPT structures. */
+            if (   !RT_BF_GET(pVmcs->u64EptpPtr.u, VMX_BF_EPTP_ACCESS_DIRTY)
+                ||  RT_BF_GET(fCaps, VMX_BF_EPT_VPID_CAP_ACCESS_DIRTY))
+            { /* likely */ }
+            else
+                IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_EptpAccessDirty);
+        }
+#else
+        Assert(!(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_EPT));                /* We don't support EPT yet. */
+#endif
+
         Assert(!(pVmcs->u32PinCtls & VMX_PIN_CTLS_POSTED_INT));             /* We don't support posted interrupts yet. */
-        Assert(!(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_EPT));                /* We don't support EPT yet. */
         Assert(!(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_PML));                /* We don't support PML yet. */
         Assert(!(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_UNRESTRICTED_GUEST)); /* We don't support Unrestricted-guests yet. */
