@@ -1859,6 +1859,7 @@ static int vcpu_prepare_pae_pdpt(struct vcpu_t *vcpu)
18591859 cr3 , ret );
18601860 return ret < 0 ? ret : - EIO ;
18611861 }
1862+ vcpu -> pae_pdpt_dirty = 1 ;
18621863 return 0 ;
18631864#else // !CONFIG_HAX_EPT2
18641865 uint64_t gpfn = (cr3 & 0xfffff000 ) >> PG_ORDER_4K ;
@@ -1880,6 +1881,7 @@ static int vcpu_prepare_pae_pdpt(struct vcpu_t *vcpu)
18801881#else // !HAX_ARCH_X86_64, i.e. HAX_ARCH_X86_32
18811882 hax_unmap_gpfn (vcpu -> vm , buf , gpfn );
18821883#endif // HAX_ARCH_X86_64
1884+ vcpu -> pae_pdpt_dirty = 1 ;
18831885 return 0 ;
18841886#endif // CONFIG_HAX_EPT2
18851887}
@@ -1966,16 +1968,21 @@ static void vmwrite_cr(struct vcpu_t *vcpu)
19661968 // eptp);
19671969 vmwrite (vcpu , GUEST_CR3 , state -> _cr3 );
19681970 scpu_ctls |= ENABLE_EPT ;
1969- // Set PDPTEs for vCPU if it's in or about to enter PAE paging mode
1970- if ((state -> _cr4 & CR4_PAE ) && !(state -> _efer & IA32_EFER_LME ) &&
1971- (state -> _cr0 & CR0_PG )) {
1972- // vcpu_prepare_pae_pdpt() has populated vcpu->pae_pdptes
1973- // TODO: Enable CR3_LOAD_EXITING so as to update vcpu->pae_pdptes
1974- // whenever guest writes to CR3 in EPT+PAE mode
1971+ if (vcpu -> pae_pdpt_dirty ) {
1972+ // vcpu_prepare_pae_pdpt() has updated vcpu->pae_pdptes
1973+ // Note that because we do not monitor guest writes to CR3, the only
1974+ // case where vcpu->pae_pdptes is newer than VMCS GUEST_PDPTE{0..3}
1975+ // is following a guest write to CR0 or CR4 that requires PDPTEs to
1976+ // be reloaded, i.e. the pae_pdpt_dirty case. When the guest is in
1977+ // PAE paging mode but !pae_pdpt_dirty, VMCS GUEST_PDPTE{0..3} are
1978+ // already up-to-date following each VM exit (see Intel SDM Vol. 3C
1979+ // 27.3.4), and we must not overwrite them with our cached values
1980+ // (vcpu->pae_pdptes), which may be outdated.
19751981 vmwrite (vcpu , GUEST_PDPTE0 , vcpu -> pae_pdptes [0 ]);
19761982 vmwrite (vcpu , GUEST_PDPTE1 , vcpu -> pae_pdptes [1 ]);
19771983 vmwrite (vcpu , GUEST_PDPTE2 , vcpu -> pae_pdptes [2 ]);
19781984 vmwrite (vcpu , GUEST_PDPTE3 , vcpu -> pae_pdptes [3 ]);
1985+ vcpu -> pae_pdpt_dirty = 0 ;
19791986 }
19801987 vmwrite (vcpu , VMX_EPTP , eptp );
19811988 // pcpu_ctls |= RDTSC_EXITING;
0 commit comments