From: Lai Jiangshan <jiangshan.ljs@xxxxxxxxxxxx> Feed the nested page fault info into ->gva_to_gpa() in walk_addr_generic(), so that the nested walk_addr_generic() can propagate the nested page fault info into x86_exception. Propagate the nested page fault info into EXIT_INFO_1 for SVM. Morph the nested page fault info and other page fault error code into EXIT_QUOLIFICATION for VMX. It is a patch that makes use of the patch1. It is untested, just served as a request for somebody to fix a known problem, and will not be included in next version of this patchset if the patchset needs to be updated. Signed-off-by: Lai Jiangshan <jiangshan.ljs@xxxxxxxxxxxx> --- arch/x86/include/asm/kvm_host.h | 2 ++ arch/x86/kvm/kvm_emulate.h | 3 ++- arch/x86/kvm/mmu/paging_tmpl.h | 8 ++++++-- arch/x86/kvm/svm/nested.c | 10 ++-------- arch/x86/kvm/vmx/nested.c | 11 +++++++++++ 5 files changed, 23 insertions(+), 11 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 565d9eb42429..68efa9d1ef0e 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -265,6 +265,8 @@ enum x86_intercept_stage; PFERR_WRITE_MASK | \ PFERR_PRESENT_MASK) +#define PFERR_GUEST_MASK (PFERR_GUEST_FINAL_MASK | PFERR_GUEST_PAGE_MASK) + /* apic attention bits */ #define KVM_APIC_CHECK_VAPIC 0 /* diff --git a/arch/x86/kvm/kvm_emulate.h b/arch/x86/kvm/kvm_emulate.h index 39eded2426ff..cdc2977ce086 100644 --- a/arch/x86/kvm/kvm_emulate.h +++ b/arch/x86/kvm/kvm_emulate.h @@ -24,8 +24,9 @@ struct x86_exception { bool error_code_valid; u16 error_code; bool nested_page_fault; - u64 address; /* cr2 or nested page fault gpa */ u8 async_page_fault; + u64 nested_pfec; /* nested page fault error code */ + u64 address; /* cr2 or nested page fault gpa */ }; /* diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index 8621188b46df..95367f5ca998 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -383,7 +383,8 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, * by the MOV to CR instruction are treated as reads and do not cause the * processor to set the dirty flag in any EPT paging-structure entry. */ - nested_access = (have_ad ? PFERR_WRITE_MASK : 0) | PFERR_USER_MASK; + nested_access = (have_ad ? PFERR_WRITE_MASK : 0) | PFERR_USER_MASK | + PFERR_GUEST_PAGE_MASK; pte_access = ~0; ++walker->level; @@ -466,7 +467,8 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, if (PTTYPE == 32 && walker->level > PG_LEVEL_4K && is_cpuid_PSE36()) gfn += pse36_gfn_delta(pte); - real_gpa = kvm_translate_gpa(vcpu, mmu, gfn_to_gpa(gfn), access, &walker->fault); + real_gpa = kvm_translate_gpa(vcpu, mmu, gfn_to_gpa(gfn), + access | PFERR_GUEST_FINAL_MASK, &walker->fault); if (real_gpa == UNMAPPED_GVA) return 0; @@ -534,6 +536,8 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, walker->fault.address = addr; walker->fault.nested_page_fault = mmu != vcpu->arch.walk_mmu; walker->fault.async_page_fault = false; + if (walker->fault.nested_page_fault) + walker->fault.nested_pfec = errcode | (access & PFERR_GUEST_MASK); trace_kvm_mmu_walker_error(walker->fault.error_code); return 0; diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index 96bab464967f..0abcbd3de892 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -38,18 +38,12 @@ static void nested_svm_inject_npf_exit(struct kvm_vcpu *vcpu, struct vcpu_svm *svm = to_svm(vcpu); if (svm->vmcb->control.exit_code != SVM_EXIT_NPF) { - /* - * TODO: track the cause of the nested page fault, and - * correctly fill in the high bits of exit_info_1. - */ svm->vmcb->control.exit_code = SVM_EXIT_NPF; svm->vmcb->control.exit_code_hi = 0; - svm->vmcb->control.exit_info_1 = (1ULL << 32); - svm->vmcb->control.exit_info_2 = fault->address; } - svm->vmcb->control.exit_info_1 &= ~0xffffffffULL; - svm->vmcb->control.exit_info_1 |= fault->error_code; + svm->vmcb->control.exit_info_1 = fault->nested_pfec; + svm->vmcb->control.exit_info_2 = fault->address; nested_svm_vmexit(svm); } diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 1dfe23963a9e..fd5dd5acf63b 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -372,6 +372,17 @@ static void nested_ept_inject_page_fault(struct kvm_vcpu *vcpu, u32 vm_exit_reason; unsigned long exit_qualification = vcpu->arch.exit_qualification; + exit_qualification &= ~(EPT_VIOLATION_ACC_READ | EPT_VIOLATION_ACC_WRITE | + EPT_VIOLATION_ACC_INSTR | EPT_VIOLATION_GVA_TRANSLATED); + exit_qualification |= fault->nested_pfec & PFERR_USER_MASK ? + EPT_VIOLATION_ACC_READ : 0; + exit_qualification |= fault->nested_pfec & PFERR_WRITE_MASK ? + EPT_VIOLATION_ACC_WRITE : 0; + exit_qualification |= fault->nested_pfec & PFERR_FETCH_MASK ? + EPT_VIOLATION_ACC_INSTR : 0; + exit_qualification |= fault->nested_pfec & PFERR_GUEST_FINAL_MASK ? + EPT_VIOLATION_GVA_TRANSLATED : 0; + if (vmx->nested.pml_full) { vm_exit_reason = EXIT_REASON_PML_FULL; vmx->nested.pml_full = false; -- 2.19.1.6.gb485710b