Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

kvm: x86: hyperv: make VP_INDEX managed by userspace

Hyper-V identifies vCPUs by Virtual Processor Index, which can be
queried via HV_X64_MSR_VP_INDEX msr. It is defined by the spec as a
sequential number which can't exceed the maximum number of vCPUs per VM.
APIC ids can be sparse and thus aren't a valid replacement for VP
indices.

Current KVM uses its internal vcpu index as VP_INDEX. However, to make
it predictable and persistent across VM migrations, the userspace has to
control the value of VP_INDEX.

This patch achieves that, by storing vp_index explicitly on vcpu, and
allowing HV_X64_MSR_VP_INDEX to be set from the host side. For
compatibility it's initialized to KVM vcpu index. Also a few variables
are renamed to make clear distinction betweed this Hyper-V vp_index and
KVM vcpu_id (== APIC id). Besides, a new capability,
KVM_CAP_HYPERV_VP_INDEX, is added to allow the userspace to skip
attempting msr writes where unsupported, to avoid spamming error logs.

Signed-off-by: Roman Kagan <rkagan@virtuozzo.com>
Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>

authored by

Roman Kagan and committed by
Radim Krčmář
d3457c87 52a5c155

+50 -19
+9
Documentation/virtual/kvm/api.txt
··· 4338 4338 controller (SynIC). The only difference with KVM_CAP_HYPERV_SYNIC is that KVM 4339 4339 doesn't clear SynIC message and event flags pages when they are enabled by 4340 4340 writing to the respective MSRs. 4341 + 4342 + 8.12 KVM_CAP_HYPERV_VP_INDEX 4343 + 4344 + Architectures: x86 4345 + 4346 + This capability indicates that userspace can load HV_X64_MSR_VP_INDEX msr. Its 4347 + value is used to denote the target vcpu for a SynIC interrupt. For 4348 + compatibilty, KVM initializes this msr to KVM's internal vcpu index. When this 4349 + capability is absent, userspace can still query this msr's value.
+1
arch/x86/include/asm/kvm_host.h
··· 467 467 468 468 /* Hyper-V per vcpu emulation context */ 469 469 struct kvm_vcpu_hv { 470 + u32 vp_index; 470 471 u64 hv_vapic; 471 472 s64 runtime_offset; 472 473 struct kvm_vcpu_hv_synic synic;
+35 -19
arch/x86/kvm/hyperv.c
··· 106 106 return 0; 107 107 } 108 108 109 - static struct kvm_vcpu_hv_synic *synic_get(struct kvm *kvm, u32 vcpu_id) 109 + static struct kvm_vcpu *get_vcpu_by_vpidx(struct kvm *kvm, u32 vpidx) 110 + { 111 + struct kvm_vcpu *vcpu = NULL; 112 + int i; 113 + 114 + if (vpidx < KVM_MAX_VCPUS) 115 + vcpu = kvm_get_vcpu(kvm, vpidx); 116 + if (vcpu && vcpu_to_hv_vcpu(vcpu)->vp_index == vpidx) 117 + return vcpu; 118 + kvm_for_each_vcpu(i, vcpu, kvm) 119 + if (vcpu_to_hv_vcpu(vcpu)->vp_index == vpidx) 120 + return vcpu; 121 + return NULL; 122 + } 123 + 124 + static struct kvm_vcpu_hv_synic *synic_get(struct kvm *kvm, u32 vpidx) 110 125 { 111 126 struct kvm_vcpu *vcpu; 112 127 struct kvm_vcpu_hv_synic *synic; 113 128 114 - if (vcpu_id >= atomic_read(&kvm->online_vcpus)) 115 - return NULL; 116 - vcpu = kvm_get_vcpu(kvm, vcpu_id); 129 + vcpu = get_vcpu_by_vpidx(kvm, vpidx); 117 130 if (!vcpu) 118 131 return NULL; 119 132 synic = vcpu_to_synic(vcpu); ··· 333 320 return ret; 334 321 } 335 322 336 - int kvm_hv_synic_set_irq(struct kvm *kvm, u32 vcpu_id, u32 sint) 323 + int kvm_hv_synic_set_irq(struct kvm *kvm, u32 vpidx, u32 sint) 337 324 { 338 325 struct kvm_vcpu_hv_synic *synic; 339 326 340 - synic = synic_get(kvm, vcpu_id); 327 + synic = synic_get(kvm, vpidx); 341 328 if (!synic) 342 329 return -EINVAL; 343 330 ··· 356 343 kvm_hv_notify_acked_sint(vcpu, i); 357 344 } 358 345 359 - static int kvm_hv_set_sint_gsi(struct kvm *kvm, u32 vcpu_id, u32 sint, int gsi) 346 + static int kvm_hv_set_sint_gsi(struct kvm *kvm, u32 vpidx, u32 sint, int gsi) 360 347 { 361 348 struct kvm_vcpu_hv_synic *synic; 362 349 363 - synic = synic_get(kvm, vcpu_id); 350 + synic = synic_get(kvm, vpidx); 364 351 if (!synic) 365 352 return -EINVAL; 366 353 ··· 702 689 stimer_init(&hv_vcpu->stimer[i], i); 703 690 } 704 691 692 + void kvm_hv_vcpu_postcreate(struct kvm_vcpu *vcpu) 693 + { 694 + struct kvm_vcpu_hv *hv_vcpu = vcpu_to_hv_vcpu(vcpu); 695 + 696 + hv_vcpu->vp_index = kvm_vcpu_get_idx(vcpu); 697 + } 698 + 705 699 int kvm_hv_activate_synic(struct kvm_vcpu *vcpu, bool dont_zero_synic_pages) 706 700 { 707 701 struct kvm_vcpu_hv_synic *synic = vcpu_to_synic(vcpu); ··· 1003 983 struct kvm_vcpu_hv *hv = &vcpu->arch.hyperv; 1004 984 1005 985 switch (msr) { 986 + case HV_X64_MSR_VP_INDEX: 987 + if (!host) 988 + return 1; 989 + hv->vp_index = (u32)data; 990 + break; 1006 991 case HV_X64_MSR_APIC_ASSIST_PAGE: { 1007 992 u64 gfn; 1008 993 unsigned long addr; ··· 1119 1094 struct kvm_vcpu_hv *hv = &vcpu->arch.hyperv; 1120 1095 1121 1096 switch (msr) { 1122 - case HV_X64_MSR_VP_INDEX: { 1123 - int r; 1124 - struct kvm_vcpu *v; 1125 - 1126 - kvm_for_each_vcpu(r, v, vcpu->kvm) { 1127 - if (v == vcpu) { 1128 - data = r; 1129 - break; 1130 - } 1131 - } 1097 + case HV_X64_MSR_VP_INDEX: 1098 + data = hv->vp_index; 1132 1099 break; 1133 - } 1134 1100 case HV_X64_MSR_EOI: 1135 1101 return kvm_hv_vapic_msr_read(vcpu, APIC_EOI, pdata); 1136 1102 case HV_X64_MSR_ICR:
+1
arch/x86/kvm/hyperv.h
··· 59 59 int kvm_hv_activate_synic(struct kvm_vcpu *vcpu, bool dont_zero_synic_pages); 60 60 61 61 void kvm_hv_vcpu_init(struct kvm_vcpu *vcpu); 62 + void kvm_hv_vcpu_postcreate(struct kvm_vcpu *vcpu); 62 63 void kvm_hv_vcpu_uninit(struct kvm_vcpu *vcpu); 63 64 64 65 static inline struct kvm_vcpu_hv_stimer *vcpu_to_stimer(struct kvm_vcpu *vcpu,
+3
arch/x86/kvm/x86.c
··· 2666 2666 case KVM_CAP_HYPERV_SPIN: 2667 2667 case KVM_CAP_HYPERV_SYNIC: 2668 2668 case KVM_CAP_HYPERV_SYNIC2: 2669 + case KVM_CAP_HYPERV_VP_INDEX: 2669 2670 case KVM_CAP_PCI_SEGMENT: 2670 2671 case KVM_CAP_DEBUGREGS: 2671 2672 case KVM_CAP_X86_ROBUST_SINGLESTEP: ··· 7688 7687 { 7689 7688 struct msr_data msr; 7690 7689 struct kvm *kvm = vcpu->kvm; 7690 + 7691 + kvm_hv_vcpu_postcreate(vcpu); 7691 7692 7692 7693 if (vcpu_load(vcpu)) 7693 7694 return;
+1
include/uapi/linux/kvm.h
··· 928 928 #define KVM_CAP_PPC_FWNMI 146 929 929 #define KVM_CAP_PPC_SMT_POSSIBLE 147 930 930 #define KVM_CAP_HYPERV_SYNIC2 148 931 + #define KVM_CAP_HYPERV_VP_INDEX 149 931 932 932 933 #ifdef KVM_CAP_IRQ_ROUTING 933 934