Signed-off-by: Gleb Natapov <[email protected]>
Signed-off-by: Vadim Rozenfeld <[email protected]>
---
 arch/x86/include/asm/kvm_host.h |    2 +
 arch/x86/kvm/lapic.c            |   53 +++++++++++++++++++++++++++++++++++++++
 arch/x86/kvm/lapic.h            |    8 ++++++
 arch/x86/kvm/x86.c              |   34 ++++++++++++++++++++++---
 include/linux/kvm.h             |    1 +
 5 files changed, 94 insertions(+), 4 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 7bfd468..4d82c52 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -362,6 +362,8 @@ struct kvm_vcpu_arch {
        /* used for guest single stepping over the given code position */
        u16 singlestep_cs;
        unsigned long singlestep_rip;
+       /* fields used by HYPER-V emulation */
+       u64 hv_vapic;
 };
 
 struct kvm_mem_alias {
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index ba8c045..063963f 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -1246,3 +1246,56 @@ int kvm_x2apic_msr_read(struct kvm_vcpu *vcpu, u32 msr, 
u64 *data)
 
        return 0;
 }
+
+static u32 kvm_hv_vapic_msr2reg(u32 msr)
+{
+       u32 reg;
+       switch (msr) {
+       case HV_X64_MSR_EOI:
+               reg = APIC_EOI;
+               break;
+       case HV_X64_MSR_ICR:
+               reg = APIC_ICR;
+               break;
+       case HV_X64_MSR_TPR:
+               reg = APIC_TASKPRI;
+               break;
+       default:
+               reg = -1;
+               break;
+       }
+
+       return reg;
+}
+
+int kvm_hv_vapic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data)
+{
+       struct kvm_lapic *apic = vcpu->arch.apic;
+       u32 reg = kvm_hv_vapic_msr2reg(msr);
+
+       if (!irqchip_in_kernel(vcpu->kvm))
+               return 1;
+
+       /* if this is ICR write vector before command */
+       if (reg == APIC_ICR)
+               apic_reg_write(apic, APIC_ICR2, (u32)(data >> 32));
+       return apic_reg_write(apic, reg, (u32)data);
+}
+
+int kvm_hv_vapic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data)
+{
+       struct kvm_lapic *apic = vcpu->arch.apic;
+       u32 reg = kvm_hv_vapic_msr2reg(msr), low, high = 0;
+
+       if (!irqchip_in_kernel(vcpu->kvm))
+               return 1;
+
+       if (apic_reg_read(apic, reg, 4, &low))
+               return 1;
+       if (reg == APIC_ICR)
+               apic_reg_read(apic, APIC_ICR2, 4, &high);
+
+       *data = (((u64)high) << 32) | low;
+
+       return 0;
+}
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index 40010b0..d081cb6 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -48,4 +48,12 @@ void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu);
 
 int kvm_x2apic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data);
 int kvm_x2apic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data);
+
+int kvm_hv_vapic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data);
+int kvm_hv_vapic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data);
+
+static inline bool kvm_hv_vapic_enabled(struct kvm_vcpu *vcpu)
+{
+       return !!(vcpu->arch.hv_vapic & HV_X64_MSR_APIC_ASSIST_PAGE_ENABLE);
+}
 #endif
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 6972b2b..e058898 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -629,7 +629,8 @@ static u32 msrs_to_save[] = {
        MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR,
 #endif
        MSR_IA32_TSC, MSR_IA32_PERF_STATUS, MSR_IA32_CR_PAT, MSR_VM_HSAVE_PA,
-       HV_X64_MSR_GUEST_OS_ID, HV_X64_MSR_HYPERCALL
+       HV_X64_MSR_GUEST_OS_ID, HV_X64_MSR_HYPERCALL,
+       HV_X64_MSR_APIC_ASSIST_PAGE
 };
 
 static unsigned num_msrs_to_save;
@@ -1061,10 +1062,30 @@ static int set_msr_hyperv_pw(struct kvm_vcpu *vcpu, u32 
msr, u64 data)
 
 static int set_msr_hyperv(struct kvm_vcpu *vcpu, u32 msr, u64 data)
 {
-       pr_unimpl(vcpu, "HYPER-V unimplemented wrmsr: 0x%x data 0x%llx\n",
-                 msr, data);
+       switch (msr) {
+       case HV_X64_MSR_APIC_ASSIST_PAGE: {
+               unsigned long addr;
+               vcpu->arch.hv_vapic = data;
+               if(!kvm_hv_vapic_enabled(vcpu))
+                       break;
+               addr = gfn_to_hva(vcpu->kvm, data >>
+                                 HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT);
+               if (kvm_is_error_hva(addr))
+                       return 1;
+               memset((void*)addr, 0, PAGE_SIZE);
+               break;
+       }
+       case HV_X64_MSR_EOI:
+       case HV_X64_MSR_ICR:
+       case HV_X64_MSR_TPR:
+               return kvm_hv_vapic_msr_write(vcpu, msr, data);
+       default:
+               pr_unimpl(vcpu, "HYPER-V unimplemented wrmsr: 0x%x "
+                         "data 0x%llx\n", msr, data);
+               return 1;
+       }
 
-       return 1;
+       return 0;
 }
 
 int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
@@ -1324,6 +1345,10 @@ static int get_msr_hyperv(struct kvm_vcpu *vcpu, u32 
msr, u64 *pdata)
                                data = r;
                break;
        }
+       case HV_X64_MSR_EOI:
+       case HV_X64_MSR_ICR:
+       case HV_X64_MSR_TPR:
+               return kvm_hv_vapic_msr_read(vcpu, msr, pdata);
        default:
                pr_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr);
                return 1;
@@ -1524,6 +1549,7 @@ int kvm_dev_ioctl_check_extension(long ext)
        case KVM_CAP_ADJUST_CLOCK:
        case KVM_CAP_VCPU_EVENTS:
        case KVM_CAP_HYPERV:
+       case KVM_CAP_HYPERV_VAPIC:
                r = 1;
                break;
        case KVM_CAP_COALESCED_MMIO:
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index e227cba..5ce6173 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -498,6 +498,7 @@ struct kvm_ioeventfd {
 #define KVM_CAP_S390_PSW 42
 #define KVM_CAP_PPC_SEGSTATE 43
 #define KVM_CAP_HYPERV 44
+#define KVM_CAP_HYPERV_VAPIC 45
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
-- 
1.6.5

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to