Merge branch 'x86-asm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / arch / x86 / kvm / x86.c
index 8f0f6ec..1e7e76e 100644 (file)
@@ -29,6 +29,7 @@
 #include "cpuid.h"
 #include "assigned-dev.h"
 #include "pmu.h"
+#include "hyperv.h"
 
 #include <linux/clocksource.h>
 #include <linux/interrupt.h>
@@ -221,11 +222,9 @@ static void shared_msr_update(unsigned slot, u32 msr)
 void kvm_define_shared_msr(unsigned slot, u32 msr)
 {
        BUG_ON(slot >= KVM_NR_SHARED_MSRS);
+       shared_msrs_global.msrs[slot] = msr;
        if (slot >= shared_msrs_global.nr)
                shared_msrs_global.nr = slot + 1;
-       shared_msrs_global.msrs[slot] = msr;
-       /* we need ensured the shared_msr_global have been updated */
-       smp_wmb();
 }
 EXPORT_SYMBOL_GPL(kvm_define_shared_msr);
 
@@ -526,7 +525,8 @@ int load_pdptrs(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, unsigned long cr3)
        }
        for (i = 0; i < ARRAY_SIZE(pdpte); ++i) {
                if (is_present_gpte(pdpte[i]) &&
-                   (pdpte[i] & vcpu->arch.mmu.rsvd_bits_mask[0][2])) {
+                   (pdpte[i] &
+                    vcpu->arch.mmu.guest_rsvd_check.rsvd_bits_mask[0][2])) {
                        ret = 0;
                        goto out;
                }
@@ -949,6 +949,8 @@ static u32 emulated_msrs[] = {
        MSR_KVM_SYSTEM_TIME_NEW, MSR_KVM_WALL_CLOCK_NEW,
        HV_X64_MSR_GUEST_OS_ID, HV_X64_MSR_HYPERCALL,
        HV_X64_MSR_TIME_REF_COUNT, HV_X64_MSR_REFERENCE_TSC,
+       HV_X64_MSR_CRASH_P0, HV_X64_MSR_CRASH_P1, HV_X64_MSR_CRASH_P2,
+       HV_X64_MSR_CRASH_P3, HV_X64_MSR_CRASH_P4, HV_X64_MSR_CRASH_CTL,
        HV_X64_MSR_APIC_ASSIST_PAGE, MSR_KVM_ASYNC_PF_EN, MSR_KVM_STEAL_TIME,
        MSR_KVM_PV_EOI_EN,
 
@@ -1217,11 +1219,6 @@ static void kvm_get_time_scale(uint32_t scaled_khz, uint32_t base_khz,
                 __func__, base_khz, scaled_khz, shift, *pmultiplier);
 }
 
-static inline u64 get_kernel_ns(void)
-{
-       return ktime_get_boot_ns();
-}
-
 #ifdef CONFIG_X86_64
 static atomic_t kvm_guest_has_master_clock = ATOMIC_INIT(0);
 #endif
@@ -1444,20 +1441,8 @@ EXPORT_SYMBOL_GPL(kvm_write_tsc);
 
 static cycle_t read_tsc(void)
 {
-       cycle_t ret;
-       u64 last;
-
-       /*
-        * Empirically, a fence (of type that depends on the CPU)
-        * before rdtsc is enough to ensure that rdtsc is ordered
-        * with respect to loads.  The various CPU manuals are unclear
-        * as to whether rdtsc can be reordered with later loads,
-        * but no one has ever seen it happen.
-        */
-       rdtsc_barrier();
-       ret = (cycle_t)vget_cycles();
-
-       last = pvclock_gtod_data.clock.cycle_last;
+       cycle_t ret = (cycle_t)rdtsc_ordered();
+       u64 last = pvclock_gtod_data.clock.cycle_last;
 
        if (likely(ret >= last))
                return ret;
@@ -1646,7 +1631,7 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
                return 1;
        }
        if (!use_master_clock) {
-               host_tsc = native_read_tsc();
+               host_tsc = rdtsc();
                kernel_ns = get_kernel_ns();
        }
 
@@ -1869,123 +1854,6 @@ out:
        return r;
 }
 
-static bool kvm_hv_hypercall_enabled(struct kvm *kvm)
-{
-       return kvm->arch.hv_hypercall & HV_X64_MSR_HYPERCALL_ENABLE;
-}
-
-static bool kvm_hv_msr_partition_wide(u32 msr)
-{
-       bool r = false;
-       switch (msr) {
-       case HV_X64_MSR_GUEST_OS_ID:
-       case HV_X64_MSR_HYPERCALL:
-       case HV_X64_MSR_REFERENCE_TSC:
-       case HV_X64_MSR_TIME_REF_COUNT:
-               r = true;
-               break;
-       }
-
-       return r;
-}
-
-static int set_msr_hyperv_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data)
-{
-       struct kvm *kvm = vcpu->kvm;
-
-       switch (msr) {
-       case HV_X64_MSR_GUEST_OS_ID:
-               kvm->arch.hv_guest_os_id = data;
-               /* setting guest os id to zero disables hypercall page */
-               if (!kvm->arch.hv_guest_os_id)
-                       kvm->arch.hv_hypercall &= ~HV_X64_MSR_HYPERCALL_ENABLE;
-               break;
-       case HV_X64_MSR_HYPERCALL: {
-               u64 gfn;
-               unsigned long addr;
-               u8 instructions[4];
-
-               /* if guest os id is not set hypercall should remain disabled */
-               if (!kvm->arch.hv_guest_os_id)
-                       break;
-               if (!(data & HV_X64_MSR_HYPERCALL_ENABLE)) {
-                       kvm->arch.hv_hypercall = data;
-                       break;
-               }
-               gfn = data >> HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT;
-               addr = gfn_to_hva(kvm, gfn);
-               if (kvm_is_error_hva(addr))
-                       return 1;
-               kvm_x86_ops->patch_hypercall(vcpu, instructions);
-               ((unsigned char *)instructions)[3] = 0xc3; /* ret */
-               if (__copy_to_user((void __user *)addr, instructions, 4))
-                       return 1;
-               kvm->arch.hv_hypercall = data;
-               mark_page_dirty(kvm, gfn);
-               break;
-       }
-       case HV_X64_MSR_REFERENCE_TSC: {
-               u64 gfn;
-               HV_REFERENCE_TSC_PAGE tsc_ref;
-               memset(&tsc_ref, 0, sizeof(tsc_ref));
-               kvm->arch.hv_tsc_page = data;
-               if (!(data & HV_X64_MSR_TSC_REFERENCE_ENABLE))
-                       break;
-               gfn = data >> HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT;
-               if (kvm_write_guest(kvm, gfn << HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT,
-                       &tsc_ref, sizeof(tsc_ref)))
-                       return 1;
-               mark_page_dirty(kvm, gfn);
-               break;
-       }
-       default:
-               vcpu_unimpl(vcpu, "HYPER-V unimplemented wrmsr: 0x%x "
-                           "data 0x%llx\n", msr, data);
-               return 1;
-       }
-       return 0;
-}
-
-static int set_msr_hyperv(struct kvm_vcpu *vcpu, u32 msr, u64 data)
-{
-       switch (msr) {
-       case HV_X64_MSR_APIC_ASSIST_PAGE: {
-               u64 gfn;
-               unsigned long addr;
-
-               if (!(data & HV_X64_MSR_APIC_ASSIST_PAGE_ENABLE)) {
-                       vcpu->arch.hv_vapic = data;
-                       if (kvm_lapic_enable_pv_eoi(vcpu, 0))
-                               return 1;
-                       break;
-               }
-               gfn = data >> HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT;
-               addr = kvm_vcpu_gfn_to_hva(vcpu, gfn);
-               if (kvm_is_error_hva(addr))
-                       return 1;
-               if (__clear_user((void __user *)addr, PAGE_SIZE))
-                       return 1;
-               vcpu->arch.hv_vapic = data;
-               kvm_vcpu_mark_page_dirty(vcpu, gfn);
-               if (kvm_lapic_enable_pv_eoi(vcpu, gfn_to_gpa(gfn) | KVM_MSR_ENABLED))
-                       return 1;
-               break;
-       }
-       case HV_X64_MSR_EOI:
-               return kvm_hv_vapic_msr_write(vcpu, APIC_EOI, data);
-       case HV_X64_MSR_ICR:
-               return kvm_hv_vapic_msr_write(vcpu, APIC_ICR, data);
-       case HV_X64_MSR_TPR:
-               return kvm_hv_vapic_msr_write(vcpu, APIC_TASKPRI, data);
-       default:
-               vcpu_unimpl(vcpu, "HYPER-V unimplemented wrmsr: 0x%x "
-                           "data 0x%llx\n", msr, data);
-               return 1;
-       }
-
-       return 0;
-}
-
 static int kvm_pv_enable_async_pf(struct kvm_vcpu *vcpu, u64 data)
 {
        gpa_t gpa = data & ~0x3f;
@@ -2224,15 +2092,10 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                 */
                break;
        case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15:
-               if (kvm_hv_msr_partition_wide(msr)) {
-                       int r;
-                       mutex_lock(&vcpu->kvm->lock);
-                       r = set_msr_hyperv_pw(vcpu, msr, data);
-                       mutex_unlock(&vcpu->kvm->lock);
-                       return r;
-               } else
-                       return set_msr_hyperv(vcpu, msr, data);
-               break;
+       case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4:
+       case HV_X64_MSR_CRASH_CTL:
+               return kvm_hv_set_msr_common(vcpu, msr, data,
+                                            msr_info->host_initiated);
        case MSR_IA32_BBL_CR_CTL3:
                /* Drop writes to this legacy MSR -- see rdmsr
                 * counterpart for further detail.
@@ -2315,68 +2178,6 @@ static int get_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
        return 0;
 }
 
-static int get_msr_hyperv_pw(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
-{
-       u64 data = 0;
-       struct kvm *kvm = vcpu->kvm;
-
-       switch (msr) {
-       case HV_X64_MSR_GUEST_OS_ID:
-               data = kvm->arch.hv_guest_os_id;
-               break;
-       case HV_X64_MSR_HYPERCALL:
-               data = kvm->arch.hv_hypercall;
-               break;
-       case HV_X64_MSR_TIME_REF_COUNT: {
-               data =
-                    div_u64(get_kernel_ns() + kvm->arch.kvmclock_offset, 100);
-               break;
-       }
-       case HV_X64_MSR_REFERENCE_TSC:
-               data = kvm->arch.hv_tsc_page;
-               break;
-       default:
-               vcpu_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr);
-               return 1;
-       }
-
-       *pdata = data;
-       return 0;
-}
-
-static int get_msr_hyperv(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
-{
-       u64 data = 0;
-
-       switch (msr) {
-       case HV_X64_MSR_VP_INDEX: {
-               int r;
-               struct kvm_vcpu *v;
-               kvm_for_each_vcpu(r, v, vcpu->kvm) {
-                       if (v == vcpu) {
-                               data = r;
-                               break;
-                       }
-               }
-               break;
-       }
-       case HV_X64_MSR_EOI:
-               return kvm_hv_vapic_msr_read(vcpu, APIC_EOI, pdata);
-       case HV_X64_MSR_ICR:
-               return kvm_hv_vapic_msr_read(vcpu, APIC_ICR, pdata);
-       case HV_X64_MSR_TPR:
-               return kvm_hv_vapic_msr_read(vcpu, APIC_TASKPRI, pdata);
-       case HV_X64_MSR_APIC_ASSIST_PAGE:
-               data = vcpu->arch.hv_vapic;
-               break;
-       default:
-               vcpu_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr);
-               return 1;
-       }
-       *pdata = data;
-       return 0;
-}
-
 int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 {
        switch (msr_info->index) {
@@ -2493,14 +2294,10 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                msr_info->data = 0x20000000;
                break;
        case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15:
-               if (kvm_hv_msr_partition_wide(msr_info->index)) {
-                       int r;
-                       mutex_lock(&vcpu->kvm->lock);
-                       r = get_msr_hyperv_pw(vcpu, msr_info->index, &msr_info->data);
-                       mutex_unlock(&vcpu->kvm->lock);
-                       return r;
-               } else
-                       return get_msr_hyperv(vcpu, msr_info->index, &msr_info->data);
+       case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4:
+       case HV_X64_MSR_CRASH_CTL:
+               return kvm_hv_get_msr_common(vcpu,
+                                            msr_info->index, &msr_info->data);
                break;
        case MSR_IA32_BBL_CR_CTL3:
                /* This legacy MSR exists but isn't fully documented in current
@@ -2651,6 +2448,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_TSC_DEADLINE_TIMER:
        case KVM_CAP_ENABLE_CAP_VM:
        case KVM_CAP_DISABLE_QUIRKS:
+       case KVM_CAP_SET_BOOT_CPU_ID:
 #ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
        case KVM_CAP_ASSIGN_DEV_IRQ:
        case KVM_CAP_PCI_2_3:
@@ -2810,7 +2608,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 
        if (unlikely(vcpu->cpu != cpu) || check_tsc_unstable()) {
                s64 tsc_delta = !vcpu->arch.last_host_tsc ? 0 :
-                               native_read_tsc() - vcpu->arch.last_host_tsc;
+                               rdtsc() - vcpu->arch.last_host_tsc;
                if (tsc_delta < 0)
                        mark_tsc_unstable("KVM discovered backwards TSC");
                if (check_tsc_unstable()) {
@@ -2838,7 +2636,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
 {
        kvm_x86_ops->vcpu_put(vcpu);
        kvm_put_guest_fpu(vcpu);
-       vcpu->arch.last_host_tsc = native_read_tsc();
+       vcpu->arch.last_host_tsc = rdtsc();
 }
 
 static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
@@ -3817,30 +3615,25 @@ long kvm_arch_vm_ioctl(struct file *filp,
                        r = kvm_ioapic_init(kvm);
                        if (r) {
                                mutex_lock(&kvm->slots_lock);
-                               kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS,
-                                                         &vpic->dev_master);
-                               kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS,
-                                                         &vpic->dev_slave);
-                               kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS,
-                                                         &vpic->dev_eclr);
+                               kvm_destroy_pic(vpic);
                                mutex_unlock(&kvm->slots_lock);
-                               kfree(vpic);
                                goto create_irqchip_unlock;
                        }
                } else
                        goto create_irqchip_unlock;
-               smp_wmb();
-               kvm->arch.vpic = vpic;
-               smp_wmb();
                r = kvm_setup_default_irq_routing(kvm);
                if (r) {
                        mutex_lock(&kvm->slots_lock);
                        mutex_lock(&kvm->irq_lock);
                        kvm_ioapic_destroy(kvm);
-                       kvm_destroy_pic(kvm);
+                       kvm_destroy_pic(vpic);
                        mutex_unlock(&kvm->irq_lock);
                        mutex_unlock(&kvm->slots_lock);
+                       goto create_irqchip_unlock;
                }
+               /* Write kvm->irq_routing before kvm->arch.vpic.  */
+               smp_wmb();
+               kvm->arch.vpic = vpic;
        create_irqchip_unlock:
                mutex_unlock(&kvm->lock);
                break;
@@ -3967,6 +3760,15 @@ long kvm_arch_vm_ioctl(struct file *filp,
                r = kvm_vm_ioctl_reinject(kvm, &control);
                break;
        }
+       case KVM_SET_BOOT_CPU_ID:
+               r = 0;
+               mutex_lock(&kvm->lock);
+               if (atomic_read(&kvm->online_vcpus) != 0)
+                       r = -EBUSY;
+               else
+                       kvm->arch.bsp_vcpu_id = arg;
+               mutex_unlock(&kvm->lock);
+               break;
        case KVM_XEN_HVM_CONFIG: {
                r = -EFAULT;
                if (copy_from_user(&kvm->arch.xen_hvm_config, argp,
@@ -5882,66 +5684,6 @@ int kvm_emulate_halt(struct kvm_vcpu *vcpu)
 }
 EXPORT_SYMBOL_GPL(kvm_emulate_halt);
 
-int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
-{
-       u64 param, ingpa, outgpa, ret;
-       uint16_t code, rep_idx, rep_cnt, res = HV_STATUS_SUCCESS, rep_done = 0;
-       bool fast, longmode;
-
-       /*
-        * hypercall generates UD from non zero cpl and real mode
-        * per HYPER-V spec
-        */
-       if (kvm_x86_ops->get_cpl(vcpu) != 0 || !is_protmode(vcpu)) {
-               kvm_queue_exception(vcpu, UD_VECTOR);
-               return 0;
-       }
-
-       longmode = is_64_bit_mode(vcpu);
-
-       if (!longmode) {
-               param = ((u64)kvm_register_read(vcpu, VCPU_REGS_RDX) << 32) |
-                       (kvm_register_read(vcpu, VCPU_REGS_RAX) & 0xffffffff);
-               ingpa = ((u64)kvm_register_read(vcpu, VCPU_REGS_RBX) << 32) |
-                       (kvm_register_read(vcpu, VCPU_REGS_RCX) & 0xffffffff);
-               outgpa = ((u64)kvm_register_read(vcpu, VCPU_REGS_RDI) << 32) |
-                       (kvm_register_read(vcpu, VCPU_REGS_RSI) & 0xffffffff);
-       }
-#ifdef CONFIG_X86_64
-       else {
-               param = kvm_register_read(vcpu, VCPU_REGS_RCX);
-               ingpa = kvm_register_read(vcpu, VCPU_REGS_RDX);
-               outgpa = kvm_register_read(vcpu, VCPU_REGS_R8);
-       }
-#endif
-
-       code = param & 0xffff;
-       fast = (param >> 16) & 0x1;
-       rep_cnt = (param >> 32) & 0xfff;
-       rep_idx = (param >> 48) & 0xfff;
-
-       trace_kvm_hv_hypercall(code, fast, rep_cnt, rep_idx, ingpa, outgpa);
-
-       switch (code) {
-       case HV_X64_HV_NOTIFY_LONG_SPIN_WAIT:
-               kvm_vcpu_on_spin(vcpu);
-               break;
-       default:
-               res = HV_STATUS_INVALID_HYPERCALL_CODE;
-               break;
-       }
-
-       ret = res | (((u64)rep_done & 0xfff) << 32);
-       if (longmode) {
-               kvm_register_write(vcpu, VCPU_REGS_RAX, ret);
-       } else {
-               kvm_register_write(vcpu, VCPU_REGS_RDX, ret >> 32);
-               kvm_register_write(vcpu, VCPU_REGS_RAX, ret & 0xffffffff);
-       }
-
-       return 1;
-}
-
 /*
  * kvm_pv_kick_cpu_op:  Kick a vcpu.
  *
@@ -6518,6 +6260,12 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
                        vcpu_scan_ioapic(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)) {
+                       vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT;
+                       vcpu->run->system_event.type = KVM_SYSTEM_EVENT_CRASH;
+                       r = 0;
+                       goto out;
+               }
        }
 
        if (kvm_check_request(KVM_REQ_EVENT, vcpu) || req_int_win) {
@@ -6627,7 +6375,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
                hw_breakpoint_restore();
 
        vcpu->arch.last_guest_tsc = kvm_x86_ops->read_l1_tsc(vcpu,
-                                                          native_read_tsc());
+                                                          rdtsc());
 
        vcpu->mode = OUTSIDE_GUEST_MODE;
        smp_wmb();
@@ -7436,7 +7184,7 @@ int kvm_arch_hardware_enable(void)
        if (ret != 0)
                return ret;
 
-       local_tsc = native_read_tsc();
+       local_tsc = rdtsc();
        stable = !check_tsc_unstable();
        list_for_each_entry(kvm, &vm_list, vm_list) {
                kvm_for_each_vcpu(i, vcpu, kvm) {
@@ -7540,6 +7288,17 @@ void kvm_arch_check_processor_compat(void *rtn)
        kvm_x86_ops->check_processor_compatibility(rtn);
 }
 
+bool kvm_vcpu_is_reset_bsp(struct kvm_vcpu *vcpu)
+{
+       return vcpu->kvm->arch.bsp_vcpu_id == vcpu->vcpu_id;
+}
+EXPORT_SYMBOL_GPL(kvm_vcpu_is_reset_bsp);
+
+bool kvm_vcpu_is_bsp(struct kvm_vcpu *vcpu)
+{
+       return (vcpu->arch.apic_base & MSR_IA32_APICBASE_BSP) != 0;
+}
+
 bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu)
 {
        return irqchip_in_kernel(vcpu->kvm) == (vcpu->arch.apic != NULL);