diff options
-rw-r--r-- | arch/x86/include/asm/kvm_host.h | 2 | ||||
-rw-r--r-- | arch/x86/kvm/lapic.c | 31 | ||||
-rw-r--r-- | arch/x86/kvm/lapic.h | 8 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 42 | ||||
-rw-r--r-- | include/linux/kvm.h | 1 |
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 | ||
368 | struct kvm_mem_alias { | 370 | struct 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 | |||
1250 | int 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 | |||
1263 | int 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 | ||
49 | int kvm_x2apic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data); | 49 | int kvm_x2apic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data); |
50 | int kvm_x2apic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data); | 50 | int kvm_x2apic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data); |
51 | |||
52 | int kvm_hv_vapic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data); | ||
53 | int kvm_hv_vapic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data); | ||
54 | |||
55 | static 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 |
626 | static u32 msrs_to_save[] = { | 626 | static 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 | ||
1068 | static int set_msr_hyperv(struct kvm_vcpu *vcpu, u32 msr, u64 data) | 1069 | static 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 | ||
1076 | int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) | 1103 | int 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 | ||