diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2014-09-02 07:18:37 -0400 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2014-09-03 04:18:54 -0400 |
commit | 5e352519519623a0b62587c606280e534d0cf1d9 (patch) | |
tree | 776ecf76c11f6092c28d2125e7e79cd49a937f9b | |
parent | a0c0feb57992c5caed170feab8a68c51306eb7c3 (diff) |
KVM: nSVM: propagate the NPF EXITINFO to the guest
This is similar to what the EPT code does with the exit qualification.
This allows the guest to see a valid value for bits 33:32.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r-- | arch/x86/kvm/paging_tmpl.h | 12 | ||||
-rw-r--r-- | arch/x86/kvm/svm.c | 24 |
2 files changed, 32 insertions, 4 deletions
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index 410776528265..df1a044d92de 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h | |||
@@ -322,8 +322,20 @@ retry_walk: | |||
322 | 322 | ||
323 | real_gfn = mmu->translate_gpa(vcpu, gfn_to_gpa(table_gfn), | 323 | real_gfn = mmu->translate_gpa(vcpu, gfn_to_gpa(table_gfn), |
324 | PFERR_USER_MASK|PFERR_WRITE_MASK); | 324 | PFERR_USER_MASK|PFERR_WRITE_MASK); |
325 | |||
326 | /* | ||
327 | * FIXME: This can happen if emulation (for of an INS/OUTS | ||
328 | * instruction) triggers a nested page fault. The exit | ||
329 | * qualification / exit info field will incorrectly have | ||
330 | * "guest page access" as the nested page fault's cause, | ||
331 | * instead of "guest page structure access". To fix this, | ||
332 | * the x86_exception struct should be augmented with enough | ||
333 | * information to fix the exit_qualification or exit_info_1 | ||
334 | * fields. | ||
335 | */ | ||
325 | if (unlikely(real_gfn == UNMAPPED_GVA)) | 336 | if (unlikely(real_gfn == UNMAPPED_GVA)) |
326 | goto error; | 337 | goto error; |
338 | |||
327 | real_gfn = gpa_to_gfn(real_gfn); | 339 | real_gfn = gpa_to_gfn(real_gfn); |
328 | 340 | ||
329 | host_addr = gfn_to_hva_prot(vcpu->kvm, real_gfn, | 341 | host_addr = gfn_to_hva_prot(vcpu->kvm, real_gfn, |
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 8ef704037370..d0a61a05a891 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
@@ -1974,10 +1974,26 @@ static void nested_svm_inject_npf_exit(struct kvm_vcpu *vcpu, | |||
1974 | { | 1974 | { |
1975 | struct vcpu_svm *svm = to_svm(vcpu); | 1975 | struct vcpu_svm *svm = to_svm(vcpu); |
1976 | 1976 | ||
1977 | svm->vmcb->control.exit_code = SVM_EXIT_NPF; | 1977 | if (svm->vmcb->control.exit_code != SVM_EXIT_NPF) { |
1978 | svm->vmcb->control.exit_code_hi = 0; | 1978 | /* |
1979 | svm->vmcb->control.exit_info_1 = fault->error_code; | 1979 | * TODO: track the cause of the nested page fault, and |
1980 | svm->vmcb->control.exit_info_2 = fault->address; | 1980 | * correctly fill in the high bits of exit_info_1. |
1981 | */ | ||
1982 | svm->vmcb->control.exit_code = SVM_EXIT_NPF; | ||
1983 | svm->vmcb->control.exit_code_hi = 0; | ||
1984 | svm->vmcb->control.exit_info_1 = (1ULL << 32); | ||
1985 | svm->vmcb->control.exit_info_2 = fault->address; | ||
1986 | } | ||
1987 | |||
1988 | svm->vmcb->control.exit_info_1 &= ~0xffffffffULL; | ||
1989 | svm->vmcb->control.exit_info_1 |= fault->error_code; | ||
1990 | |||
1991 | /* | ||
1992 | * The present bit is always zero for page structure faults on real | ||
1993 | * hardware. | ||
1994 | */ | ||
1995 | if (svm->vmcb->control.exit_info_1 & (2ULL << 32)) | ||
1996 | svm->vmcb->control.exit_info_1 &= ~1; | ||
1981 | 1997 | ||
1982 | nested_svm_vmexit(svm); | 1998 | nested_svm_vmexit(svm); |
1983 | } | 1999 | } |