KVM: nSVM: propagate the NPF EXITINFO to the guest
authorPaolo Bonzini <pbonzini@redhat.com>
Tue, 2 Sep 2014 11:18:37 +0000 (13:18 +0200)
committerPaolo Bonzini <pbonzini@redhat.com>
Wed, 3 Sep 2014 08:18:54 +0000 (10:18 +0200)
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>
arch/x86/kvm/paging_tmpl.h
arch/x86/kvm/svm.c

index 410776528265898abaac0d6f8a816e7413c0edc4..df1a044d92de125928b45f00d49deb3e7d50591a 100644 (file)
@@ -322,8 +322,20 @@ retry_walk:
 
                real_gfn = mmu->translate_gpa(vcpu, gfn_to_gpa(table_gfn),
                                              PFERR_USER_MASK|PFERR_WRITE_MASK);
+
+               /*
+                * FIXME: This can happen if emulation (for of an INS/OUTS
+                * instruction) triggers a nested page fault.  The exit
+                * qualification / exit info field will incorrectly have
+                * "guest page access" as the nested page fault's cause,
+                * instead of "guest page structure access".  To fix this,
+                * the x86_exception struct should be augmented with enough
+                * information to fix the exit_qualification or exit_info_1
+                * fields.
+                */
                if (unlikely(real_gfn == UNMAPPED_GVA))
                        goto error;
+
                real_gfn = gpa_to_gfn(real_gfn);
 
                host_addr = gfn_to_hva_prot(vcpu->kvm, real_gfn,
index 8ef70403737045d953fd680a1ca6ec794f55d0e3..d0a61a05a891309ea2f2f7037d64137d6d791d89 100644 (file)
@@ -1974,10 +1974,26 @@ static void nested_svm_inject_npf_exit(struct kvm_vcpu *vcpu,
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
-       svm->vmcb->control.exit_code = SVM_EXIT_NPF;
-       svm->vmcb->control.exit_code_hi = 0;
-       svm->vmcb->control.exit_info_1 = fault->error_code;
-       svm->vmcb->control.exit_info_2 = fault->address;
+       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;
+
+       /*
+        * The present bit is always zero for page structure faults on real
+        * hardware.
+        */
+       if (svm->vmcb->control.exit_info_1 & (2ULL << 32))
+               svm->vmcb->control.exit_info_1 &= ~1;
 
        nested_svm_vmexit(svm);
 }