KVM: remove export of emulator_write_emulated()
[pandora-kernel.git] / arch / x86 / kvm / x86.c
index 9a469df..15a4b75 100644 (file)
@@ -414,57 +414,49 @@ out:
        return changed;
 }
 
-void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
+static int __kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
 {
        cr0 |= X86_CR0_ET;
 
 #ifdef CONFIG_X86_64
-       if (cr0 & 0xffffffff00000000UL) {
-               kvm_inject_gp(vcpu, 0);
-               return;
-       }
+       if (cr0 & 0xffffffff00000000UL)
+               return 1;
 #endif
 
        cr0 &= ~CR0_RESERVED_BITS;
 
-       if ((cr0 & X86_CR0_NW) && !(cr0 & X86_CR0_CD)) {
-               kvm_inject_gp(vcpu, 0);
-               return;
-       }
+       if ((cr0 & X86_CR0_NW) && !(cr0 & X86_CR0_CD))
+               return 1;
 
-       if ((cr0 & X86_CR0_PG) && !(cr0 & X86_CR0_PE)) {
-               kvm_inject_gp(vcpu, 0);
-               return;
-       }
+       if ((cr0 & X86_CR0_PG) && !(cr0 & X86_CR0_PE))
+               return 1;
 
        if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) {
 #ifdef CONFIG_X86_64
                if ((vcpu->arch.efer & EFER_LME)) {
                        int cs_db, cs_l;
 
-                       if (!is_pae(vcpu)) {
-                               kvm_inject_gp(vcpu, 0);
-                               return;
-                       }
+                       if (!is_pae(vcpu))
+                               return 1;
                        kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
-                       if (cs_l) {
-                               kvm_inject_gp(vcpu, 0);
-                               return;
-
-                       }
+                       if (cs_l)
+                               return 1;
                } else
 #endif
-               if (is_pae(vcpu) && !load_pdptrs(vcpu, vcpu->arch.cr3)) {
-                       kvm_inject_gp(vcpu, 0);
-                       return;
-               }
-
+               if (is_pae(vcpu) && !load_pdptrs(vcpu, vcpu->arch.cr3))
+                       return 1;
        }
 
        kvm_x86_ops->set_cr0(vcpu, cr0);
 
        kvm_mmu_reset_context(vcpu);
-       return;
+       return 0;
+}
+
+void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
+{
+       if (__kvm_set_cr0(vcpu, cr0))
+               kvm_inject_gp(vcpu, 0);
 }
 EXPORT_SYMBOL_GPL(kvm_set_cr0);
 
@@ -474,61 +466,56 @@ void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw)
 }
 EXPORT_SYMBOL_GPL(kvm_lmsw);
 
-void kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
+int __kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
 {
        unsigned long old_cr4 = kvm_read_cr4(vcpu);
        unsigned long pdptr_bits = X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE;
 
-       if (cr4 & CR4_RESERVED_BITS) {
-               kvm_inject_gp(vcpu, 0);
-               return;
-       }
+       if (cr4 & CR4_RESERVED_BITS)
+               return 1;
 
        if (is_long_mode(vcpu)) {
-               if (!(cr4 & X86_CR4_PAE)) {
-                       kvm_inject_gp(vcpu, 0);
-                       return;
-               }
+               if (!(cr4 & X86_CR4_PAE))
+                       return 1;
        } else if (is_paging(vcpu) && (cr4 & X86_CR4_PAE)
                   && ((cr4 ^ old_cr4) & pdptr_bits)
-                  && !load_pdptrs(vcpu, vcpu->arch.cr3)) {
-               kvm_inject_gp(vcpu, 0);
-               return;
-       }
+                  && !load_pdptrs(vcpu, vcpu->arch.cr3))
+               return 1;
+
+       if (cr4 & X86_CR4_VMXE)
+               return 1;
 
-       if (cr4 & X86_CR4_VMXE) {
-               kvm_inject_gp(vcpu, 0);
-               return;
-       }
        kvm_x86_ops->set_cr4(vcpu, cr4);
        vcpu->arch.cr4 = cr4;
        kvm_mmu_reset_context(vcpu);
+
+       return 0;
+}
+
+void kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
+{
+       if (__kvm_set_cr4(vcpu, cr4))
+               kvm_inject_gp(vcpu, 0);
 }
 EXPORT_SYMBOL_GPL(kvm_set_cr4);
 
-void kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
+static int __kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
 {
        if (cr3 == vcpu->arch.cr3 && !pdptrs_changed(vcpu)) {
                kvm_mmu_sync_roots(vcpu);
                kvm_mmu_flush_tlb(vcpu);
-               return;
+               return 0;
        }
 
        if (is_long_mode(vcpu)) {
-               if (cr3 & CR3_L_MODE_RESERVED_BITS) {
-                       kvm_inject_gp(vcpu, 0);
-                       return;
-               }
+               if (cr3 & CR3_L_MODE_RESERVED_BITS)
+                       return 1;
        } else {
                if (is_pae(vcpu)) {
-                       if (cr3 & CR3_PAE_RESERVED_BITS) {
-                               kvm_inject_gp(vcpu, 0);
-                               return;
-                       }
-                       if (is_paging(vcpu) && !load_pdptrs(vcpu, cr3)) {
-                               kvm_inject_gp(vcpu, 0);
-                               return;
-                       }
+                       if (cr3 & CR3_PAE_RESERVED_BITS)
+                               return 1;
+                       if (is_paging(vcpu) && !load_pdptrs(vcpu, cr3))
+                               return 1;
                }
                /*
                 * We don't check reserved bits in nonpae mode, because
@@ -546,24 +533,34 @@ void kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
         * to debug) behavior on the guest side.
         */
        if (unlikely(!gfn_to_memslot(vcpu->kvm, cr3 >> PAGE_SHIFT)))
+               return 1;
+       vcpu->arch.cr3 = cr3;
+       vcpu->arch.mmu.new_cr3(vcpu);
+       return 0;
+}
+
+void kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
+{
+       if (__kvm_set_cr3(vcpu, cr3))
                kvm_inject_gp(vcpu, 0);
-       else {
-               vcpu->arch.cr3 = cr3;
-               vcpu->arch.mmu.new_cr3(vcpu);
-       }
 }
 EXPORT_SYMBOL_GPL(kvm_set_cr3);
 
-void kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8)
+int __kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8)
 {
-       if (cr8 & CR8_RESERVED_BITS) {
-               kvm_inject_gp(vcpu, 0);
-               return;
-       }
+       if (cr8 & CR8_RESERVED_BITS)
+               return 1;
        if (irqchip_in_kernel(vcpu->kvm))
                kvm_lapic_set_tpr(vcpu, cr8);
        else
                vcpu->arch.cr8 = cr8;
+       return 0;
+}
+
+void kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8)
+{
+       if (__kvm_set_cr8(vcpu, cr8))
+               kvm_inject_gp(vcpu, 0);
 }
 EXPORT_SYMBOL_GPL(kvm_set_cr8);
 
@@ -576,7 +573,7 @@ unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu)
 }
 EXPORT_SYMBOL_GPL(kvm_get_cr8);
 
-int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
+static int __kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
 {
        switch (dr) {
        case 0 ... 3:
@@ -585,29 +582,21 @@ int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
                        vcpu->arch.eff_db[dr] = val;
                break;
        case 4:
-               if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) {
-                       kvm_queue_exception(vcpu, UD_VECTOR);
-                       return 1;
-               }
+               if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
+                       return 1; /* #UD */
                /* fall through */
        case 6:
-               if (val & 0xffffffff00000000ULL) {
-                       kvm_inject_gp(vcpu, 0);
-                       return 1;
-               }
+               if (val & 0xffffffff00000000ULL)
+                       return -1; /* #GP */
                vcpu->arch.dr6 = (val & DR6_VOLATILE) | DR6_FIXED_1;
                break;
        case 5:
-               if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) {
-                       kvm_queue_exception(vcpu, UD_VECTOR);
-                       return 1;
-               }
+               if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
+                       return 1; /* #UD */
                /* fall through */
        default: /* 7 */
-               if (val & 0xffffffff00000000ULL) {
-                       kvm_inject_gp(vcpu, 0);
-                       return 1;
-               }
+               if (val & 0xffffffff00000000ULL)
+                       return -1; /* #GP */
                vcpu->arch.dr7 = (val & DR7_VOLATILE) | DR7_FIXED_1;
                if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)) {
                        kvm_x86_ops->set_dr7(vcpu, vcpu->arch.dr7);
@@ -618,28 +607,37 @@ int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
 
        return 0;
 }
+
+int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
+{
+       int res;
+
+       res = __kvm_set_dr(vcpu, dr, val);
+       if (res > 0)
+               kvm_queue_exception(vcpu, UD_VECTOR);
+       else if (res < 0)
+               kvm_inject_gp(vcpu, 0);
+
+       return res;
+}
 EXPORT_SYMBOL_GPL(kvm_set_dr);
 
-int kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val)
+static int _kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val)
 {
        switch (dr) {
        case 0 ... 3:
                *val = vcpu->arch.db[dr];
                break;
        case 4:
-               if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) {
-                       kvm_queue_exception(vcpu, UD_VECTOR);
+               if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
                        return 1;
-               }
                /* fall through */
        case 6:
                *val = vcpu->arch.dr6;
                break;
        case 5:
-               if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) {
-                       kvm_queue_exception(vcpu, UD_VECTOR);
+               if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
                        return 1;
-               }
                /* fall through */
        default: /* 7 */
                *val = vcpu->arch.dr7;
@@ -648,6 +646,15 @@ int kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val)
 
        return 0;
 }
+
+int kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val)
+{
+       if (_kvm_get_dr(vcpu, dr, val)) {
+               kvm_queue_exception(vcpu, UD_VECTOR);
+               return 1;
+       }
+       return 0;
+}
 EXPORT_SYMBOL_GPL(kvm_get_dr);
 
 static inline u32 bit(int bitno)
@@ -3268,7 +3275,7 @@ static int kvm_read_guest_virt_helper(gva_t addr, void *val, unsigned int bytes,
                }
                ret = kvm_read_guest(vcpu->kvm, gpa, data, toread);
                if (ret < 0) {
-                       r = X86EMUL_UNHANDLEABLE;
+                       r = X86EMUL_IO_NEEDED;
                        goto out;
                }
 
@@ -3324,7 +3331,7 @@ static int kvm_write_guest_virt_system(gva_t addr, void *val,
                }
                ret = kvm_write_guest(vcpu->kvm, gpa, data, towrite);
                if (ret < 0) {
-                       r = X86EMUL_UNHANDLEABLE;
+                       r = X86EMUL_IO_NEEDED;
                        goto out;
                }
 
@@ -3379,11 +3386,12 @@ mmio:
        trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, bytes, gpa, 0);
 
        vcpu->mmio_needed = 1;
-       vcpu->mmio_phys_addr = gpa;
-       vcpu->mmio_size = bytes;
-       vcpu->mmio_is_write = 0;
+       vcpu->run->exit_reason = KVM_EXIT_MMIO;
+       vcpu->run->mmio.phys_addr = vcpu->mmio_phys_addr = gpa;
+       vcpu->run->mmio.len = vcpu->mmio_size = bytes;
+       vcpu->run->mmio.is_write = vcpu->mmio_is_write = 0;
 
-       return X86EMUL_UNHANDLEABLE;
+       return X86EMUL_IO_NEEDED;
 }
 
 int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
@@ -3429,10 +3437,11 @@ mmio:
                return X86EMUL_CONTINUE;
 
        vcpu->mmio_needed = 1;
-       vcpu->mmio_phys_addr = gpa;
-       vcpu->mmio_size = bytes;
-       vcpu->mmio_is_write = 1;
-       memcpy(vcpu->mmio_data, val, bytes);
+       vcpu->run->exit_reason = KVM_EXIT_MMIO;
+       vcpu->run->mmio.phys_addr = vcpu->mmio_phys_addr = gpa;
+       vcpu->run->mmio.len = vcpu->mmio_size = bytes;
+       vcpu->run->mmio.is_write = vcpu->mmio_is_write = 1;
+       memcpy(vcpu->run->mmio.data, val, bytes);
 
        return X86EMUL_CONTINUE;
 }
@@ -3456,7 +3465,6 @@ int emulator_write_emulated(unsigned long addr,
        }
        return emulator_write_emulated_onepage(addr, val, bytes, vcpu);
 }
-EXPORT_SYMBOL_GPL(emulator_write_emulated);
 
 #define CMPXCHG_TYPE(t, ptr, old, new) \
        (cmpxchg((t *)(ptr), *(t *)(old), *(t *)(new)) == *(t *)(old))
@@ -3622,12 +3630,13 @@ int emulate_clts(struct kvm_vcpu *vcpu)
 
 int emulator_get_dr(int dr, unsigned long *dest, struct kvm_vcpu *vcpu)
 {
-       return kvm_get_dr(vcpu, dr, dest);
+       return _kvm_get_dr(vcpu, dr, dest);
 }
 
 int emulator_set_dr(int dr, unsigned long value, struct kvm_vcpu *vcpu)
 {
-       return kvm_set_dr(vcpu, dr, value);
+
+       return __kvm_set_dr(vcpu, dr, value);
 }
 
 void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context)
@@ -3681,27 +3690,32 @@ static unsigned long emulator_get_cr(int cr, struct kvm_vcpu *vcpu)
        return value;
 }
 
-static void emulator_set_cr(int cr, unsigned long val, struct kvm_vcpu *vcpu)
+static int emulator_set_cr(int cr, unsigned long val, struct kvm_vcpu *vcpu)
 {
+       int res = 0;
+
        switch (cr) {
        case 0:
-               kvm_set_cr0(vcpu, mk_cr_64(kvm_read_cr0(vcpu), val));
+               res = __kvm_set_cr0(vcpu, mk_cr_64(kvm_read_cr0(vcpu), val));
                break;
        case 2:
                vcpu->arch.cr2 = val;
                break;
        case 3:
-               kvm_set_cr3(vcpu, val);
+               res = __kvm_set_cr3(vcpu, val);
                break;
        case 4:
-               kvm_set_cr4(vcpu, mk_cr_64(kvm_read_cr4(vcpu), val));
+               res = __kvm_set_cr4(vcpu, mk_cr_64(kvm_read_cr4(vcpu), val));
                break;
        case 8:
-               kvm_set_cr8(vcpu, val & 0xfUL);
+               res = __kvm_set_cr8(vcpu, val & 0xfUL);
                break;
        default:
                vcpu_printf(vcpu, "%s: unexpected cr %u\n", __func__, cr);
+               res = -1;
        }
+
+       return res;
 }
 
 static int emulator_get_cpl(struct kvm_vcpu *vcpu)
@@ -3837,7 +3851,6 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
 {
        int r, shadow_mask;
        struct decode_cache *c;
-       struct kvm_run *run = vcpu->run;
 
        kvm_clear_exception_queue(vcpu);
        vcpu->arch.mmio_fault_cr2 = cr2;
@@ -3849,8 +3862,6 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
         */
        cache_all_regs(vcpu);
 
-       vcpu->mmio_is_write = 0;
-
        if (!(emulation_type & EMULTYPE_NO_DECODE)) {
                int cs_db, cs_l;
                kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
@@ -3924,32 +3935,26 @@ restart:
                return EMULATE_DO_MMIO;
        }
 
-       if (r || vcpu->mmio_is_write) {
-               run->exit_reason = KVM_EXIT_MMIO;
-               run->mmio.phys_addr = vcpu->mmio_phys_addr;
-               memcpy(run->mmio.data, vcpu->mmio_data, 8);
-               run->mmio.len = vcpu->mmio_size;
-               run->mmio.is_write = vcpu->mmio_is_write;
+       if (vcpu->mmio_needed) {
+               if (vcpu->mmio_is_write)
+                       vcpu->mmio_needed = 0;
+               return EMULATE_DO_MMIO;
        }
 
-       if (r) {
+       if (r) { /* emulation failed */
+               /*
+                * if emulation was due to access to shadowed page table
+                * and it failed try to unshadow page and re-entetr the
+                * guest to let CPU execute the instruction.
+                */
                if (kvm_mmu_unprotect_page_virt(vcpu, cr2))
-                       goto done;
-               if (!vcpu->mmio_needed) {
-                       ++vcpu->stat.insn_emulation_fail;
-                       trace_kvm_emulate_insn_failed(vcpu);
-                       kvm_report_emulation_failure(vcpu, "mmio");
-                       return EMULATE_FAIL;
-               }
-               return EMULATE_DO_MMIO;
-       }
+                       return EMULATE_DONE;
 
-       if (vcpu->mmio_is_write) {
-               vcpu->mmio_needed = 0;
-               return EMULATE_DO_MMIO;
+               trace_kvm_emulate_insn_failed(vcpu);
+               kvm_report_emulation_failure(vcpu, "mmio");
+               return EMULATE_FAIL;
        }
 
-done:
        if (vcpu->arch.exception.pending)
                vcpu->arch.emulate_ctxt.restart = false;