Changeset 91580 in vbox for trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h
- Timestamp:
- Oct 6, 2021 7:22:04 AM (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h
r91427 r91580 1104 1104 1105 1105 /** 1106 * Gets the instruction diagnostic for guest CR3 referenced PDPTE reserved bits1107 * failure during VM-entry of a nested-guest.1108 *1109 * @param iSegReg The PDPTE entry index.1110 */1111 IEM_STATIC VMXVDIAG iemVmxGetDiagVmentryPdpteRsvd(unsigned iPdpte)1112 {1113 Assert(iPdpte < X86_PG_PAE_PDPE_ENTRIES);1114 switch (iPdpte)1115 {1116 case 0: return kVmxVDiag_Vmentry_GuestPdpte0Rsvd;1117 case 1: return kVmxVDiag_Vmentry_GuestPdpte1Rsvd;1118 case 2: return kVmxVDiag_Vmentry_GuestPdpte2Rsvd;1119 case 3: return kVmxVDiag_Vmentry_GuestPdpte3Rsvd;1120 IEM_NOT_REACHED_DEFAULT_CASE_RET2(kVmxVDiag_Ipe_11);1121 }1122 }1123 1124 1125 /**1126 * Gets the instruction diagnostic for host CR3 referenced PDPTE reserved bits1127 * failure during VM-exit of a nested-guest.1128 *1129 * @param iSegReg The PDPTE entry index.1130 */1131 IEM_STATIC VMXVDIAG iemVmxGetDiagVmexitPdpteRsvd(unsigned iPdpte)1132 {1133 Assert(iPdpte < X86_PG_PAE_PDPE_ENTRIES);1134 switch (iPdpte)1135 {1136 case 0: return kVmxVDiag_Vmexit_HostPdpte0Rsvd;1137 case 1: return kVmxVDiag_Vmexit_HostPdpte1Rsvd;1138 case 2: return kVmxVDiag_Vmexit_HostPdpte2Rsvd;1139 case 3: return kVmxVDiag_Vmexit_HostPdpte3Rsvd;1140 IEM_NOT_REACHED_DEFAULT_CASE_RET2(kVmxVDiag_Ipe_12);1141 }1142 }1143 1144 1145 /**1146 1106 * Saves the guest control registers, debug registers and some MSRs are part of 1147 1107 * VM-exit. … … 1254 1214 1255 1215 /** 1256 * Perform a VMX transition updated PGM, IEM and CPUM. 1257 * 1258 * @param pVCpu The cross context virtual CPU structure. 1259 */ 1260 IEM_STATIC int iemVmxWorldSwitch(PVMCPUCC pVCpu) 1216 * Performs the VMX transition to/from VMX non-root mode. 1217 * 1218 * @param pVCpu The cross context virtual CPU structure. 1219 * @param fPdpesMapped Whether the PAE PDPTEs (and PDPT) have been mapped. 1220 */ 1221 IEM_STATIC int iemVmxTransition(PVMCPUCC pVCpu, bool fPdpesMapped) 1261 1222 { 1262 1223 /* … … 1280 1241 if (rc == VINF_SUCCESS) 1281 1242 { 1282 rc = PGMFlushTLB(pVCpu, pVCpu->cpum.GstCtx.cr3, true );1243 rc = PGMFlushTLB(pVCpu, pVCpu->cpum.GstCtx.cr3, true /* fGlobal */, fPdpesMapped); 1283 1244 AssertRCReturn(rc, rc); 1284 1245 } … … 1903 1864 1904 1865 /** 1905 * Checks host PDPTes as part of VM-exit.1866 * Checks the host PAE PDPTEs assuming we are switching to a PAE mode host. 1906 1867 * 1907 1868 * @param pVCpu The cross context virtual CPU structure. 1908 * @param uExitReason The VM-exit reason (for logging purposes). 1869 * @param uExitReason The VMX instruction name (for logging purposes). 1870 * 1871 * @remarks Caller must ensure the preconditions are met before calling this 1872 * function as failure here will trigger VMX aborts! 1909 1873 */ 1910 1874 IEM_STATIC int iemVmxVmexitCheckHostPdptes(PVMCPUCC pVCpu, uint32_t uExitReason) 1911 1875 { 1912 /* 1913 * Check host PDPTEs. 1914 * See Intel spec. 27.5.4 "Checking and Loading Host Page-Directory-Pointer-Table Entries". 1915 */ 1916 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs; 1917 const char * const pszFailure = "VMX-abort"; 1918 bool const fHostInLongMode = RT_BOOL(pVmcs->u32ExitCtls & VMX_EXIT_CTLS_HOST_ADDR_SPACE_SIZE); 1919 1920 if ( (pVCpu->cpum.GstCtx.cr4 & X86_CR4_PAE) 1921 && !fHostInLongMode) 1922 { 1923 uint64_t const uHostCr3 = pVCpu->cpum.GstCtx.cr3 & X86_CR3_PAE_PAGE_MASK; 1924 X86PDPE aPdptes[X86_PG_PAE_PDPE_ENTRIES]; 1925 int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), (void *)&aPdptes[0], uHostCr3, sizeof(aPdptes)); 1926 if (RT_SUCCESS(rc)) 1927 { 1928 uint8_t idxInvalid; 1929 bool const fValid = CPUMArePaePdpesValid(&aPdptes[0], &idxInvalid); 1930 if (fValid) 1931 { /* likely */ } 1932 else 1933 { 1934 VMXVDIAG const enmDiag = iemVmxGetDiagVmexitPdpteRsvd(idxInvalid); 1935 IEM_VMX_VMEXIT_FAILED_RET(pVCpu, uExitReason, pszFailure, enmDiag); 1936 } 1937 } 1938 else 1939 IEM_VMX_VMEXIT_FAILED_RET(pVCpu, uExitReason, pszFailure, kVmxVDiag_Vmexit_HostPdpteCr3ReadPhys); 1940 } 1941 1942 NOREF(pszFailure); 1943 NOREF(uExitReason); 1944 return VINF_SUCCESS; 1876 PCVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs; 1877 const char * const pszFailure = "VMX-abort"; 1878 int const rc = PGMGstMapPaePdpesAtCr3(pVCpu, pVmcs->u64HostCr3.u); 1879 if (RT_SUCCESS(rc)) 1880 return rc; 1881 IEM_VMX_VMEXIT_FAILED_RET(pVCpu, uExitReason, pszFailure, kVmxVDiag_Vmexit_HostPdpte); 1945 1882 } 1946 1883 … … 1950 1887 * 1951 1888 * @returns VBox status code. 1952 * @param pVCpu The cross context virtual CPU structure.1953 * @param pszInstrThe VMX instruction name (for logging purposes).1889 * @param pVCpu The cross context virtual CPU structure. 1890 * @param uExitReason The VMX instruction name (for logging purposes). 1954 1891 */ 1955 1892 IEM_STATIC int iemVmxVmexitLoadHostAutoMsrs(PVMCPUCC pVCpu, uint32_t uExitReason) … … 2054 1991 } 2055 1992 1993 /* 1994 * Check host PAE PDPTEs prior to loading the host state. 1995 * See Intel spec. 26.5.4 "Checking and Loading Host Page-Directory-Pointer-Table Entries". 1996 */ 1997 bool fPdpesMapped; 1998 if ( (pVmcs->u64HostCr4.u & X86_CR4_PAE) 1999 && !fHostInLongMode 2000 && ( !CPUMIsGuestInPAEModeEx(&pVCpu->cpum.GstCtx) 2001 || pVmcs->u64HostCr3.u != pVCpu->cpum.GstCtx.cr3)) 2002 { 2003 int const rc = iemVmxVmexitCheckHostPdptes(pVCpu, uExitReason); 2004 if (RT_FAILURE(rc)) 2005 { 2006 Log(("VM-exit attempting to load invalid PDPTEs -> VMX-Abort\n")); 2007 return iemVmxAbort(pVCpu, VMXBOART_HOST_PDPTE); 2008 } 2009 fPdpesMapped = true; 2010 } 2011 else 2012 fPdpesMapped = false; 2013 2056 2014 iemVmxVmexitLoadHostControlRegsMsrs(pVCpu); 2057 2015 iemVmxVmexitLoadHostSegRegs(pVCpu); … … 2069 2027 2070 2028 /* Perform the VMX transition (PGM updates). */ 2071 VBOXSTRICTRC rcStrict = iemVmx WorldSwitch(pVCpu);2029 VBOXSTRICTRC rcStrict = iemVmxTransition(pVCpu, fPdpesMapped); 2072 2030 if (rcStrict == VINF_SUCCESS) 2073 { 2074 /* Check host PDPTEs (only when we've fully switched page tables_. */ 2075 /** @todo r=ramshankar: I don't know if PGM does this for us already or not... */ 2076 int rc = iemVmxVmexitCheckHostPdptes(pVCpu, uExitReason); 2077 if (RT_FAILURE(rc)) 2078 { 2079 Log(("VM-exit failed while restoring host PDPTEs -> VMX-Abort\n")); 2080 return iemVmxAbort(pVCpu, VMXBOART_HOST_PDPTE); 2081 } 2082 } 2031 { /* likely */ } 2083 2032 else if (RT_SUCCESS(rcStrict)) 2084 2033 { 2085 Log3(("VM-exit: iemVmx WorldSwitchreturns %Rrc (uExitReason=%u) -> Setting passup status\n", VBOXSTRICTRC_VAL(rcStrict),2034 Log3(("VM-exit: iemVmxTransition returns %Rrc (uExitReason=%u) -> Setting passup status\n", VBOXSTRICTRC_VAL(rcStrict), 2086 2035 uExitReason)); 2087 2036 rcStrict = iemSetPassUpStatus(pVCpu, rcStrict); … … 2089 2038 else 2090 2039 { 2091 Log3(("VM-exit: iemVmx WorldSwitchfailed! rc=%Rrc (uExitReason=%u)\n", VBOXSTRICTRC_VAL(rcStrict), uExitReason));2040 Log3(("VM-exit: iemVmxTransition failed! rc=%Rrc (uExitReason=%u)\n", VBOXSTRICTRC_VAL(rcStrict), uExitReason)); 2092 2041 return VBOXSTRICTRC_VAL(rcStrict); 2093 2042 } … … 5643 5592 * Checks guest PDPTEs as part of VM-entry. 5644 5593 * 5645 * @param pVCpu The cross context virtual CPU structure. 5646 * @param pszInstr The VMX instruction name (for logging purposes). 5647 */ 5648 IEM_STATIC int iemVmxVmentryCheckGuestPdptes(PVMCPUCC pVCpu, const char *pszInstr) 5594 * @param pVCpu The cross context virtual CPU structure. 5595 * @param pfPdpesMapped Where to store whether PAE PDPTEs (and PDPT) have been 5596 * mapped as part of checking guest state. 5597 * @param pszInstr The VMX instruction name (for logging purposes). 5598 */ 5599 IEM_STATIC int iemVmxVmentryCheckGuestPdptes(PVMCPUCC pVCpu, bool *pfPdpesMapped, const char *pszInstr) 5649 5600 { 5650 5601 /* … … 5654 5605 PVMXVVMCS const pVmcs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Vmcs; 5655 5606 const char * const pszFailure = "VM-exit"; 5607 *pfPdpesMapped = false; 5656 5608 5657 5609 if ( !(pVmcs->u32EntryCtls & VMX_ENTRY_CTLS_IA32E_MODE_GUEST) … … 5659 5611 && (pVmcs->u64GuestCr0.u & X86_CR0_PG)) 5660 5612 { 5661 /* Get the PDPTEs. */5662 X86PDPE aPdptes[X86_PG_PAE_PDPE_ENTRIES];5663 5613 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT 5664 5614 if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_EPT) 5665 5615 { 5666 aPdptes[0].u = pVmcs->u64GuestPdpte0.u; 5667 aPdptes[1].u = pVmcs->u64GuestPdpte1.u; 5668 aPdptes[2].u = pVmcs->u64GuestPdpte2.u; 5669 aPdptes[3].u = pVmcs->u64GuestPdpte3.u; 5670 } 5671 else 5672 #endif 5673 { 5674 uint64_t const uGuestCr3 = pVmcs->u64GuestCr3.u & X86_CR3_PAE_PAGE_MASK; 5675 int const rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), (void *)&aPdptes[0], uGuestCr3, sizeof(aPdptes)); 5676 if (RT_FAILURE(rc)) 5616 /* Get PDPTEs from the VMCS. */ 5617 X86PDPE aPaePdptes[X86_PG_PAE_PDPE_ENTRIES]; 5618 aPaePdptes[0].u = pVmcs->u64GuestPdpte0.u; 5619 aPaePdptes[1].u = pVmcs->u64GuestPdpte1.u; 5620 aPaePdptes[2].u = pVmcs->u64GuestPdpte2.u; 5621 aPaePdptes[3].u = pVmcs->u64GuestPdpte3.u; 5622 5623 /* Check validity of the PDPTEs. */ 5624 bool const fValid = PGMGstArePaePdpesValid(pVCpu, &aPaePdptes[0]); 5625 if (fValid) 5626 { /* likely */ } 5627 else 5677 5628 { 5678 5629 iemVmxVmcsSetExitQual(pVCpu, VMX_ENTRY_FAIL_QUAL_PDPTE); 5679 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestPdpte Cr3ReadPhys);5630 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestPdpte); 5680 5631 } 5681 5632 } 5682 5683 /* Check validity of the PDPTEs. */ 5684 uint8_t idxInvalid;5685 bool const fValid = CPUMArePaePdpesValid(&aPdptes[0], &idxInvalid);5686 if (fValid)5687 { /* likely */ }5688 else5689 {5690 VMXVDIAG const enmDiag = iemVmxGetDiagVmentryPdpteRsvd(idxInvalid);5691 iemVmxVmcsSetExitQual(pVCpu, VMX_ENTRY_FAIL_QUAL_PDPTE);5692 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, enmDiag);5633 else 5634 #endif 5635 { 5636 int const rc = PGMGstMapPaePdpesAtCr3(pVCpu, pVmcs->u64GuestCr3.u); 5637 if (rc == VINF_SUCCESS) 5638 *pfPdpesMapped = true; 5639 else 5640 { 5641 iemVmxVmcsSetExitQual(pVCpu, VMX_ENTRY_FAIL_QUAL_PDPTE); 5642 IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_GuestPdpte); 5643 } 5693 5644 } 5694 5645 } … … 5704 5655 * 5705 5656 * @returns VBox status code. 5706 * @param pVCpu The cross context virtual CPU structure. 5707 * @param pszInstr The VMX instruction name (for logging purposes). 5708 */ 5709 IEM_STATIC int iemVmxVmentryCheckGuestState(PVMCPUCC pVCpu, const char *pszInstr) 5657 * @param pVCpu The cross context virtual CPU structure. 5658 * @param pfPdpesMapped Where to store whether PAE PDPTEs (and PDPT) have been 5659 * mapped as part of checking guest state. 5660 * @param pszInstr The VMX instruction name (for logging purposes). 5661 */ 5662 IEM_STATIC int iemVmxVmentryCheckGuestState(PVMCPUCC pVCpu, bool *pfPdpesMapped, const char *pszInstr) 5710 5663 { 5711 5664 int rc = iemVmxVmentryCheckGuestControlRegsMsrs(pVCpu, pszInstr); … … 5723 5676 rc = iemVmxVmentryCheckGuestNonRegState(pVCpu, pszInstr); 5724 5677 if (RT_SUCCESS(rc)) 5725 return iemVmxVmentryCheckGuestPdptes(pVCpu, p szInstr);5678 return iemVmxVmentryCheckGuestPdptes(pVCpu, pfPdpesMapped, pszInstr); 5726 5679 } 5727 5680 } … … 7419 7372 iemVmxVmentrySaveNmiBlockingFF(pVCpu); 7420 7373 7421 rc = iemVmxVmentryCheckGuestState(pVCpu, pszInstr); 7374 bool fPdpesMapped; 7375 rc = iemVmxVmentryCheckGuestState(pVCpu, &fPdpesMapped, pszInstr); 7422 7376 if (RT_SUCCESS(rc)) 7423 7377 { … … 7435 7389 7436 7390 /* Perform the VMX transition (PGM updates). */ 7437 VBOXSTRICTRC rcStrict = iemVmx WorldSwitch(pVCpu);7391 VBOXSTRICTRC rcStrict = iemVmxTransition(pVCpu, fPdpesMapped); 7438 7392 if (rcStrict == VINF_SUCCESS) 7439 7393 { /* likely */ } 7440 7394 else if (RT_SUCCESS(rcStrict)) 7441 7395 { 7442 Log3(("%s: iemVmx WorldSwitchreturns %Rrc -> Setting passup status\n", pszInstr,7396 Log3(("%s: iemVmxTransition returns %Rrc -> Setting passup status\n", pszInstr, 7443 7397 VBOXSTRICTRC_VAL(rcStrict))); 7444 7398 rcStrict = iemSetPassUpStatus(pVCpu, rcStrict); … … 7446 7400 else 7447 7401 { 7448 Log3(("%s: iemVmx WorldSwitchfailed! rc=%Rrc\n", pszInstr, VBOXSTRICTRC_VAL(rcStrict)));7402 Log3(("%s: iemVmxTransition failed! rc=%Rrc\n", pszInstr, VBOXSTRICTRC_VAL(rcStrict))); 7449 7403 return rcStrict; 7450 7404 } … … 8437 8391 /* Invalidate mappings for the linear address tagged with VPID. */ 8438 8392 /** @todo PGM support for VPID? Currently just flush everything. */ 8439 PGMFlushTLB(pVCpu, uCr3, true /* fGlobal */ );8393 PGMFlushTLB(pVCpu, uCr3, true /* fGlobal */, false /* fPdpesMapped */); 8440 8394 iemVmxVmSucceed(pVCpu); 8441 8395 } … … 8464 8418 /* Invalidate all mappings with VPID. */ 8465 8419 /** @todo PGM support for VPID? Currently just flush everything. */ 8466 PGMFlushTLB(pVCpu, uCr3, true /* fGlobal */ );8420 PGMFlushTLB(pVCpu, uCr3, true /* fGlobal */, false /* fPdpesMapped */); 8467 8421 iemVmxVmSucceed(pVCpu); 8468 8422 } … … 8481 8435 /* Invalidate all mappings with non-zero VPIDs. */ 8482 8436 /** @todo PGM support for VPID? Currently just flush everything. */ 8483 PGMFlushTLB(pVCpu, uCr3, true /* fGlobal */ );8437 PGMFlushTLB(pVCpu, uCr3, true /* fGlobal */, false /* fPdpesMapped */); 8484 8438 iemVmxVmSucceed(pVCpu); 8485 8439 break; … … 8492 8446 /* Invalidate all mappings with VPID except global translations. */ 8493 8447 /** @todo PGM support for VPID? Currently just flush everything. */ 8494 PGMFlushTLB(pVCpu, uCr3, true /* fGlobal */ );8448 PGMFlushTLB(pVCpu, uCr3, true /* fGlobal */, false /* fPdpesMapped */); 8495 8449 iemVmxVmSucceed(pVCpu); 8496 8450 }
Note:
See TracChangeset
for help on using the changeset viewer.