Skip to content

Commit b9220d3

Browse files
Paul Durrantsean-jc
authored andcommitted
KVM: x86/xen: allow shared_info to be mapped by fixed HVA
The shared_info page is not guest memory as such. It is a dedicated page allocated by the VMM and overlaid onto guest memory in a GFN chosen by the guest and specified in the XENMEM_add_to_physmap hypercall. The guest may even request that shared_info be moved from one GFN to another by re-issuing that hypercall, but the HVA is never going to change. Because the shared_info page is an overlay the memory slots need to be updated in response to the hypercall. However, memory slot adjustment is not atomic and, whilst all vCPUs are paused, there is still the possibility that events may be delivered (which requires the shared_info page to be updated) whilst the shared_info GPA is absent. The HVA is never absent though, so it makes much more sense to use that as the basis for the kernel's mapping. Hence add a new KVM_XEN_ATTR_TYPE_SHARED_INFO_HVA attribute type for this purpose and a KVM_XEN_HVM_CONFIG_SHARED_INFO_HVA flag to advertize its availability. Don't actually advertize it yet though. That will be done in a subsequent patch, which will also add tests for the new attribute type. Also update the KVM API documentation with the new attribute and also fix it up to consistently refer to 'shared_info' (with the underscore). Signed-off-by: Paul Durrant <pdurrant@amazon.com> Reviewed-by: David Woodhouse <dwmw@amazon.co.uk> Link: https://lore.kernel.org/r/20240215152916.1158-13-paul@xen.org [sean: store "hva" as a user pointer, use kvm_gpc_is_{gpa,hva}_active()] Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent 18b99e4 commit b9220d3

File tree

3 files changed

+56
-15
lines changed

3 files changed

+56
-15
lines changed

Documentation/virt/kvm/api.rst

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ The bits in the dirty bitmap are cleared before the ioctl returns, unless
372372
KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 is enabled. For more information,
373373
see the description of the capability.
374374

375-
Note that the Xen shared info page, if configured, shall always be assumed
375+
Note that the Xen shared_info page, if configured, shall always be assumed
376376
to be dirty. KVM will not explicitly mark it such.
377377

378378

@@ -5487,8 +5487,9 @@ KVM_PV_ASYNC_CLEANUP_PERFORM
54875487
__u8 long_mode;
54885488
__u8 vector;
54895489
__u8 runstate_update_flag;
5490-
struct {
5490+
union {
54915491
__u64 gfn;
5492+
__u64 hva;
54925493
} shared_info;
54935494
struct {
54945495
__u32 send_port;
@@ -5516,10 +5517,10 @@ type values:
55165517

55175518
KVM_XEN_ATTR_TYPE_LONG_MODE
55185519
Sets the ABI mode of the VM to 32-bit or 64-bit (long mode). This
5519-
determines the layout of the shared info pages exposed to the VM.
5520+
determines the layout of the shared_info page exposed to the VM.
55205521

55215522
KVM_XEN_ATTR_TYPE_SHARED_INFO
5522-
Sets the guest physical frame number at which the Xen "shared info"
5523+
Sets the guest physical frame number at which the Xen shared_info
55235524
page resides. Note that although Xen places vcpu_info for the first
55245525
32 vCPUs in the shared_info page, KVM does not automatically do so
55255526
and instead requires that KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO be used
@@ -5528,7 +5529,7 @@ KVM_XEN_ATTR_TYPE_SHARED_INFO
55285529
not be aware of the Xen CPU id which is used as the index into the
55295530
vcpu_info[] array, so may know the correct default location.
55305531

5531-
Note that the shared info page may be constantly written to by KVM;
5532+
Note that the shared_info page may be constantly written to by KVM;
55325533
it contains the event channel bitmap used to deliver interrupts to
55335534
a Xen guest, amongst other things. It is exempt from dirty tracking
55345535
mechanisms — KVM will not explicitly mark the page as dirty each
@@ -5537,9 +5538,21 @@ KVM_XEN_ATTR_TYPE_SHARED_INFO
55375538
any vCPU has been running or any event channel interrupts can be
55385539
routed to the guest.
55395540

5540-
Setting the gfn to KVM_XEN_INVALID_GFN will disable the shared info
5541+
Setting the gfn to KVM_XEN_INVALID_GFN will disable the shared_info
55415542
page.
55425543

5544+
KVM_XEN_ATTR_TYPE_SHARED_INFO_HVA
5545+
If the KVM_XEN_HVM_CONFIG_SHARED_INFO_HVA flag is also set in the
5546+
Xen capabilities, then this attribute may be used to set the
5547+
userspace address at which the shared_info page resides, which
5548+
will always be fixed in the VMM regardless of where it is mapped
5549+
in guest physical address space. This attribute should be used in
5550+
preference to KVM_XEN_ATTR_TYPE_SHARED_INFO as it avoids
5551+
unnecessary invalidation of an internal cache when the page is
5552+
re-mapped in guest physcial address space.
5553+
5554+
Setting the hva to zero will disable the shared_info page.
5555+
55435556
KVM_XEN_ATTR_TYPE_UPCALL_VECTOR
55445557
Sets the exception vector used to deliver Xen event channel upcalls.
55455558
This is the HVM-wide vector injected directly by the hypervisor

arch/x86/include/uapi/asm/kvm.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,7 @@ struct kvm_x86_mce {
549549
#define KVM_XEN_HVM_CONFIG_EVTCHN_SEND (1 << 5)
550550
#define KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG (1 << 6)
551551
#define KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE (1 << 7)
552+
#define KVM_XEN_HVM_CONFIG_SHARED_INFO_HVA (1 << 8)
552553

553554
struct kvm_xen_hvm_config {
554555
__u32 flags;
@@ -567,9 +568,10 @@ struct kvm_xen_hvm_attr {
567568
__u8 long_mode;
568569
__u8 vector;
569570
__u8 runstate_update_flag;
570-
struct {
571+
union {
571572
__u64 gfn;
572573
#define KVM_XEN_INVALID_GFN ((__u64)-1)
574+
__u64 hva;
573575
} shared_info;
574576
struct {
575577
__u32 send_port;
@@ -611,6 +613,8 @@ struct kvm_xen_hvm_attr {
611613
#define KVM_XEN_ATTR_TYPE_XEN_VERSION 0x4
612614
/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG */
613615
#define KVM_XEN_ATTR_TYPE_RUNSTATE_UPDATE_FLAG 0x5
616+
/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO_HVA */
617+
#define KVM_XEN_ATTR_TYPE_SHARED_INFO_HVA 0x6
614618

615619
struct kvm_xen_vcpu_attr {
616620
__u16 type;

arch/x86/kvm/xen.c

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -638,20 +638,36 @@ int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
638638
}
639639
break;
640640

641-
case KVM_XEN_ATTR_TYPE_SHARED_INFO: {
641+
case KVM_XEN_ATTR_TYPE_SHARED_INFO:
642+
case KVM_XEN_ATTR_TYPE_SHARED_INFO_HVA: {
642643
int idx;
643644

644645
mutex_lock(&kvm->arch.xen.xen_lock);
645646

646647
idx = srcu_read_lock(&kvm->srcu);
647648

648-
if (data->u.shared_info.gfn == KVM_XEN_INVALID_GFN) {
649-
kvm_gpc_deactivate(&kvm->arch.xen.shinfo_cache);
650-
r = 0;
649+
if (data->type == KVM_XEN_ATTR_TYPE_SHARED_INFO) {
650+
gfn_t gfn = data->u.shared_info.gfn;
651+
652+
if (gfn == KVM_XEN_INVALID_GFN) {
653+
kvm_gpc_deactivate(&kvm->arch.xen.shinfo_cache);
654+
r = 0;
655+
} else {
656+
r = kvm_gpc_activate(&kvm->arch.xen.shinfo_cache,
657+
gfn_to_gpa(gfn), PAGE_SIZE);
658+
}
651659
} else {
652-
r = kvm_gpc_activate(&kvm->arch.xen.shinfo_cache,
653-
gfn_to_gpa(data->u.shared_info.gfn),
654-
PAGE_SIZE);
660+
void __user * hva = u64_to_user_ptr(data->u.shared_info.hva);
661+
662+
if (!PAGE_ALIGNED(hva) || !access_ok(hva, PAGE_SIZE)) {
663+
r = -EINVAL;
664+
} else if (!hva) {
665+
kvm_gpc_deactivate(&kvm->arch.xen.shinfo_cache);
666+
r = 0;
667+
} else {
668+
r = kvm_gpc_activate_hva(&kvm->arch.xen.shinfo_cache,
669+
(unsigned long)hva, PAGE_SIZE);
670+
}
655671
}
656672

657673
srcu_read_unlock(&kvm->srcu, idx);
@@ -715,13 +731,21 @@ int kvm_xen_hvm_get_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
715731
break;
716732

717733
case KVM_XEN_ATTR_TYPE_SHARED_INFO:
718-
if (kvm->arch.xen.shinfo_cache.active)
734+
if (kvm_gpc_is_gpa_active(&kvm->arch.xen.shinfo_cache))
719735
data->u.shared_info.gfn = gpa_to_gfn(kvm->arch.xen.shinfo_cache.gpa);
720736
else
721737
data->u.shared_info.gfn = KVM_XEN_INVALID_GFN;
722738
r = 0;
723739
break;
724740

741+
case KVM_XEN_ATTR_TYPE_SHARED_INFO_HVA:
742+
if (kvm_gpc_is_hva_active(&kvm->arch.xen.shinfo_cache))
743+
data->u.shared_info.hva = kvm->arch.xen.shinfo_cache.uhva;
744+
else
745+
data->u.shared_info.hva = 0;
746+
r = 0;
747+
break;
748+
725749
case KVM_XEN_ATTR_TYPE_UPCALL_VECTOR:
726750
data->u.vector = kvm->arch.xen.upcall_vector;
727751
r = 0;

0 commit comments

Comments
 (0)