Skip to content

Commit d3457c8

Browse files
rvkarkrcmar
authored andcommitted
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>
1 parent 52a5c15 commit d3457c8

File tree

6 files changed

+50
-19
lines changed

6 files changed

+50
-19
lines changed

Documentation/virtual/kvm/api.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4338,3 +4338,12 @@ This capability enables a newer version of Hyper-V Synthetic interrupt
43384338
controller (SynIC). The only difference with KVM_CAP_HYPERV_SYNIC is that KVM
43394339
doesn't clear SynIC message and event flags pages when they are enabled by
43404340
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.

arch/x86/include/asm/kvm_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,7 @@ struct kvm_vcpu_hv_synic {
467467

468468
/* Hyper-V per vcpu emulation context */
469469
struct kvm_vcpu_hv {
470+
u32 vp_index;
470471
u64 hv_vapic;
471472
s64 runtime_offset;
472473
struct kvm_vcpu_hv_synic synic;

arch/x86/kvm/hyperv.c

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -106,14 +106,27 @@ static int synic_set_sint(struct kvm_vcpu_hv_synic *synic, int sint,
106106
return 0;
107107
}
108108

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)
110125
{
111126
struct kvm_vcpu *vcpu;
112127
struct kvm_vcpu_hv_synic *synic;
113128

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);
117130
if (!vcpu)
118131
return NULL;
119132
synic = vcpu_to_synic(vcpu);
@@ -320,11 +333,11 @@ static int synic_set_irq(struct kvm_vcpu_hv_synic *synic, u32 sint)
320333
return ret;
321334
}
322335

323-
int kvm_hv_synic_set_irq(struct kvm *kvm, u32 vcpu_id, u32 sint)
336+
int kvm_hv_synic_set_irq(struct kvm *kvm, u32 vpidx, u32 sint)
324337
{
325338
struct kvm_vcpu_hv_synic *synic;
326339

327-
synic = synic_get(kvm, vcpu_id);
340+
synic = synic_get(kvm, vpidx);
328341
if (!synic)
329342
return -EINVAL;
330343

@@ -343,11 +356,11 @@ void kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector)
343356
kvm_hv_notify_acked_sint(vcpu, i);
344357
}
345358

346-
static int kvm_hv_set_sint_gsi(struct kvm *kvm, u32 vcpu_id, u32 sint, int gsi)
359+
static int kvm_hv_set_sint_gsi(struct kvm *kvm, u32 vpidx, u32 sint, int gsi)
347360
{
348361
struct kvm_vcpu_hv_synic *synic;
349362

350-
synic = synic_get(kvm, vcpu_id);
363+
synic = synic_get(kvm, vpidx);
351364
if (!synic)
352365
return -EINVAL;
353366

@@ -689,6 +702,13 @@ void kvm_hv_vcpu_init(struct kvm_vcpu *vcpu)
689702
stimer_init(&hv_vcpu->stimer[i], i);
690703
}
691704

705+
void kvm_hv_vcpu_postcreate(struct kvm_vcpu *vcpu)
706+
{
707+
struct kvm_vcpu_hv *hv_vcpu = vcpu_to_hv_vcpu(vcpu);
708+
709+
hv_vcpu->vp_index = kvm_vcpu_get_idx(vcpu);
710+
}
711+
692712
int kvm_hv_activate_synic(struct kvm_vcpu *vcpu, bool dont_zero_synic_pages)
693713
{
694714
struct kvm_vcpu_hv_synic *synic = vcpu_to_synic(vcpu);
@@ -983,6 +1003,11 @@ static int kvm_hv_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host)
9831003
struct kvm_vcpu_hv *hv = &vcpu->arch.hyperv;
9841004

9851005
switch (msr) {
1006+
case HV_X64_MSR_VP_INDEX:
1007+
if (!host)
1008+
return 1;
1009+
hv->vp_index = (u32)data;
1010+
break;
9861011
case HV_X64_MSR_APIC_ASSIST_PAGE: {
9871012
u64 gfn;
9881013
unsigned long addr;
@@ -1094,18 +1119,9 @@ static int kvm_hv_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
10941119
struct kvm_vcpu_hv *hv = &vcpu->arch.hyperv;
10951120

10961121
switch (msr) {
1097-
case HV_X64_MSR_VP_INDEX: {
1098-
int r;
1099-
struct kvm_vcpu *v;
1100-
1101-
kvm_for_each_vcpu(r, v, vcpu->kvm) {
1102-
if (v == vcpu) {
1103-
data = r;
1104-
break;
1105-
}
1106-
}
1122+
case HV_X64_MSR_VP_INDEX:
1123+
data = hv->vp_index;
11071124
break;
1108-
}
11091125
case HV_X64_MSR_EOI:
11101126
return kvm_hv_vapic_msr_read(vcpu, APIC_EOI, pdata);
11111127
case HV_X64_MSR_ICR:

arch/x86/kvm/hyperv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ void kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector);
5959
int kvm_hv_activate_synic(struct kvm_vcpu *vcpu, bool dont_zero_synic_pages);
6060

6161
void kvm_hv_vcpu_init(struct kvm_vcpu *vcpu);
62+
void kvm_hv_vcpu_postcreate(struct kvm_vcpu *vcpu);
6263
void kvm_hv_vcpu_uninit(struct kvm_vcpu *vcpu);
6364

6465
static inline struct kvm_vcpu_hv_stimer *vcpu_to_stimer(struct kvm_vcpu *vcpu,

arch/x86/kvm/x86.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2666,6 +2666,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
26662666
case KVM_CAP_HYPERV_SPIN:
26672667
case KVM_CAP_HYPERV_SYNIC:
26682668
case KVM_CAP_HYPERV_SYNIC2:
2669+
case KVM_CAP_HYPERV_VP_INDEX:
26692670
case KVM_CAP_PCI_SEGMENT:
26702671
case KVM_CAP_DEBUGREGS:
26712672
case KVM_CAP_X86_ROBUST_SINGLESTEP:
@@ -7688,6 +7689,8 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
76887689
struct msr_data msr;
76897690
struct kvm *kvm = vcpu->kvm;
76907691

7692+
kvm_hv_vcpu_postcreate(vcpu);
7693+
76917694
if (vcpu_load(vcpu))
76927695
return;
76937696
msr.data = 0x0;

include/uapi/linux/kvm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -928,6 +928,7 @@ struct kvm_ppc_resize_hpt {
928928
#define KVM_CAP_PPC_FWNMI 146
929929
#define KVM_CAP_PPC_SMT_POSSIBLE 147
930930
#define KVM_CAP_HYPERV_SYNIC2 148
931+
#define KVM_CAP_HYPERV_VP_INDEX 149
931932

932933
#ifdef KVM_CAP_IRQ_ROUTING
933934

0 commit comments

Comments
 (0)