aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/kvm_host.h2
-rw-r--r--arch/x86/kvm/lapic.c31
-rw-r--r--arch/x86/kvm/lapic.h8
-rw-r--r--arch/x86/kvm/x86.c42
-rw-r--r--include/linux/kvm.h1
5 files changed, 80 insertions, 4 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 67d19e422006..a1f0b5dd7d75 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -363,6 +363,8 @@ struct kvm_vcpu_arch {
363 /* used for guest single stepping over the given code position */ 363 /* used for guest single stepping over the given code position */
364 u16 singlestep_cs; 364 u16 singlestep_cs;
365 unsigned long singlestep_rip; 365 unsigned long singlestep_rip;
366 /* fields used by HYPER-V emulation */
367 u64 hv_vapic;
366}; 368};
367 369
368struct kvm_mem_alias { 370struct kvm_mem_alias {
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index ba8c045da782..4b224f90087b 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -1246,3 +1246,34 @@ int kvm_x2apic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data)
1246 1246
1247 return 0; 1247 return 0;
1248} 1248}
1249
1250int kvm_hv_vapic_msr_write(struct kvm_vcpu *vcpu, u32 reg, u64 data)
1251{
1252 struct kvm_lapic *apic = vcpu->arch.apic;
1253
1254 if (!irqchip_in_kernel(vcpu->kvm))
1255 return 1;
1256
1257 /* if this is ICR write vector before command */
1258 if (reg == APIC_ICR)
1259 apic_reg_write(apic, APIC_ICR2, (u32)(data >> 32));
1260 return apic_reg_write(apic, reg, (u32)data);
1261}
1262
1263int kvm_hv_vapic_msr_read(struct kvm_vcpu *vcpu, u32 reg, u64 *data)
1264{
1265 struct kvm_lapic *apic = vcpu->arch.apic;
1266 u32 low, high = 0;
1267
1268 if (!irqchip_in_kernel(vcpu->kvm))
1269 return 1;
1270
1271 if (apic_reg_read(apic, reg, 4, &low))
1272 return 1;
1273 if (reg == APIC_ICR)
1274 apic_reg_read(apic, APIC_ICR2, 4, &high);
1275
1276 *data = (((u64)high) << 32) | low;
1277
1278 return 0;
1279}
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index 40010b09c4aa..f5fe32c5edad 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);
48 48
49int kvm_x2apic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data); 49int kvm_x2apic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data);
50int kvm_x2apic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data); 50int kvm_x2apic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data);
51
52int kvm_hv_vapic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data);
53int kvm_hv_vapic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data);
54
55static inline bool kvm_hv_vapic_assist_page_enabled(struct kvm_vcpu *vcpu)
56{
57 return vcpu->arch.hv_vapic & HV_X64_MSR_APIC_ASSIST_PAGE_ENABLE;
58}
51#endif 59#endif
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 480137db4770..552be51e4d84 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -622,10 +622,11 @@ static inline u32 bit(int bitno)
622 * kvm-specific. Those are put in the beginning of the list. 622 * kvm-specific. Those are put in the beginning of the list.
623 */ 623 */
624 624
625#define KVM_SAVE_MSRS_BEGIN 4 625#define KVM_SAVE_MSRS_BEGIN 5
626static u32 msrs_to_save[] = { 626static u32 msrs_to_save[] = {
627 MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK, 627 MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK,
628 HV_X64_MSR_GUEST_OS_ID, HV_X64_MSR_HYPERCALL, 628 HV_X64_MSR_GUEST_OS_ID, HV_X64_MSR_HYPERCALL,
629 HV_X64_MSR_APIC_ASSIST_PAGE,
629 MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP, 630 MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
630 MSR_K6_STAR, 631 MSR_K6_STAR,
631#ifdef CONFIG_X86_64 632#ifdef CONFIG_X86_64
@@ -1067,10 +1068,36 @@ static int set_msr_hyperv_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data)
1067 1068
1068static int set_msr_hyperv(struct kvm_vcpu *vcpu, u32 msr, u64 data) 1069static int set_msr_hyperv(struct kvm_vcpu *vcpu, u32 msr, u64 data)
1069{ 1070{
1070 pr_unimpl(vcpu, "HYPER-V unimplemented wrmsr: 0x%x data 0x%llx\n", 1071 switch (msr) {
1071 msr, data); 1072 case HV_X64_MSR_APIC_ASSIST_PAGE: {
1073 unsigned long addr;
1072 1074
1073 return 1; 1075 if (!(data & HV_X64_MSR_APIC_ASSIST_PAGE_ENABLE)) {
1076 vcpu->arch.hv_vapic = data;
1077 break;
1078 }
1079 addr = gfn_to_hva(vcpu->kvm, data >>
1080 HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT);
1081 if (kvm_is_error_hva(addr))
1082 return 1;
1083 if (clear_user((void __user *)addr, PAGE_SIZE))
1084 return 1;
1085 vcpu->arch.hv_vapic = data;
1086 break;
1087 }
1088 case HV_X64_MSR_EOI:
1089 return kvm_hv_vapic_msr_write(vcpu, APIC_EOI, data);
1090 case HV_X64_MSR_ICR:
1091 return kvm_hv_vapic_msr_write(vcpu, APIC_ICR, data);
1092 case HV_X64_MSR_TPR:
1093 return kvm_hv_vapic_msr_write(vcpu, APIC_TASKPRI, data);
1094 default:
1095 pr_unimpl(vcpu, "HYPER-V unimplemented wrmsr: 0x%x "
1096 "data 0x%llx\n", msr, data);
1097 return 1;
1098 }
1099
1100 return 0;
1074} 1101}
1075 1102
1076int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) 1103int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
@@ -1330,6 +1357,12 @@ static int get_msr_hyperv(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
1330 data = r; 1357 data = r;
1331 break; 1358 break;
1332 } 1359 }
1360 case HV_X64_MSR_EOI:
1361 return kvm_hv_vapic_msr_read(vcpu, APIC_EOI, pdata);
1362 case HV_X64_MSR_ICR:
1363 return kvm_hv_vapic_msr_read(vcpu, APIC_ICR, pdata);
1364 case HV_X64_MSR_TPR:
1365 return kvm_hv_vapic_msr_read(vcpu, APIC_TASKPRI, pdata);
1333 default: 1366 default:
1334 pr_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr); 1367 pr_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr);
1335 return 1; 1368 return 1;
@@ -1530,6 +1563,7 @@ int kvm_dev_ioctl_check_extension(long ext)
1530 case KVM_CAP_ADJUST_CLOCK: 1563 case KVM_CAP_ADJUST_CLOCK:
1531 case KVM_CAP_VCPU_EVENTS: 1564 case KVM_CAP_VCPU_EVENTS:
1532 case KVM_CAP_HYPERV: 1565 case KVM_CAP_HYPERV:
1566 case KVM_CAP_HYPERV_VAPIC:
1533 r = 1; 1567 r = 1;
1534 break; 1568 break;
1535 case KVM_CAP_COALESCED_MMIO: 1569 case KVM_CAP_COALESCED_MMIO:
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index e227cbae70ad..5ce61738dc30 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -498,6 +498,7 @@ struct kvm_ioeventfd {
498#define KVM_CAP_S390_PSW 42 498#define KVM_CAP_S390_PSW 42
499#define KVM_CAP_PPC_SEGSTATE 43 499#define KVM_CAP_PPC_SEGSTATE 43
500#define KVM_CAP_HYPERV 44 500#define KVM_CAP_HYPERV 44
501#define KVM_CAP_HYPERV_VAPIC 45
501 502
502#ifdef KVM_CAP_IRQ_ROUTING 503#ifdef KVM_CAP_IRQ_ROUTING
503 504