x86, apicv: add virtual x2apic support
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / arch / x86 / kvm / svm.c
index d017df3899ef23a2dc339ebcf7c7d88b6eef6e8e..38407e9fd1bdee00b599b9cdc582cf7007766603 100644 (file)
@@ -20,6 +20,7 @@
 #include "mmu.h"
 #include "kvm_cache_regs.h"
 #include "x86.h"
+#include "cpuid.h"
 
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
@@ -630,15 +631,12 @@ static int svm_hardware_enable(void *garbage)
                return -EBUSY;
 
        if (!has_svm()) {
-               printk(KERN_ERR "svm_hardware_enable: err EOPNOTSUPP on %d\n",
-                      me);
+               pr_err("%s: err EOPNOTSUPP on %d\n", __func__, me);
                return -EINVAL;
        }
        sd = per_cpu(svm_data, me);
-
        if (!sd) {
-               printk(KERN_ERR "svm_hardware_enable: svm_data is NULL on %d\n",
-                      me);
+               pr_err("%s: svm_data is NULL on %d\n", __func__, me);
                return -EINVAL;
        }
 
@@ -1012,6 +1010,13 @@ static void svm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)
        svm->tsc_ratio             = ratio;
 }
 
+static u64 svm_read_tsc_offset(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       return svm->vmcb->control.tsc_offset;
+}
+
 static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
@@ -1189,6 +1194,8 @@ static void init_vmcb(struct vcpu_svm *svm)
 static int svm_vcpu_reset(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
+       u32 dummy;
+       u32 eax = 1;
 
        init_vmcb(svm);
 
@@ -1197,8 +1204,9 @@ static int svm_vcpu_reset(struct kvm_vcpu *vcpu)
                svm->vmcb->save.cs.base = svm->vcpu.arch.sipi_vector << 12;
                svm->vmcb->save.cs.selector = svm->vcpu.arch.sipi_vector << 8;
        }
-       vcpu->arch.regs_avail = ~0;
-       vcpu->arch.regs_dirty = ~0;
+
+       kvm_cpuid(vcpu, &eax, &dummy, &dummy, &dummy);
+       kvm_register_write(vcpu, VCPU_REGS_RDX, eax);
 
        return 0;
 }
@@ -1254,11 +1262,6 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
        svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT;
        svm->asid_generation = 0;
        init_vmcb(svm);
-       kvm_write_tsc(&svm->vcpu, 0);
-
-       err = fx_init(&svm->vcpu);
-       if (err)
-               goto free_page4;
 
        svm->vcpu.arch.apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
        if (kvm_vcpu_is_bsp(&svm->vcpu))
@@ -1268,8 +1271,6 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
 
        return &svm->vcpu;
 
-free_page4:
-       __free_page(hsave_page);
 free_page3:
        __free_pages(nested_msrpm_pages, MSRPM_ALLOC_ORDER);
 free_page2:
@@ -3008,11 +3009,11 @@ static int cr8_write_interception(struct vcpu_svm *svm)
        return 0;
 }
 
-u64 svm_read_l1_tsc(struct kvm_vcpu *vcpu)
+u64 svm_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc)
 {
        struct vmcb *vmcb = get_host_vmcb(to_svm(vcpu));
        return vmcb->control.tsc_offset +
-               svm_scale_tsc(vcpu, native_read_tsc());
+               svm_scale_tsc(vcpu, host_tsc);
 }
 
 static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
@@ -3131,13 +3132,15 @@ static int svm_set_vm_cr(struct kvm_vcpu *vcpu, u64 data)
        return 0;
 }
 
-static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data)
+static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
+       u32 ecx = msr->index;
+       u64 data = msr->data;
        switch (ecx) {
        case MSR_IA32_TSC:
-               kvm_write_tsc(vcpu, data);
+               kvm_write_tsc(vcpu, msr);
                break;
        case MSR_STAR:
                svm->vmcb->save.star = data;
@@ -3192,20 +3195,24 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data)
                vcpu_unimpl(vcpu, "unimplemented wrmsr: 0x%x data 0x%llx\n", ecx, data);
                break;
        default:
-               return kvm_set_msr_common(vcpu, ecx, data);
+               return kvm_set_msr_common(vcpu, msr);
        }
        return 0;
 }
 
 static int wrmsr_interception(struct vcpu_svm *svm)
 {
+       struct msr_data msr;
        u32 ecx = svm->vcpu.arch.regs[VCPU_REGS_RCX];
        u64 data = (svm->vcpu.arch.regs[VCPU_REGS_RAX] & -1u)
                | ((u64)(svm->vcpu.arch.regs[VCPU_REGS_RDX] & -1u) << 32);
 
+       msr.data = data;
+       msr.index = ecx;
+       msr.host_initiated = false;
 
        svm->next_rip = kvm_rip_read(&svm->vcpu) + 2;
-       if (svm_set_msr(&svm->vcpu, ecx, data)) {
+       if (svm_set_msr(&svm->vcpu, &msr)) {
                trace_kvm_msr_write_ex(ecx, data);
                kvm_inject_gp(&svm->vcpu, 0);
        } else {
@@ -3564,6 +3571,11 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
                set_cr_intercept(svm, INTERCEPT_CR8_WRITE);
 }
 
+static void svm_set_virtual_x2apic_mode(struct kvm_vcpu *vcpu, bool set)
+{
+       return;
+}
+
 static int svm_nmi_allowed(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
@@ -4283,6 +4295,7 @@ static struct kvm_x86_ops svm_x86_ops = {
        .enable_nmi_window = enable_nmi_window,
        .enable_irq_window = enable_irq_window,
        .update_cr8_intercept = update_cr8_intercept,
+       .set_virtual_x2apic_mode = svm_set_virtual_x2apic_mode,
 
        .set_tss_addr = svm_set_tss_addr,
        .get_tdp_level = get_npt_level,
@@ -4302,6 +4315,7 @@ static struct kvm_x86_ops svm_x86_ops = {
        .has_wbinvd_exit = svm_has_wbinvd_exit,
 
        .set_tsc_khz = svm_set_tsc_khz,
+       .read_tsc_offset = svm_read_tsc_offset,
        .write_tsc_offset = svm_write_tsc_offset,
        .adjust_tsc_offset = svm_adjust_tsc_offset,
        .compute_tsc_offset = svm_compute_tsc_offset,