Skip to content

Commit d8ba8ba

Browse files
dwmw2bonzini
authored andcommitted
KVM: x86/xen: Allow XEN_RUNSTATE_UPDATE flag behaviour to be configured
Closer inspection of the Xen code shows that we aren't supposed to be using the XEN_RUNSTATE_UPDATE flag unconditionally. It should be explicitly enabled by guests through the HYPERVISOR_vm_assist hypercall. If we randomly set the top bit of ->state_entry_time for a guest that hasn't asked for it and doesn't expect it, that could make the runtimes fail to add up and confuse the guest. Without the flag it's perfectly safe for a vCPU to read its own vcpu_runstate_info; just not for one vCPU to read *another's*. I briefly pondered adding a word for the whole set of VMASST_TYPE_* flags but the only one we care about for HVM guests is this, so it seemed a bit pointless. Signed-off-by: David Woodhouse <[email protected]> Message-Id: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 5ec3289 commit d8ba8ba

File tree

6 files changed

+93
-20
lines changed

6 files changed

+93
-20
lines changed

Documentation/virt/kvm/api.rst

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5339,6 +5339,7 @@ KVM_PV_ASYNC_CLEANUP_PERFORM
53395339
union {
53405340
__u8 long_mode;
53415341
__u8 vector;
5342+
__u8 runstate_update_flag;
53425343
struct {
53435344
__u64 gfn;
53445345
} shared_info;
@@ -5416,6 +5417,14 @@ KVM_XEN_ATTR_TYPE_XEN_VERSION
54165417
event channel delivery, so responding within the kernel without
54175418
exiting to userspace is beneficial.
54185419

5420+
KVM_XEN_ATTR_TYPE_RUNSTATE_UPDATE_FLAG
5421+
This attribute is available when the KVM_CAP_XEN_HVM ioctl indicates
5422+
support for KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG. It enables the
5423+
XEN_RUNSTATE_UPDATE flag which allows guest vCPUs to safely read
5424+
other vCPUs' vcpu_runstate_info. Xen guests enable this feature via
5425+
the VM_ASST_TYPE_runstate_update_flag of the HYPERVISOR_vm_assist
5426+
hypercall.
5427+
54195428
4.127 KVM_XEN_HVM_GET_ATTR
54205429
--------------------------
54215430

@@ -8059,12 +8068,13 @@ to userspace.
80598068
This capability indicates the features that Xen supports for hosting Xen
80608069
PVHVM guests. Valid flags are::
80618070

8062-
#define KVM_XEN_HVM_CONFIG_HYPERCALL_MSR (1 << 0)
8063-
#define KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL (1 << 1)
8064-
#define KVM_XEN_HVM_CONFIG_SHARED_INFO (1 << 2)
8065-
#define KVM_XEN_HVM_CONFIG_RUNSTATE (1 << 3)
8066-
#define KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL (1 << 4)
8067-
#define KVM_XEN_HVM_CONFIG_EVTCHN_SEND (1 << 5)
8071+
#define KVM_XEN_HVM_CONFIG_HYPERCALL_MSR (1 << 0)
8072+
#define KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL (1 << 1)
8073+
#define KVM_XEN_HVM_CONFIG_SHARED_INFO (1 << 2)
8074+
#define KVM_XEN_HVM_CONFIG_RUNSTATE (1 << 3)
8075+
#define KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL (1 << 4)
8076+
#define KVM_XEN_HVM_CONFIG_EVTCHN_SEND (1 << 5)
8077+
#define KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG (1 << 6)
80688078

80698079
The KVM_XEN_HVM_CONFIG_HYPERCALL_MSR flag indicates that the KVM_XEN_HVM_CONFIG
80708080
ioctl is available, for the guest to set its hypercall page.
@@ -8096,6 +8106,18 @@ KVM_XEN_VCPU_ATTR_TYPE_VCPU_ID/TIMER/UPCALL_VECTOR vCPU attributes.
80968106
related to event channel delivery, timers, and the XENVER_version
80978107
interception.
80988108

8109+
The KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG flag indicates that KVM supports
8110+
the KVM_XEN_ATTR_TYPE_RUNSTATE_UPDATE_FLAG attribute in the KVM_XEN_SET_ATTR
8111+
and KVM_XEN_GET_ATTR ioctls. This controls whether KVM will set the
8112+
XEN_RUNSTATE_UPDATE flag in guest memory mapped vcpu_runstate_info during
8113+
updates of the runstate information. Note that versions of KVM which support
8114+
the RUNSTATE feature above, but not thie RUNSTATE_UPDATE_FLAG feature, will
8115+
always set the XEN_RUNSTATE_UPDATE flag when updating the guest structure,
8116+
which is perhaps counterintuitive. When this flag is advertised, KVM will
8117+
behave more correctly, not using the XEN_RUNSTATE_UPDATE flag until/unless
8118+
specifically enabled (by the guest making the hypercall, causing the VMM
8119+
to enable the KVM_XEN_ATTR_TYPE_RUNSTATE_UPDATE_FLAG attribute).
8120+
80998121
8.31 KVM_CAP_PPC_MULTITCE
81008122
-------------------------
81018123

arch/x86/include/asm/kvm_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,6 +1113,7 @@ struct msr_bitmap_range {
11131113
struct kvm_xen {
11141114
u32 xen_version;
11151115
bool long_mode;
1116+
bool runstate_update_flag;
11161117
u8 upcall_vector;
11171118
struct gfn_to_pfn_cache shinfo_cache;
11181119
struct idr evtchn_ports;

arch/x86/kvm/x86.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4431,7 +4431,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
44314431
KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL |
44324432
KVM_XEN_HVM_CONFIG_EVTCHN_SEND;
44334433
if (sched_info_on())
4434-
r |= KVM_XEN_HVM_CONFIG_RUNSTATE;
4434+
r |= KVM_XEN_HVM_CONFIG_RUNSTATE |
4435+
KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG;
44354436
break;
44364437
#endif
44374438
case KVM_CAP_SYNC_REGS:

arch/x86/kvm/xen.c

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,8 @@ static void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, bool atomic)
179179
struct vcpu_runstate_info rs;
180180
unsigned long flags;
181181
size_t times_ofs;
182-
uint8_t *update_bit;
182+
uint8_t *update_bit = NULL;
183+
uint64_t entry_time;
183184
uint64_t *rs_times;
184185
int *rs_state;
185186

@@ -297,7 +298,8 @@ static void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, bool atomic)
297298
*/
298299
rs_state = gpc1->khva;
299300
rs_times = gpc1->khva + times_ofs;
300-
update_bit = ((void *)(&rs_times[1])) - 1;
301+
if (v->kvm->arch.xen.runstate_update_flag)
302+
update_bit = ((void *)(&rs_times[1])) - 1;
301303
} else {
302304
/*
303305
* The guest's runstate_info is split across two pages and we
@@ -351,12 +353,14 @@ static void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, bool atomic)
351353
* The update_bit is still directly in the guest memory,
352354
* via one GPC or the other.
353355
*/
354-
if (user_len1 >= times_ofs + sizeof(uint64_t))
355-
update_bit = gpc1->khva + times_ofs +
356-
sizeof(uint64_t) - 1;
357-
else
358-
update_bit = gpc2->khva + times_ofs +
359-
sizeof(uint64_t) - 1 - user_len1;
356+
if (v->kvm->arch.xen.runstate_update_flag) {
357+
if (user_len1 >= times_ofs + sizeof(uint64_t))
358+
update_bit = gpc1->khva + times_ofs +
359+
sizeof(uint64_t) - 1;
360+
else
361+
update_bit = gpc2->khva + times_ofs +
362+
sizeof(uint64_t) - 1 - user_len1;
363+
}
360364

361365
#ifdef CONFIG_X86_64
362366
/*
@@ -376,16 +380,20 @@ static void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, bool atomic)
376380
* different cache line to the rest of the 64-bit word, due to
377381
* the (lack of) alignment constraints.
378382
*/
379-
*update_bit = (vx->runstate_entry_time | XEN_RUNSTATE_UPDATE) >> 56;
380-
smp_wmb();
383+
entry_time = vx->runstate_entry_time;
384+
if (update_bit) {
385+
entry_time |= XEN_RUNSTATE_UPDATE;
386+
*update_bit = (vx->runstate_entry_time | XEN_RUNSTATE_UPDATE) >> 56;
387+
smp_wmb();
388+
}
381389

382390
/*
383391
* Now assemble the actual structure, either on our kernel stack
384392
* or directly in the guest according to how the rs_state and
385393
* rs_times pointers were set up above.
386394
*/
387395
*rs_state = vx->current_runstate;
388-
rs_times[0] = vx->runstate_entry_time | XEN_RUNSTATE_UPDATE;
396+
rs_times[0] = entry_time;
389397
memcpy(rs_times + 1, vx->runstate_times, sizeof(vx->runstate_times));
390398

391399
/* For the split case, we have to then copy it to the guest. */
@@ -396,8 +404,11 @@ static void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, bool atomic)
396404
smp_wmb();
397405

398406
/* Finally, clear the XEN_RUNSTATE_UPDATE bit. */
399-
*update_bit = vx->runstate_entry_time >> 56;
400-
smp_wmb();
407+
if (update_bit) {
408+
entry_time &= ~XEN_RUNSTATE_UPDATE;
409+
*update_bit = entry_time >> 56;
410+
smp_wmb();
411+
}
401412

402413
if (user_len2)
403414
read_unlock(&gpc2->lock);
@@ -619,6 +630,17 @@ int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
619630
r = 0;
620631
break;
621632

633+
case KVM_XEN_ATTR_TYPE_RUNSTATE_UPDATE_FLAG:
634+
if (!sched_info_on()) {
635+
r = -EOPNOTSUPP;
636+
break;
637+
}
638+
mutex_lock(&kvm->lock);
639+
kvm->arch.xen.runstate_update_flag = !!data->u.runstate_update_flag;
640+
mutex_unlock(&kvm->lock);
641+
r = 0;
642+
break;
643+
622644
default:
623645
break;
624646
}
@@ -656,6 +678,15 @@ int kvm_xen_hvm_get_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
656678
r = 0;
657679
break;
658680

681+
case KVM_XEN_ATTR_TYPE_RUNSTATE_UPDATE_FLAG:
682+
if (!sched_info_on()) {
683+
r = -EOPNOTSUPP;
684+
break;
685+
}
686+
data->u.runstate_update_flag = kvm->arch.xen.runstate_update_flag;
687+
r = 0;
688+
break;
689+
659690
default:
660691
break;
661692
}

include/uapi/linux/kvm.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1271,6 +1271,7 @@ struct kvm_x86_mce {
12711271
#define KVM_XEN_HVM_CONFIG_RUNSTATE (1 << 3)
12721272
#define KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL (1 << 4)
12731273
#define KVM_XEN_HVM_CONFIG_EVTCHN_SEND (1 << 5)
1274+
#define KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG (1 << 6)
12741275

12751276
struct kvm_xen_hvm_config {
12761277
__u32 flags;
@@ -1776,6 +1777,7 @@ struct kvm_xen_hvm_attr {
17761777
union {
17771778
__u8 long_mode;
17781779
__u8 vector;
1780+
__u8 runstate_update_flag;
17791781
struct {
17801782
__u64 gfn;
17811783
} shared_info;
@@ -1816,6 +1818,8 @@ struct kvm_xen_hvm_attr {
18161818
/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_EVTCHN_SEND */
18171819
#define KVM_XEN_ATTR_TYPE_EVTCHN 0x3
18181820
#define KVM_XEN_ATTR_TYPE_XEN_VERSION 0x4
1821+
/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG */
1822+
#define KVM_XEN_ATTR_TYPE_RUNSTATE_UPDATE_FLAG 0x5
18191823

18201824
/* Per-vCPU Xen attributes */
18211825
#define KVM_XEN_VCPU_GET_ATTR _IOWR(KVMIO, 0xca, struct kvm_xen_vcpu_attr)

tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,7 @@ int main(int argc, char *argv[])
440440
TEST_REQUIRE(xen_caps & KVM_XEN_HVM_CONFIG_SHARED_INFO);
441441

442442
bool do_runstate_tests = !!(xen_caps & KVM_XEN_HVM_CONFIG_RUNSTATE);
443+
bool do_runstate_flag = !!(xen_caps & KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG);
443444
bool do_eventfd_tests = !!(xen_caps & KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL);
444445
bool do_evtchn_tests = do_eventfd_tests && !!(xen_caps & KVM_XEN_HVM_CONFIG_EVTCHN_SEND);
445446

@@ -475,6 +476,19 @@ int main(int argc, char *argv[])
475476
};
476477
vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &lm);
477478

479+
if (do_runstate_flag) {
480+
struct kvm_xen_hvm_attr ruf = {
481+
.type = KVM_XEN_ATTR_TYPE_RUNSTATE_UPDATE_FLAG,
482+
.u.runstate_update_flag = 1,
483+
};
484+
vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &ruf);
485+
486+
ruf.u.runstate_update_flag = 0;
487+
vm_ioctl(vm, KVM_XEN_HVM_GET_ATTR, &ruf);
488+
TEST_ASSERT(ruf.u.runstate_update_flag == 1,
489+
"Failed to read back RUNSTATE_UPDATE_FLAG attr");
490+
}
491+
478492
struct kvm_xen_hvm_attr ha = {
479493
.type = KVM_XEN_ATTR_TYPE_SHARED_INFO,
480494
.u.shared_info.gfn = SHINFO_REGION_GPA / PAGE_SIZE,

0 commit comments

Comments
 (0)