]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - arch/x86/kvm/svm.c
KVM; SVM: Add correct handling of nested iopm
[mirror_ubuntu-artful-kernel.git] / arch / x86 / kvm / svm.c
index 7cb2eb906ecad81c3f727b52ec2cb960cb41aadb..ddea391e78cd7e271a07921ea87b48ac742981db 100644 (file)
@@ -79,6 +79,7 @@ struct nested_state {
 
        /* gpa pointers to the real vectors */
        u64 vmcb_msrpm;
+       u64 vmcb_iopm;
 
        /* A VMEXIT is required but not yet emulated */
        bool exit_required;
@@ -1658,6 +1659,26 @@ static void nested_svm_unmap(struct page *page)
        kvm_release_page_dirty(page);
 }
 
+static int nested_svm_intercept_ioio(struct vcpu_svm *svm)
+{
+       unsigned port;
+       u8 val, bit;
+       u64 gpa;
+
+       if (!(svm->nested.intercept & (1ULL << INTERCEPT_IOIO_PROT)))
+               return NESTED_EXIT_HOST;
+
+       port = svm->vmcb->control.exit_info_1 >> 16;
+       gpa  = svm->nested.vmcb_iopm + (port / 8);
+       bit  = port % 8;
+       val  = 0;
+
+       if (kvm_read_guest(svm->vcpu.kvm, gpa, &val, 1))
+               val &= (1 << bit);
+
+       return val ? NESTED_EXIT_DONE : NESTED_EXIT_HOST;
+}
+
 static int nested_svm_exit_handled_msr(struct vcpu_svm *svm)
 {
        u32 offset, msr, value;
@@ -1723,6 +1744,9 @@ static int nested_svm_intercept(struct vcpu_svm *svm)
        case SVM_EXIT_MSR:
                vmexit = nested_svm_exit_handled_msr(svm);
                break;
+       case SVM_EXIT_IOIO:
+               vmexit = nested_svm_intercept_ioio(svm);
+               break;
        case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR8: {
                u32 cr_bits = 1 << (exit_code - SVM_EXIT_READ_CR0);
                if (svm->nested.intercept_cr_read & cr_bits)
@@ -2047,6 +2071,7 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm)
        svm->vmcb->save.cpl = nested_vmcb->save.cpl;
 
        svm->nested.vmcb_msrpm = nested_vmcb->control.msrpm_base_pa;
+       svm->nested.vmcb_iopm  = nested_vmcb->control.iopm_base_pa  & ~0x0fffULL;
 
        /* cache intercepts */
        svm->nested.intercept_cr_read    = nested_vmcb->control.intercept_cr_read;