From 9060aa00e0ebb503ced3337d3156eb620f30d4fc Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 15 Jan 2019 00:21:17 +0400 Subject: [PATCH 1/2] Avoid flushing outdated PDPTE0..3 cache to VMCS Signed-off-by: Alexey Romko --- core/include/vcpu.h | 3 ++- core/vcpu.c | 19 +++++++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/core/include/vcpu.h b/core/include/vcpu.h index b3ff6bd1..2a842b8f 100644 --- a/core/include/vcpu.h +++ b/core/include/vcpu.h @@ -200,7 +200,8 @@ struct vcpu_t { uint64_t fs_base_dirty : 1; uint64_t interruptibility_dirty : 1; uint64_t pcpu_ctls_dirty : 1; - uint64_t padding : 46; + uint64_t pae_pdpt_dirty : 1; + uint64_t padding : 45; }; /* For TSC offseting feature*/ diff --git a/core/vcpu.c b/core/vcpu.c index 6bf32a22..52b091b0 100644 --- a/core/vcpu.c +++ b/core/vcpu.c @@ -1859,6 +1859,7 @@ static int vcpu_prepare_pae_pdpt(struct vcpu_t *vcpu) cr3, ret); return ret < 0 ? ret : -EIO; } + vcpu->pae_pdpt_dirty = 1; return 0; #else // !CONFIG_HAX_EPT2 uint64_t gpfn = (cr3 & 0xfffff000) >> PG_ORDER_4K; @@ -1880,6 +1881,7 @@ static int vcpu_prepare_pae_pdpt(struct vcpu_t *vcpu) #else // !HAX_ARCH_X86_64, i.e. HAX_ARCH_X86_32 hax_unmap_gpfn(vcpu->vm, buf, gpfn); #endif // HAX_ARCH_X86_64 + vcpu->pae_pdpt_dirty = 1; return 0; #endif // CONFIG_HAX_EPT2 } @@ -1966,16 +1968,21 @@ static void vmwrite_cr(struct vcpu_t *vcpu) // eptp); vmwrite(vcpu, GUEST_CR3, state->_cr3); scpu_ctls |= ENABLE_EPT; - // Set PDPTEs for vCPU if it's in or about to enter PAE paging mode - if ((state->_cr4 & CR4_PAE) && !(state->_efer & IA32_EFER_LME) && - (state->_cr0 & CR0_PG)) { - // vcpu_prepare_pae_pdpt() has populated vcpu->pae_pdptes - // TODO: Enable CR3_LOAD_EXITING so as to update vcpu->pae_pdptes - // whenever guest writes to CR3 in EPT+PAE mode + if (vcpu->pae_pdpt_dirty) { + // vcpu_prepare_pae_pdpt() has updated vcpu->pae_pdptes + // Note that because we do not monitor guest writes to CR3, the only + // case where vcpu->pae_pdptes is newer than VMCS GUEST_PDPTE{0..3} + // is following a guest write to CR0 or CR4 that requires PDPTEs to + // be reloaded, i.e. the pae_pdpt_dirty case. When the guest is in + // PAE paging mode but !pae_pdpt_dirty, VMCS GUEST_PDPTE{0..3} are + // already up-to-date following each VM exit (see Intel SDM Vol. 3C + // 27.3.4), and we must not overwrite them with our cached values + // (vcpu->pae_pdptes), which may be outdated. vmwrite(vcpu, GUEST_PDPTE0, vcpu->pae_pdptes[0]); vmwrite(vcpu, GUEST_PDPTE1, vcpu->pae_pdptes[1]); vmwrite(vcpu, GUEST_PDPTE2, vcpu->pae_pdptes[2]); vmwrite(vcpu, GUEST_PDPTE3, vcpu->pae_pdptes[3]); + vcpu->pae_pdpt_dirty = 0; } vmwrite(vcpu, VMX_EPTP, eptp); // pcpu_ctls |= RDTSC_EXITING; From ecd359f1cee49dc6e2fcea00c19c0d39ea5c4ae7 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 15 Jan 2019 00:21:42 +0400 Subject: [PATCH 2/2] page_walker: Fix PAE PDPT pointer calculation Signed-off-by: Alexey Romko --- core/page_walker.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/core/page_walker.c b/core/page_walker.c index 68deeb8f..9b0f1c5b 100644 --- a/core/page_walker.c +++ b/core/page_walker.c @@ -616,6 +616,8 @@ uint32_t pw_perform_page_walk( first_table = pw_retrieve_table_from_cr3(cr3, is_pae, is_lme); if (is_pae) { + uint8_t *pdpt_page_hva; + if (is_lme) { pml4t_gpa = first_table; #ifdef CONFIG_HAX_EPT2 @@ -655,21 +657,24 @@ uint32_t pw_perform_page_walk( } #ifdef CONFIG_HAX_EPT2 - pdpt_hva = gpa_space_map_page(&vcpu->vm->gpa_space, - pdpt_gpa >> PG_ORDER_4K, - &pdpt_kmap, NULL); + pdpt_page_hva = gpa_space_map_page(&vcpu->vm->gpa_space, + pdpt_gpa >> PG_ORDER_4K, + &pdpt_kmap, NULL); #else // !CONFIG_HAX_EPT2 #ifdef HAX_ARCH_X86_32 - pdpt_hva = hax_map_gpfn(vcpu->vm, pdpt_gpa >> 12, is_kernel, cr3, 1); + pdpt_page_hva = hax_map_gpfn(vcpu->vm, pdpt_gpa >> 12, is_kernel, cr3, 1); #else - pdpt_hva = hax_map_gpfn(vcpu->vm, pdpt_gpa >> 12); + pdpt_page_hva = hax_map_gpfn(vcpu->vm, pdpt_gpa >> 12); #endif #endif // CONFIG_HAX_EPT2 - if (pdpt_hva == NULL) { + if (pdpt_page_hva == NULL) { retval = TF_FAILED; goto out; } + // In PAE paging mode, pdpt_gpa is 32-byte aligned, not 4KB-aligned + pdpt_hva = pdpt_page_hva + (uint)(pdpt_gpa & (PAGE_SIZE_4K - 1)); + pdpte_ptr = pw_retrieve_table_entry(vcpu, pdpt_hva, pdpte_index, is_pae); pw_read_entry_value(&pdpte_val, pdpte_ptr, is_pae);