Index: trunk/src/VBox/VMM/VMMAll/HMVMXAll.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/HMVMXAll.cpp	(revision 74186)
+++ trunk/src/VBox/VMM/VMMAll/HMVMXAll.cpp	(revision 74187)
@@ -181,4 +181,9 @@
     VMXV_DIAG_DESC(kVmxVDiag_Vmentry_GuestPatMsr              , "GuestPatMsr"               ),
     VMXV_DIAG_DESC(kVmxVDiag_Vmentry_GuestPcide               , "GuestPcide"                ),
+    VMXV_DIAG_DESC(kVmxVDiag_Vmentry_GuestPdpteCr3ReadPhys    , "GuestPdpteCr3ReadPhys"     ),
+    VMXV_DIAG_DESC(kVmxVDiag_Vmentry_GuestPdpte0Rsvd          , "GuestPdpte0Rsvd"           ),
+    VMXV_DIAG_DESC(kVmxVDiag_Vmentry_GuestPdpte1Rsvd          , "GuestPdpte1Rsvd"           ),
+    VMXV_DIAG_DESC(kVmxVDiag_Vmentry_GuestPdpte2Rsvd          , "GuestPdpte2Rsvd"           ),
+    VMXV_DIAG_DESC(kVmxVDiag_Vmentry_GuestPdpte3Rsvd          , "GuestPdpte3Rsvd"           ),
     VMXV_DIAG_DESC(kVmxVDiag_Vmentry_GuestPndDbgXcptBsNoTf    , "GuestPndDbgXcptBsNoTf"     ),
     VMXV_DIAG_DESC(kVmxVDiag_Vmentry_GuestPndDbgXcptBsTf      , "GuestPndDbgXcptBsTf"       ),
Index: trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h
===================================================================
--- trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h	(revision 74186)
+++ trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h	(revision 74187)
@@ -709,5 +709,5 @@
 
 /**
- * Gets a segment register from the VMCS given its index.
+ * Gets a guest segment register from the VMCS given its index.
  *
  * @returns VBox status code.
@@ -2065,5 +2065,6 @@
         case X86_SREG_FS: return kVmxVDiag_Vmentry_GuestSegBaseFs;
         case X86_SREG_GS: return kVmxVDiag_Vmentry_GuestSegBaseGs;
-        default:          return kVmxVDiag_Vmentry_GuestSegBaseSs;
+        case X86_SREG_SS: return kVmxVDiag_Vmentry_GuestSegBaseSs;
+        IEM_NOT_REACHED_DEFAULT_CASE_RET2(kVmxVDiag_Ipe_2);
     }
 }
@@ -2085,7 +2086,6 @@
         case X86_SREG_FS: return kVmxVDiag_Vmentry_GuestSegBaseV86Fs;
         case X86_SREG_GS: return kVmxVDiag_Vmentry_GuestSegBaseV86Gs;
-        default:
-            Assert(iSegReg == X86_SREG_SS);
-            return kVmxVDiag_Vmentry_GuestSegBaseV86Ss;
+        case X86_SREG_SS: return kVmxVDiag_Vmentry_GuestSegBaseV86Ss;
+        IEM_NOT_REACHED_DEFAULT_CASE_RET2(kVmxVDiag_Ipe_2);
     }
 }
@@ -2107,7 +2107,6 @@
         case X86_SREG_FS: return kVmxVDiag_Vmentry_GuestSegLimitV86Fs;
         case X86_SREG_GS: return kVmxVDiag_Vmentry_GuestSegLimitV86Gs;
-        default:
-            Assert(iSegReg == X86_SREG_SS);
-            return kVmxVDiag_Vmentry_GuestSegLimitV86Ss;
+        case X86_SREG_SS: return kVmxVDiag_Vmentry_GuestSegLimitV86Ss;
+        IEM_NOT_REACHED_DEFAULT_CASE_RET2(kVmxVDiag_Ipe_2);
     }
 }
@@ -2129,7 +2128,6 @@
         case X86_SREG_FS: return kVmxVDiag_Vmentry_GuestSegAttrV86Fs;
         case X86_SREG_GS: return kVmxVDiag_Vmentry_GuestSegAttrV86Gs;
-        default:
-            Assert(iSegReg == X86_SREG_SS);
-            return kVmxVDiag_Vmentry_GuestSegAttrV86Ss;
+        case X86_SREG_SS: return kVmxVDiag_Vmentry_GuestSegAttrV86Ss;
+        IEM_NOT_REACHED_DEFAULT_CASE_RET2(kVmxVDiag_Ipe_2);
     }
 }
@@ -2151,7 +2149,6 @@
         case X86_SREG_FS: return kVmxVDiag_Vmentry_GuestSegAttrRsvdFs;
         case X86_SREG_GS: return kVmxVDiag_Vmentry_GuestSegAttrRsvdGs;
-        default:
-            Assert(iSegReg == X86_SREG_SS);
-            return kVmxVDiag_Vmentry_GuestSegAttrRsvdSs;
+        case X86_SREG_SS: return kVmxVDiag_Vmentry_GuestSegAttrRsvdSs;
+        IEM_NOT_REACHED_DEFAULT_CASE_RET2(kVmxVDiag_Ipe_2);
     }
 }
@@ -2173,7 +2170,6 @@
         case X86_SREG_FS: return kVmxVDiag_Vmentry_GuestSegAttrDescTypeFs;
         case X86_SREG_GS: return kVmxVDiag_Vmentry_GuestSegAttrDescTypeGs;
-        default:
-            Assert(iSegReg == X86_SREG_SS);
-            return kVmxVDiag_Vmentry_GuestSegAttrDescTypeSs;
+        case X86_SREG_SS: return kVmxVDiag_Vmentry_GuestSegAttrDescTypeSs;
+        IEM_NOT_REACHED_DEFAULT_CASE_RET2(kVmxVDiag_Ipe_2);
     }
 }
@@ -2195,7 +2191,6 @@
         case X86_SREG_FS: return kVmxVDiag_Vmentry_GuestSegAttrPresentFs;
         case X86_SREG_GS: return kVmxVDiag_Vmentry_GuestSegAttrPresentGs;
-        default:
-            Assert(iSegReg == X86_SREG_SS);
-            return kVmxVDiag_Vmentry_GuestSegAttrPresentSs;
+        case X86_SREG_SS: return kVmxVDiag_Vmentry_GuestSegAttrPresentSs;
+        IEM_NOT_REACHED_DEFAULT_CASE_RET2(kVmxVDiag_Ipe_2);
     }
 }
@@ -2217,7 +2212,6 @@
         case X86_SREG_FS: return kVmxVDiag_Vmentry_GuestSegAttrGranFs;
         case X86_SREG_GS: return kVmxVDiag_Vmentry_GuestSegAttrGranGs;
-        default:
-            Assert(iSegReg == X86_SREG_SS);
-            return kVmxVDiag_Vmentry_GuestSegAttrGranSs;
+        case X86_SREG_SS: return kVmxVDiag_Vmentry_GuestSegAttrGranSs;
+        IEM_NOT_REACHED_DEFAULT_CASE_RET2(kVmxVDiag_Ipe_2);
     }
 }
@@ -2238,7 +2232,6 @@
         case X86_SREG_FS: return kVmxVDiag_Vmentry_GuestSegAttrDplRplFs;
         case X86_SREG_GS: return kVmxVDiag_Vmentry_GuestSegAttrDplRplGs;
-        default:
-            Assert(iSegReg == X86_SREG_SS);
-            return kVmxVDiag_Vmentry_GuestSegAttrDplRplSs;
+        case X86_SREG_SS: return kVmxVDiag_Vmentry_GuestSegAttrDplRplSs;
+        IEM_NOT_REACHED_DEFAULT_CASE_RET2(kVmxVDiag_Ipe_2);
     }
 }
@@ -2260,7 +2253,26 @@
         case X86_SREG_FS: return kVmxVDiag_Vmentry_GuestSegAttrTypeAccFs;
         case X86_SREG_GS: return kVmxVDiag_Vmentry_GuestSegAttrTypeAccGs;
-        default:
-            Assert(iSegReg == X86_SREG_SS);
-            return kVmxVDiag_Vmentry_GuestSegAttrTypeAccSs;
+        case X86_SREG_SS: return kVmxVDiag_Vmentry_GuestSegAttrTypeAccSs;
+        IEM_NOT_REACHED_DEFAULT_CASE_RET2(kVmxVDiag_Ipe_2);
+    }
+}
+
+
+/**
+ * Gets the instruction diagnostic for CR3 referenced PDPTE reserved bits failure
+ * during VM-entry of a nested-guest.
+ *
+ * @param   iSegReg     The PDPTE entry index.
+ */
+IEM_STATIC VMXVDIAG iemVmxGetDiagVmentryPdpteRsvd(unsigned iPdpte)
+{
+    Assert(iPdpte < X86_PG_PAE_PDPE_ENTRIES);
+    switch (iPdpte)
+    {
+        case 0: return kVmxVDiag_Vmentry_GuestPdpte0Rsvd;
+        case 1: return kVmxVDiag_Vmentry_GuestPdpte1Rsvd;
+        case 2: return kVmxVDiag_Vmentry_GuestPdpte2Rsvd;
+        case 3: return kVmxVDiag_Vmentry_GuestPdpte3Rsvd;
+        IEM_NOT_REACHED_DEFAULT_CASE_RET2(kVmxVDiag_Ipe_2);
     }
 }
@@ -2872,5 +2884,5 @@
                                 : pVmcs->u64GuestRFlags.s.Lo;
     if (   !(uGuestRFlags & ~(X86_EFL_LIVE_MASK | X86_EFL_RA1_MASK))
-        &&  (uGuestRFlags &  X86_EFL_RA1_MASK) == X86_EFL_RA1_MASK)
+        &&  (uGuestRFlags & X86_EFL_RA1_MASK) == X86_EFL_RA1_MASK)
     { /* likely */ }
     else
@@ -3128,4 +3140,85 @@
 
 /**
+ * Checks if the PDPTEs referenced by the nested-guest CR3 are valid as part of
+ * VM-entry.
+ *
+ * @returns @c true if all PDPTEs are valid, @c false otherwise.
+ * @param   pVCpu       The cross context virtual CPU structure.
+ * @param   pszInstr    The VMX instruction name (for logging purposes).
+ * @param   pVmcs       Pointer to the virtual VMCS.
+ */
+IEM_STATIC int iemVmxVmentryCheckGuestPdptesForCr3(PVMCPU pVCpu, const char *pszInstr, PVMXVVMCS pVmcs)
+{
+    /*
+     * Check PDPTEs.
+     * See Intel spec. 4.4.1 "PDPTE Registers".
+     */
+    uint64_t const uGuestCr3 = pVmcs->u64GuestCr3.u & X86_CR3_PAE_PAGE_MASK;
+    const char *const pszFailure = "VM-exit";
+
+    X86PDPE aPdptes[X86_PG_PAE_PDPE_ENTRIES];
+    int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), (void *)&aPdptes[0], uGuestCr3, sizeof(aPdptes));
+    if (RT_SUCCESS(rc))
+    {
+        for (unsigned iPdpte = 0; iPdpte < RT_ELEMENTS(aPdptes); iPdpte++)
+        {
+            if (   !(aPdptes[iPdpte].u & X86_PDPE_P)
+                || !(aPdptes[iPdpte].u & X86_PDPE_PAE_MBZ_MASK))
+            { /* likely */ }
+            else
+            {
+                pVmcs->u64ExitQual.u = VMX_ENTRY_FAIL_QUAL_PDPTE;
+                VMXVDIAG const enmDiag = iemVmxGetDiagVmentryPdpteRsvd(iPdpte);
+                IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, enmDiag);
+            }
+        }
+    }
+    else
+    {
+        pVmcs->u64ExitQual.u = VMX_ENTRY_FAIL_QUAL_PDPTE;
+        IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestPdpteCr3ReadPhys);
+    }
+
+    NOREF(pszFailure);
+    return rc;
+}
+
+
+/**
+ * Checks guest PDPTEs as part of VM-entry.
+ *
+ * @param   pVCpu           The cross context virtual CPU structure.
+ * @param   pszInstr        The VMX instruction name (for logging purposes).
+ */
+IEM_STATIC int iemVmxVmentryCheckGuestPdptes(PVMCPU pVCpu, const char *pszInstr)
+{
+    /*
+     * Guest PDPTEs.
+     * See Intel spec. 26.3.1.5 "Checks on Guest Page-Directory-Pointer-Table Entries".
+     */
+    PVMXVVMCS pVmcs = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
+    bool const fGstInLongMode = RT_BOOL(pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_IA32E_MODE_GUEST);
+
+    /* Check PDPTes if the VM-entry is to a guest using PAE paging. */
+    int rc;
+    if (   !fGstInLongMode
+        && (pVmcs->u64GuestCr4.u & X86_CR4_PAE)
+        && (pVmcs->u64GuestCr0.u & X86_CR0_PG))
+    {
+        /*
+         * We don't support nested-paging for nested-guests yet.
+         *
+         * Without nested-paging for nested-guests, PDPTEs in the VMCS are not used,
+         * rather we need to check the PDPTEs referenced by the guest CR3.
+         */
+        rc = iemVmxVmentryCheckGuestPdptesForCr3(pVCpu, pszInstr, pVmcs);
+    }
+    else
+        rc = VINF_SUCCESS;
+    return rc;
+}
+
+
+/**
  * Checks guest-state as part of VM-entry.
  *
@@ -3161,4 +3254,10 @@
 
     rc = iemVmxVmentryCheckGuestNonRegState(pVCpu, pszInstr);
+    if (rc == VINF_SUCCESS)
+    { /* likely */ }
+    else
+        return rc;
+
+    rc = iemVmxVmentryCheckGuestPdptes(pVCpu, pszInstr);
     if (rc == VINF_SUCCESS)
     { /* likely */ }
