]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - arch/x86/kvm/x86.c
KVM: x86: Fix perf timer mode IP reporting
[linux.git] / arch / x86 / kvm / x86.c
index 6c81df94cd77c51b91557091bbc7ad169665c55b..bf89876e620b63d2a531d258933a9dbb4bb91e6f 100644 (file)
@@ -142,6 +142,10 @@ module_param(lapic_timer_advance_ns, uint, S_IRUGO | S_IWUSR);
 static bool __read_mostly vector_hashing = true;
 module_param(vector_hashing, bool, S_IRUGO);
 
+bool __read_mostly enable_vmware_backdoor = false;
+module_param(enable_vmware_backdoor, bool, S_IRUGO);
+EXPORT_SYMBOL_GPL(enable_vmware_backdoor);
+
 #define KVM_NR_SHARED_MSRS 16
 
 struct kvm_shared_msrs_global {
@@ -1034,7 +1038,11 @@ static u32 emulated_msrs[] = {
        HV_X64_MSR_VP_RUNTIME,
        HV_X64_MSR_SCONTROL,
        HV_X64_MSR_STIMER0_CONFIG,
-       HV_X64_MSR_APIC_ASSIST_PAGE, MSR_KVM_ASYNC_PF_EN, MSR_KVM_STEAL_TIME,
+       HV_X64_MSR_APIC_ASSIST_PAGE,
+       HV_X64_MSR_REENLIGHTENMENT_CONTROL, HV_X64_MSR_TSC_EMULATION_CONTROL,
+       HV_X64_MSR_TSC_EMULATION_STATUS,
+
+       MSR_KVM_ASYNC_PF_EN, MSR_KVM_STEAL_TIME,
        MSR_KVM_PV_EOI_EN,
 
        MSR_IA32_TSC_ADJUST,
@@ -2453,6 +2461,9 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
        case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4:
        case HV_X64_MSR_CRASH_CTL:
        case HV_X64_MSR_STIMER0_CONFIG ... HV_X64_MSR_STIMER3_COUNT:
+       case HV_X64_MSR_REENLIGHTENMENT_CONTROL:
+       case HV_X64_MSR_TSC_EMULATION_CONTROL:
+       case HV_X64_MSR_TSC_EMULATION_STATUS:
                return kvm_hv_set_msr_common(vcpu, msr, data,
                                             msr_info->host_initiated);
        case MSR_IA32_BBL_CR_CTL3:
@@ -2683,6 +2694,9 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
        case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4:
        case HV_X64_MSR_CRASH_CTL:
        case HV_X64_MSR_STIMER0_CONFIG ... HV_X64_MSR_STIMER3_COUNT:
+       case HV_X64_MSR_REENLIGHTENMENT_CONTROL:
+       case HV_X64_MSR_TSC_EMULATION_CONTROL:
+       case HV_X64_MSR_TSC_EMULATION_STATUS:
                return kvm_hv_get_msr_common(vcpu,
                                             msr_info->index, &msr_info->data);
                break;
@@ -2799,9 +2813,15 @@ static int msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs __user *user_msrs,
        return r;
 }
 
+static inline bool kvm_can_mwait_in_guest(void)
+{
+       return boot_cpu_has(X86_FEATURE_MWAIT) &&
+               !boot_cpu_has_bug(X86_BUG_MONITOR);
+}
+
 int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 {
-       int r;
+       int r = 0;
 
        switch (ext) {
        case KVM_CAP_IRQCHIP:
@@ -2857,8 +2877,10 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_ADJUST_CLOCK:
                r = KVM_CLOCK_TSC_STABLE;
                break;
-       case KVM_CAP_X86_GUEST_MWAIT:
-               r = kvm_mwait_in_guest();
+       case KVM_CAP_X86_DISABLE_EXITS:
+               r |=  KVM_X86_DISABLE_EXITS_HTL | KVM_X86_DISABLE_EXITS_PAUSE;
+               if(kvm_can_mwait_in_guest())
+                       r |= KVM_X86_DISABLE_EXITS_MWAIT;
                break;
        case KVM_CAP_X86_SMM:
                /* SMBASE is usually relocated above 1M on modern chipsets,
@@ -2899,7 +2921,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
                r = KVM_X2APIC_API_VALID_FLAGS;
                break;
        default:
-               r = 0;
                break;
        }
        return r;
@@ -3943,8 +3964,7 @@ static int kvm_vm_ioctl_set_tss_addr(struct kvm *kvm, unsigned long addr)
 static int kvm_vm_ioctl_set_identity_map_addr(struct kvm *kvm,
                                              u64 ident_addr)
 {
-       kvm->arch.ept_identity_map_addr = ident_addr;
-       return 0;
+       return kvm_x86_ops->set_identity_map_addr(kvm, ident_addr);
 }
 
 static int kvm_vm_ioctl_set_nr_mmu_pages(struct kvm *kvm,
@@ -4204,6 +4224,20 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
 
                r = 0;
                break;
+       case KVM_CAP_X86_DISABLE_EXITS:
+               r = -EINVAL;
+               if (cap->args[0] & ~KVM_X86_DISABLE_VALID_EXITS)
+                       break;
+
+               if ((cap->args[0] & KVM_X86_DISABLE_EXITS_MWAIT) &&
+                       kvm_can_mwait_in_guest())
+                       kvm->arch.mwait_in_guest = true;
+               if (cap->args[0] & KVM_X86_DISABLE_EXITS_HTL)
+                       kvm->arch.hlt_in_guest = true;
+               if (cap->args[0] & KVM_X86_DISABLE_EXITS_PAUSE)
+                       kvm->arch.pause_in_guest = true;
+               r = 0;
+               break;
        default:
                r = -EINVAL;
                break;
@@ -5656,18 +5690,23 @@ int kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq, int inc_eip)
 }
 EXPORT_SYMBOL_GPL(kvm_inject_realmode_interrupt);
 
-static int handle_emulation_failure(struct kvm_vcpu *vcpu)
+static int handle_emulation_failure(struct kvm_vcpu *vcpu, int emulation_type)
 {
        int r = EMULATE_DONE;
 
        ++vcpu->stat.insn_emulation_fail;
        trace_kvm_emulate_insn_failed(vcpu);
+
+       if (emulation_type & EMULTYPE_NO_UD_ON_FAIL)
+               return EMULATE_FAIL;
+
        if (!is_guest_mode(vcpu) && kvm_x86_ops->get_cpl(vcpu) == 0) {
                vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
                vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
                vcpu->run->internal.ndata = 0;
                r = EMULATE_USER_EXIT;
        }
+
        kvm_queue_exception(vcpu, UD_VECTOR);
 
        return r;
@@ -5911,6 +5950,37 @@ static bool kvm_vcpu_check_breakpoint(struct kvm_vcpu *vcpu, int *r)
        return false;
 }
 
+static bool is_vmware_backdoor_opcode(struct x86_emulate_ctxt *ctxt)
+{
+       switch (ctxt->opcode_len) {
+       case 1:
+               switch (ctxt->b) {
+               case 0xe4:      /* IN */
+               case 0xe5:
+               case 0xec:
+               case 0xed:
+               case 0xe6:      /* OUT */
+               case 0xe7:
+               case 0xee:
+               case 0xef:
+               case 0x6c:      /* INS */
+               case 0x6d:
+               case 0x6e:      /* OUTS */
+               case 0x6f:
+                       return true;
+               }
+               break;
+       case 2:
+               switch (ctxt->b) {
+               case 0x33:      /* RDPMC */
+                       return true;
+               }
+               break;
+       }
+
+       return false;
+}
+
 int x86_emulate_instruction(struct kvm_vcpu *vcpu,
                            unsigned long cr2,
                            int emulation_type,
@@ -5963,10 +6033,14 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu,
                                return EMULATE_DONE;
                        if (emulation_type & EMULTYPE_SKIP)
                                return EMULATE_FAIL;
-                       return handle_emulation_failure(vcpu);
+                       return handle_emulation_failure(vcpu, emulation_type);
                }
        }
 
+       if ((emulation_type & EMULTYPE_VMWARE) &&
+           !is_vmware_backdoor_opcode(ctxt))
+               return EMULATE_FAIL;
+
        if (emulation_type & EMULTYPE_SKIP) {
                kvm_rip_write(vcpu, ctxt->_eip);
                if (ctxt->eflags & X86_EFLAGS_RF)
@@ -5998,7 +6072,7 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu,
                                        emulation_type))
                        return EMULATE_DONE;
 
-               return handle_emulation_failure(vcpu);
+               return handle_emulation_failure(vcpu, emulation_type);
        }
 
        if (ctxt->have_exception) {
@@ -6051,7 +6125,8 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu,
 }
 EXPORT_SYMBOL_GPL(x86_emulate_instruction);
 
-int kvm_fast_pio_out(struct kvm_vcpu *vcpu, int size, unsigned short port)
+static int kvm_fast_pio_out(struct kvm_vcpu *vcpu, int size,
+                           unsigned short port)
 {
        unsigned long val = kvm_register_read(vcpu, VCPU_REGS_RAX);
        int ret = emulator_pio_out_emulated(&vcpu->arch.emulate_ctxt,
@@ -6060,7 +6135,6 @@ int kvm_fast_pio_out(struct kvm_vcpu *vcpu, int size, unsigned short port)
        vcpu->arch.pio.count = 0;
        return ret;
 }
-EXPORT_SYMBOL_GPL(kvm_fast_pio_out);
 
 static int complete_fast_pio_in(struct kvm_vcpu *vcpu)
 {
@@ -6084,7 +6158,8 @@ static int complete_fast_pio_in(struct kvm_vcpu *vcpu)
        return 1;
 }
 
-int kvm_fast_pio_in(struct kvm_vcpu *vcpu, int size, unsigned short port)
+static int kvm_fast_pio_in(struct kvm_vcpu *vcpu, int size,
+                          unsigned short port)
 {
        unsigned long val;
        int ret;
@@ -6103,7 +6178,21 @@ int kvm_fast_pio_in(struct kvm_vcpu *vcpu, int size, unsigned short port)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(kvm_fast_pio_in);
+
+int kvm_fast_pio(struct kvm_vcpu *vcpu, int size, unsigned short port, int in)
+{
+       int ret = kvm_skip_emulated_instruction(vcpu);
+
+       /*
+        * TODO: we might be squashing a KVM_GUESTDBG_SINGLESTEP-triggered
+        * KVM_EXIT_DEBUG here.
+        */
+       if (in)
+               return kvm_fast_pio_in(vcpu, size, port) && ret;
+       else
+               return kvm_fast_pio_out(vcpu, size, port) && ret;
+}
+EXPORT_SYMBOL_GPL(kvm_fast_pio);
 
 static int kvmclock_cpu_down_prep(unsigned int cpu)
 {
@@ -6281,7 +6370,8 @@ static void kvm_timer_init(void)
                          kvmclock_cpu_online, kvmclock_cpu_down_prep);
 }
 
-static DEFINE_PER_CPU(struct kvm_vcpu *, current_vcpu);
+DEFINE_PER_CPU(struct kvm_vcpu *, current_vcpu);
+EXPORT_PER_CPU_SYMBOL_GPL(current_vcpu);
 
 int kvm_is_in_guest(void)
 {
@@ -6314,18 +6404,6 @@ static struct perf_guest_info_callbacks kvm_guest_cbs = {
        .get_guest_ip           = kvm_get_guest_ip,
 };
 
-void kvm_before_handle_nmi(struct kvm_vcpu *vcpu)
-{
-       __this_cpu_write(current_vcpu, vcpu);
-}
-EXPORT_SYMBOL_GPL(kvm_before_handle_nmi);
-
-void kvm_after_handle_nmi(struct kvm_vcpu *vcpu)
-{
-       __this_cpu_write(current_vcpu, NULL);
-}
-EXPORT_SYMBOL_GPL(kvm_after_handle_nmi);
-
 static void kvm_set_mmio_spte_mask(void)
 {
        u64 mask;
@@ -7020,8 +7098,6 @@ void kvm_make_scan_ioapic_request(struct kvm *kvm)
 
 static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu)
 {
-       u64 eoi_exit_bitmap[4];
-
        if (!kvm_apic_hw_enabled(vcpu->arch.apic))
                return;
 
@@ -7034,6 +7110,20 @@ static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu)
                        kvm_x86_ops->sync_pir_to_irr(vcpu);
                kvm_ioapic_scan_entry(vcpu, vcpu->arch.ioapic_handled_vectors);
        }
+
+       if (is_guest_mode(vcpu))
+               vcpu->arch.load_eoi_exitmap_pending = true;
+       else
+               kvm_make_request(KVM_REQ_LOAD_EOI_EXITMAP, vcpu);
+}
+
+static void vcpu_load_eoi_exitmap(struct kvm_vcpu *vcpu)
+{
+       u64 eoi_exit_bitmap[4];
+
+       if (!kvm_apic_hw_enabled(vcpu->arch.apic))
+               return;
+
        bitmap_or((ulong *)eoi_exit_bitmap, vcpu->arch.ioapic_handled_vectors,
                  vcpu_to_synic(vcpu)->vec_bitmap, 256);
        kvm_x86_ops->load_eoi_exitmap(vcpu, eoi_exit_bitmap);
@@ -7148,6 +7238,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
                }
                if (kvm_check_request(KVM_REQ_SCAN_IOAPIC, vcpu))
                        vcpu_scan_ioapic(vcpu);
+               if (kvm_check_request(KVM_REQ_LOAD_EOI_EXITMAP, vcpu))
+                       vcpu_load_eoi_exitmap(vcpu);
                if (kvm_check_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu))
                        kvm_vcpu_reload_apic_access_page(vcpu);
                if (kvm_check_request(KVM_REQ_HV_CRASH, vcpu)) {
@@ -7326,7 +7418,9 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 
        kvm_put_guest_xcr0(vcpu);
 
+       kvm_before_interrupt(vcpu);
        kvm_x86_ops->handle_external_intr(vcpu);
+       kvm_after_interrupt(vcpu);
 
        ++vcpu->stat.exits;