All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/15] KVM: Add Xen hypercall and shared info pages
@ 2020-12-04  1:18 David Woodhouse
  2020-12-04  1:18 ` [PATCH 01/15] KVM: Fix arguments to kvm_{un,}map_gfn() David Woodhouse
                   ` (16 more replies)
  0 siblings, 17 replies; 33+ messages in thread
From: David Woodhouse @ 2020-12-04  1:18 UTC (permalink / raw)
  To: kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson

Reviving the first section (so far) of a patch set that Joao posted as 
RFC last year:

https://lore.kernel.org/kvm/20190220201609.28290-1-joao.m.martins@oracle.com/

This adds basic hypercall interception support, and adds support for
timekeeping and runstate-related shared info regions.

I've updated and reworked the original a bit, including:
 • Support for 32-bit guests
 • 64-bit second support in wallclock
 • Time counters for runnable/blocked states in runstate support
 • Self-tests
 • Fixed Viridian coexistence
 • No new KVM_CAP_XEN_xxx, just more bits returned by KVM_CAP_XEN_HVM

I'm about to do the event channel support, but this part stands alone
and should be sufficient to get a fully functional Xen HVM guest running.

David Woodhouse (6):
      KVM: Fix arguments to kvm_{un,}map_gfn()
      KVM: x86/xen: Fix coexistence of Xen and Hyper-V hypercalls
      KVM: x86/xen: latch long_mode when hypercall page is set up
      KVM: x86/xen: add definitions of compat_shared_info, compat_vcpu_info
      xen: add wc_sec_hi to struct shared_info
      KVM: x86: declare Xen HVM shared info capability and add test case

Joao Martins (9):
      KVM: x86/xen: fix Xen hypercall page msr handling
      KVM: x86/xen: intercept xen hypercalls if enabled
      KVM: x86/xen: add KVM_XEN_HVM_SET_ATTR/KVM_XEN_HVM_GET_ATTR
      KVM: x86/xen: register shared_info page
      KVM: x86/xen: setup pvclock updates
      KVM: x86/xen: update wallclock region
      KVM: x86/xen: register vcpu info
      KVM: x86/xen: register vcpu time info region
      KVM: x86/xen: register runstate info

 arch/x86/include/asm/kvm_host.h                    |  23 +
 arch/x86/include/asm/xen/interface.h               |   3 +
 arch/x86/kvm/Makefile                              |   2 +-
 arch/x86/kvm/hyperv.c                              |  40 +-
 arch/x86/kvm/trace.h                               |  36 ++
 arch/x86/kvm/x86.c                                 | 109 +++--
 arch/x86/kvm/x86.h                                 |   1 +
 arch/x86/kvm/xen.c                                 | 544 +++++++++++++++++++++
 arch/x86/kvm/xen.h                                 |  83 ++++
 include/linux/kvm_host.h                           |  34 +-
 include/uapi/linux/kvm.h                           |  47 ++
 include/xen/interface/xen.h                        |   4 +-
 tools/testing/selftests/kvm/Makefile               |   2 +
 tools/testing/selftests/kvm/lib/kvm_util.c         |   1 +
 .../testing/selftests/kvm/x86_64/xen_shinfo_test.c | 187 +++++++
 .../testing/selftests/kvm/x86_64/xen_vmcall_test.c | 150 ++++++
 virt/kvm/kvm_main.c                                |   8 +-
 17 files changed, 1201 insertions(+), 73 deletions(-)

32-bit guests, and fleshed out the runstate information a little more
to add times for all of running, runnable, blocked states.





^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH 01/15] KVM: Fix arguments to kvm_{un,}map_gfn()
  2020-12-04  1:18 [PATCH 00/15] KVM: Add Xen hypercall and shared info pages David Woodhouse
@ 2020-12-04  1:18 ` David Woodhouse
  2020-12-04 18:27   ` Alexander Graf
  2020-12-04  1:18 ` [PATCH 02/15] KVM: x86/xen: fix Xen hypercall page msr handling David Woodhouse
                   ` (15 subsequent siblings)
  16 siblings, 1 reply; 33+ messages in thread
From: David Woodhouse @ 2020-12-04  1:18 UTC (permalink / raw)
  To: kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson

From: David Woodhouse <dwmw@amazon.co.uk>

It shouldn't take a vcpu.

Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
 arch/x86/kvm/x86.c       | 8 ++++----
 include/linux/kvm_host.h | 4 ++--
 virt/kvm/kvm_main.c      | 8 ++++----
 3 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index e545a8a613b1..c7f1ba21212e 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2957,7 +2957,7 @@ static void record_steal_time(struct kvm_vcpu *vcpu)
 		return;
 
 	/* -EAGAIN is returned in atomic context so we can just return. */
-	if (kvm_map_gfn(vcpu, vcpu->arch.st.msr_val >> PAGE_SHIFT,
+	if (kvm_map_gfn(vcpu->kvm, vcpu->arch.st.msr_val >> PAGE_SHIFT,
 			&map, &vcpu->arch.st.cache, false))
 		return;
 
@@ -2992,7 +2992,7 @@ static void record_steal_time(struct kvm_vcpu *vcpu)
 
 	st->version += 1;
 
-	kvm_unmap_gfn(vcpu, &map, &vcpu->arch.st.cache, true, false);
+	kvm_unmap_gfn(vcpu->kvm, &map, &vcpu->arch.st.cache, true, false);
 }
 
 int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
@@ -3981,7 +3981,7 @@ static void kvm_steal_time_set_preempted(struct kvm_vcpu *vcpu)
 	if (vcpu->arch.st.preempted)
 		return;
 
-	if (kvm_map_gfn(vcpu, vcpu->arch.st.msr_val >> PAGE_SHIFT, &map,
+	if (kvm_map_gfn(vcpu->kvm, vcpu->arch.st.msr_val >> PAGE_SHIFT, &map,
 			&vcpu->arch.st.cache, true))
 		return;
 
@@ -3990,7 +3990,7 @@ static void kvm_steal_time_set_preempted(struct kvm_vcpu *vcpu)
 
 	st->preempted = vcpu->arch.st.preempted = KVM_VCPU_PREEMPTED;
 
-	kvm_unmap_gfn(vcpu, &map, &vcpu->arch.st.cache, true, true);
+	kvm_unmap_gfn(vcpu->kvm, &map, &vcpu->arch.st.cache, true, true);
 }
 
 void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 7f2e2a09ebbd..8eb5eb1399f5 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -806,11 +806,11 @@ struct kvm_memory_slot *kvm_vcpu_gfn_to_memslot(struct kvm_vcpu *vcpu, gfn_t gfn
 kvm_pfn_t kvm_vcpu_gfn_to_pfn_atomic(struct kvm_vcpu *vcpu, gfn_t gfn);
 kvm_pfn_t kvm_vcpu_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn);
 int kvm_vcpu_map(struct kvm_vcpu *vcpu, gpa_t gpa, struct kvm_host_map *map);
-int kvm_map_gfn(struct kvm_vcpu *vcpu, gfn_t gfn, struct kvm_host_map *map,
+int kvm_map_gfn(struct kvm *kvm, gfn_t gfn, struct kvm_host_map *map,
 		struct gfn_to_pfn_cache *cache, bool atomic);
 struct page *kvm_vcpu_gfn_to_page(struct kvm_vcpu *vcpu, gfn_t gfn);
 void kvm_vcpu_unmap(struct kvm_vcpu *vcpu, struct kvm_host_map *map, bool dirty);
-int kvm_unmap_gfn(struct kvm_vcpu *vcpu, struct kvm_host_map *map,
+int kvm_unmap_gfn(struct kvm *kvm, struct kvm_host_map *map,
 		  struct gfn_to_pfn_cache *cache, bool dirty, bool atomic);
 unsigned long kvm_vcpu_gfn_to_hva(struct kvm_vcpu *vcpu, gfn_t gfn);
 unsigned long kvm_vcpu_gfn_to_hva_prot(struct kvm_vcpu *vcpu, gfn_t gfn, bool *writable);
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 2541a17ff1c4..f01a8df7806a 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -2181,10 +2181,10 @@ static int __kvm_map_gfn(struct kvm_memslots *slots, gfn_t gfn,
 	return 0;
 }
 
-int kvm_map_gfn(struct kvm_vcpu *vcpu, gfn_t gfn, struct kvm_host_map *map,
+int kvm_map_gfn(struct kvm *kvm, gfn_t gfn, struct kvm_host_map *map,
 		struct gfn_to_pfn_cache *cache, bool atomic)
 {
-	return __kvm_map_gfn(kvm_memslots(vcpu->kvm), gfn, map,
+	return __kvm_map_gfn(kvm_memslots(kvm), gfn, map,
 			cache, atomic);
 }
 EXPORT_SYMBOL_GPL(kvm_map_gfn);
@@ -2232,10 +2232,10 @@ static void __kvm_unmap_gfn(struct kvm_memory_slot *memslot,
 	map->page = NULL;
 }
 
-int kvm_unmap_gfn(struct kvm_vcpu *vcpu, struct kvm_host_map *map, 
+int kvm_unmap_gfn(struct kvm *kvm, struct kvm_host_map *map,
 		  struct gfn_to_pfn_cache *cache, bool dirty, bool atomic)
 {
-	__kvm_unmap_gfn(gfn_to_memslot(vcpu->kvm, map->gfn), map,
+	__kvm_unmap_gfn(gfn_to_memslot(kvm, map->gfn), map,
 			cache, dirty, atomic);
 	return 0;
 }
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 02/15] KVM: x86/xen: fix Xen hypercall page msr handling
  2020-12-04  1:18 [PATCH 00/15] KVM: Add Xen hypercall and shared info pages David Woodhouse
  2020-12-04  1:18 ` [PATCH 01/15] KVM: Fix arguments to kvm_{un,}map_gfn() David Woodhouse
@ 2020-12-04  1:18 ` David Woodhouse
  2020-12-04 18:26   ` Alexander Graf
  2020-12-04  1:18 ` [PATCH 03/15] KVM: x86/xen: intercept xen hypercalls if enabled David Woodhouse
                   ` (14 subsequent siblings)
  16 siblings, 1 reply; 33+ messages in thread
From: David Woodhouse @ 2020-12-04  1:18 UTC (permalink / raw)
  To: kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson

From: Joao Martins <joao.m.martins@oracle.com>

Xen usually places its MSR at 0x40000000 or 0x40000200 depending on
whether it is running in viridian mode or not. Note that this is not
ABI guaranteed, so it is possible for Xen to advertise the MSR some
place else.

Given the way xen_hvm_config() is handled, if the former address is
selected, this will conflict with Hyper-V's MSR
(HV_X64_MSR_GUEST_OS_ID) which unconditionally uses the same address.

Given that the MSR location is arbitrary, move the xen_hvm_config()
handling to the top of kvm_set_msr_common() before falling through.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
 arch/x86/kvm/x86.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index c7f1ba21212e..13ba4a64f748 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3001,6 +3001,9 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 	u32 msr = msr_info->index;
 	u64 data = msr_info->data;
 
+	if (msr && (msr == vcpu->kvm->arch.xen_hvm_config.msr))
+		return xen_hvm_config(vcpu, data);
+
 	switch (msr) {
 	case MSR_AMD64_NB_CFG:
 	case MSR_IA32_UCODE_WRITE:
@@ -3288,8 +3291,6 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 		vcpu->arch.msr_misc_features_enables = data;
 		break;
 	default:
-		if (msr && (msr == vcpu->kvm->arch.xen_hvm_config.msr))
-			return xen_hvm_config(vcpu, data);
 		if (kvm_pmu_is_valid_msr(vcpu, msr))
 			return kvm_pmu_set_msr(vcpu, msr_info);
 		return KVM_MSR_RET_INVALID;
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 03/15] KVM: x86/xen: intercept xen hypercalls if enabled
  2020-12-04  1:18 [PATCH 00/15] KVM: Add Xen hypercall and shared info pages David Woodhouse
  2020-12-04  1:18 ` [PATCH 01/15] KVM: Fix arguments to kvm_{un,}map_gfn() David Woodhouse
  2020-12-04  1:18 ` [PATCH 02/15] KVM: x86/xen: fix Xen hypercall page msr handling David Woodhouse
@ 2020-12-04  1:18 ` David Woodhouse
  2020-12-04 18:26   ` Alexander Graf
  2020-12-05 18:42   ` Joao Martins
  2020-12-04  1:18 ` [PATCH 04/15] KVM: x86/xen: Fix coexistence of Xen and Hyper-V hypercalls David Woodhouse
                   ` (13 subsequent siblings)
  16 siblings, 2 replies; 33+ messages in thread
From: David Woodhouse @ 2020-12-04  1:18 UTC (permalink / raw)
  To: kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson

From: Joao Martins <joao.m.martins@oracle.com>

Add a new exit reason for emulator to handle Xen hypercalls.

Since this means KVM owns the ABI, dispense with the facility for the
VMM to provide its own copy of the hypercall pages; just fill them in
directly using VMCALL/VMMCALL as we do for the Hyper-V hypercall page.

This behaviour is enabled by a new INTERCEPT_HCALL flag in the
KVM_XEN_HVM_CONFIG ioctl structure, and advertised by the same flag
being returned from the KVM_CAP_XEN_HVM check.

Add a test case and shift xen_hvm_config() to the nascent xen.c while
we're at it.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
 arch/x86/include/asm/kvm_host.h               |   6 +
 arch/x86/kvm/Makefile                         |   2 +-
 arch/x86/kvm/trace.h                          |  36 +++++
 arch/x86/kvm/x86.c                            |  46 +++---
 arch/x86/kvm/xen.c                            | 140 ++++++++++++++++++
 arch/x86/kvm/xen.h                            |  21 +++
 include/uapi/linux/kvm.h                      |  19 +++
 tools/testing/selftests/kvm/Makefile          |   1 +
 tools/testing/selftests/kvm/lib/kvm_util.c    |   1 +
 .../selftests/kvm/x86_64/xen_vmcall_test.c    | 123 +++++++++++++++
 10 files changed, 365 insertions(+), 30 deletions(-)
 create mode 100644 arch/x86/kvm/xen.c
 create mode 100644 arch/x86/kvm/xen.h
 create mode 100644 tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 7e5f33a0d0e2..9de3229e91e1 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -520,6 +520,11 @@ struct kvm_vcpu_hv {
 	cpumask_t tlb_flush;
 };
 
+/* Xen HVM per vcpu emulation context */
+struct kvm_vcpu_xen {
+	u64 hypercall_rip;
+};
+
 struct kvm_vcpu_arch {
 	/*
 	 * rip and regs accesses must go through
@@ -717,6 +722,7 @@ struct kvm_vcpu_arch {
 	unsigned long singlestep_rip;
 
 	struct kvm_vcpu_hv hyperv;
+	struct kvm_vcpu_xen xen;
 
 	cpumask_var_t wbinvd_dirty_mask;
 
diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile
index b804444e16d4..8bee4afc1fec 100644
--- a/arch/x86/kvm/Makefile
+++ b/arch/x86/kvm/Makefile
@@ -13,7 +13,7 @@ kvm-y			+= $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o \
 				$(KVM)/eventfd.o $(KVM)/irqchip.o $(KVM)/vfio.o
 kvm-$(CONFIG_KVM_ASYNC_PF)	+= $(KVM)/async_pf.o
 
-kvm-y			+= x86.o emulate.o i8259.o irq.o lapic.o \
+kvm-y			+= x86.o emulate.o i8259.o irq.o lapic.o xen.o \
 			   i8254.o ioapic.o irq_comm.o cpuid.o pmu.o mtrr.o \
 			   hyperv.o debugfs.o mmu/mmu.o mmu/page_track.o \
 			   mmu/spte.o mmu/tdp_iter.o mmu/tdp_mmu.o
diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h
index aef960f90f26..d28ecb37b62c 100644
--- a/arch/x86/kvm/trace.h
+++ b/arch/x86/kvm/trace.h
@@ -92,6 +92,42 @@ TRACE_EVENT(kvm_hv_hypercall,
 		  __entry->outgpa)
 );
 
+/*
+ * Tracepoint for Xen hypercall.
+ */
+TRACE_EVENT(kvm_xen_hypercall,
+	TP_PROTO(unsigned long nr, unsigned long a0, unsigned long a1,
+		 unsigned long a2, unsigned long a3, unsigned long a4,
+		 unsigned long a5),
+	    TP_ARGS(nr, a0, a1, a2, a3, a4, a5),
+
+	TP_STRUCT__entry(
+		__field(unsigned long, nr)
+		__field(unsigned long, a0)
+		__field(unsigned long, a1)
+		__field(unsigned long, a2)
+		__field(unsigned long, a3)
+		__field(unsigned long, a4)
+		__field(unsigned long, a5)
+	),
+
+	TP_fast_assign(
+		__entry->nr = nr;
+		__entry->a0 = a0;
+		__entry->a1 = a1;
+		__entry->a2 = a2;
+		__entry->a3 = a3;
+		__entry->a4 = a4;
+		__entry->a4 = a5;
+	),
+
+	TP_printk("nr 0x%lx a0 0x%lx a1 0x%lx a2 0x%lx a3 0x%lx a4 0x%lx a5 %lx",
+		  __entry->nr, __entry->a0, __entry->a1,  __entry->a2,
+		  __entry->a3, __entry->a4, __entry->a5)
+);
+
+
+
 /*
  * Tracepoint for PIO.
  */
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 13ba4a64f748..1a7f016afb21 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -29,6 +29,7 @@
 #include "pmu.h"
 #include "hyperv.h"
 #include "lapic.h"
+#include "xen.h"
 
 #include <linux/clocksource.h>
 #include <linux/interrupt.h>
@@ -2842,32 +2843,6 @@ static int set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 	return 0;
 }
 
-static int xen_hvm_config(struct kvm_vcpu *vcpu, u64 data)
-{
-	struct kvm *kvm = vcpu->kvm;
-	int lm = is_long_mode(vcpu);
-	u8 *blob_addr = lm ? (u8 *)(long)kvm->arch.xen_hvm_config.blob_addr_64
-		: (u8 *)(long)kvm->arch.xen_hvm_config.blob_addr_32;
-	u8 blob_size = lm ? kvm->arch.xen_hvm_config.blob_size_64
-		: kvm->arch.xen_hvm_config.blob_size_32;
-	u32 page_num = data & ~PAGE_MASK;
-	u64 page_addr = data & PAGE_MASK;
-	u8 *page;
-
-	if (page_num >= blob_size)
-		return 1;
-
-	page = memdup_user(blob_addr + (page_num * PAGE_SIZE), PAGE_SIZE);
-	if (IS_ERR(page))
-		return PTR_ERR(page);
-
-	if (kvm_vcpu_write_guest(vcpu, page_addr, page, PAGE_SIZE)) {
-		kfree(page);
-		return 1;
-	}
-	return 0;
-}
-
 static inline bool kvm_pv_async_pf_enabled(struct kvm_vcpu *vcpu)
 {
 	u64 mask = KVM_ASYNC_PF_ENABLED | KVM_ASYNC_PF_DELIVERY_AS_INT;
@@ -3002,7 +2977,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 	u64 data = msr_info->data;
 
 	if (msr && (msr == vcpu->kvm->arch.xen_hvm_config.msr))
-		return xen_hvm_config(vcpu, data);
+		return kvm_xen_hvm_config(vcpu, data);
 
 	switch (msr) {
 	case MSR_AMD64_NB_CFG:
@@ -3703,7 +3678,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 	case KVM_CAP_PIT2:
 	case KVM_CAP_PIT_STATE2:
 	case KVM_CAP_SET_IDENTITY_MAP_ADDR:
-	case KVM_CAP_XEN_HVM:
 	case KVM_CAP_VCPU_EVENTS:
 	case KVM_CAP_HYPERV:
 	case KVM_CAP_HYPERV_VAPIC:
@@ -3742,6 +3716,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 	case KVM_CAP_ENFORCE_PV_FEATURE_CPUID:
 		r = 1;
 		break;
+	case KVM_CAP_XEN_HVM:
+		r = 1 | KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL;
+		break;
 	case KVM_CAP_SYNC_REGS:
 		r = KVM_SYNC_X86_VALID_FIELDS;
 		break;
@@ -5603,7 +5580,15 @@ long kvm_arch_vm_ioctl(struct file *filp,
 		if (copy_from_user(&xhc, argp, sizeof(xhc)))
 			goto out;
 		r = -EINVAL;
-		if (xhc.flags)
+		if (xhc.flags & ~KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL)
+			goto out;
+		/*
+		 * With hypercall interception the kernel generates its own
+		 * hypercall page so it must not be provided.
+		 */
+		if ((xhc.flags & KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL) &&
+		    (xhc.blob_addr_32 || xhc.blob_addr_64 ||
+		     xhc.blob_size_32 || xhc.blob_size_64))
 			goto out;
 		memcpy(&kvm->arch.xen_hvm_config, &xhc, sizeof(xhc));
 		r = 0;
@@ -8066,6 +8051,9 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
 	unsigned long nr, a0, a1, a2, a3, ret;
 	int op_64_bit;
 
+	if (kvm_xen_hypercall_enabled(vcpu->kvm))
+		return kvm_xen_hypercall(vcpu);
+
 	if (kvm_hv_hypercall_enabled(vcpu->kvm))
 		return kvm_hv_hypercall(vcpu);
 
diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c
new file mode 100644
index 000000000000..b76d121a86c0
--- /dev/null
+++ b/arch/x86/kvm/xen.c
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright © 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright © 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * KVM Xen emulation
+ */
+
+#include "x86.h"
+#include "xen.h"
+
+#include <linux/kvm_host.h>
+
+#include <trace/events/kvm.h>
+
+#include "trace.h"
+
+int kvm_xen_hvm_config(struct kvm_vcpu *vcpu, u64 data)
+{
+	struct kvm *kvm = vcpu->kvm;
+	u32 page_num = data & ~PAGE_MASK;
+	u64 page_addr = data & PAGE_MASK;
+
+	/*
+	 * If Xen hypercall intercept is enabled, fill the hypercall
+	 * page with VMCALL/VMMCALL instructions since that's what
+	 * we catch. Else the VMM has provided the hypercall pages
+	 * with instructions of its own choosing, so use those.
+	 */
+	if (kvm_xen_hypercall_enabled(kvm)) {
+		u8 instructions[32];
+		int i;
+
+		if (page_num)
+			return 1;
+
+		/* mov imm32, %eax */
+		instructions[0] = 0xb8;
+
+		/* vmcall / vmmcall */
+		kvm_x86_ops.patch_hypercall(vcpu, instructions + 5);
+
+		/* ret */
+		instructions[8] = 0xc3;
+
+		/* int3 to pad */
+		memset(instructions + 9, 0xcc, sizeof(instructions) - 9);
+
+		for (i = 0; i < PAGE_SIZE / sizeof(instructions); i++) {
+			*(u32 *)&instructions[1] = i;
+			if (kvm_vcpu_write_guest(vcpu,
+						 page_addr + (i * sizeof(instructions)),
+						 instructions, sizeof(instructions)))
+				return 1;
+		}
+	} else {
+		int lm = is_long_mode(vcpu);
+		u8 *blob_addr = lm ? (u8 *)(long)kvm->arch.xen_hvm_config.blob_addr_64
+				   : (u8 *)(long)kvm->arch.xen_hvm_config.blob_addr_32;
+		u8 blob_size = lm ? kvm->arch.xen_hvm_config.blob_size_64
+				  : kvm->arch.xen_hvm_config.blob_size_32;
+		u8 *page;
+
+		if (page_num >= blob_size)
+			return 1;
+
+		page = memdup_user(blob_addr + (page_num * PAGE_SIZE), PAGE_SIZE);
+		if (IS_ERR(page))
+			return PTR_ERR(page);
+
+		if (kvm_vcpu_write_guest(vcpu, page_addr, page, PAGE_SIZE)) {
+			kfree(page);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static int kvm_xen_hypercall_set_result(struct kvm_vcpu *vcpu, u64 result)
+{
+	kvm_rax_write(vcpu, result);
+	return kvm_skip_emulated_instruction(vcpu);
+}
+
+static int kvm_xen_hypercall_complete_userspace(struct kvm_vcpu *vcpu)
+{
+	struct kvm_run *run = vcpu->run;
+
+	if (unlikely(!kvm_is_linear_rip(vcpu, vcpu->arch.xen.hypercall_rip)))
+		return 1;
+
+	return kvm_xen_hypercall_set_result(vcpu, run->xen.u.hcall.result);
+}
+
+int kvm_xen_hypercall(struct kvm_vcpu *vcpu)
+{
+	bool longmode;
+	u64 input, params[6];
+
+	input = (u64)kvm_register_read(vcpu, VCPU_REGS_RAX);
+
+	longmode = is_64_bit_mode(vcpu);
+	if (!longmode) {
+		params[0] = (u32)kvm_rbx_read(vcpu);
+		params[1] = (u32)kvm_rcx_read(vcpu);
+		params[2] = (u32)kvm_rdx_read(vcpu);
+		params[3] = (u32)kvm_rsi_read(vcpu);
+		params[4] = (u32)kvm_rdi_read(vcpu);
+		params[5] = (u32)kvm_rbp_read(vcpu);
+	}
+#ifdef CONFIG_X86_64
+	else {
+		params[0] = (u64)kvm_rdi_read(vcpu);
+		params[1] = (u64)kvm_rsi_read(vcpu);
+		params[2] = (u64)kvm_rdx_read(vcpu);
+		params[3] = (u64)kvm_r10_read(vcpu);
+		params[4] = (u64)kvm_r8_read(vcpu);
+		params[5] = (u64)kvm_r9_read(vcpu);
+	}
+#endif
+	trace_kvm_xen_hypercall(input, params[0], params[1], params[2],
+				params[3], params[4], params[5]);
+
+	vcpu->run->exit_reason = KVM_EXIT_XEN;
+	vcpu->run->xen.type = KVM_EXIT_XEN_HCALL;
+	vcpu->run->xen.u.hcall.longmode = longmode;
+	vcpu->run->xen.u.hcall.cpl = kvm_x86_ops.get_cpl(vcpu);
+	vcpu->run->xen.u.hcall.input = input;
+	vcpu->run->xen.u.hcall.params[0] = params[0];
+	vcpu->run->xen.u.hcall.params[1] = params[1];
+	vcpu->run->xen.u.hcall.params[2] = params[2];
+	vcpu->run->xen.u.hcall.params[3] = params[3];
+	vcpu->run->xen.u.hcall.params[4] = params[4];
+	vcpu->run->xen.u.hcall.params[5] = params[5];
+	vcpu->arch.xen.hypercall_rip = kvm_get_linear_rip(vcpu);
+	vcpu->arch.complete_userspace_io =
+		kvm_xen_hypercall_complete_userspace;
+
+	return 0;
+}
diff --git a/arch/x86/kvm/xen.h b/arch/x86/kvm/xen.h
new file mode 100644
index 000000000000..81e12f716d2e
--- /dev/null
+++ b/arch/x86/kvm/xen.h
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright © 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright © 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * KVM Xen emulation
+ */
+
+#ifndef __ARCH_X86_KVM_XEN_H__
+#define __ARCH_X86_KVM_XEN_H__
+
+int kvm_xen_hypercall(struct kvm_vcpu *vcpu);
+int kvm_xen_hvm_config(struct kvm_vcpu *vcpu, u64 data);
+
+static inline bool kvm_xen_hypercall_enabled(struct kvm *kvm)
+{
+	return kvm->arch.xen_hvm_config.flags &
+		KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL;
+}
+
+#endif /* __ARCH_X86_KVM_XEN_H__ */
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index ca41220b40b8..00221fe56994 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -216,6 +216,20 @@ struct kvm_hyperv_exit {
 	} u;
 };
 
+struct kvm_xen_exit {
+#define KVM_EXIT_XEN_HCALL          1
+	__u32 type;
+	union {
+		struct {
+			__u32 longmode;
+			__u32 cpl;
+			__u64 input;
+			__u64 result;
+			__u64 params[6];
+		} hcall;
+	} u;
+};
+
 #define KVM_S390_GET_SKEYS_NONE   1
 #define KVM_S390_SKEYS_MAX        1048576
 
@@ -250,6 +264,7 @@ struct kvm_hyperv_exit {
 #define KVM_EXIT_ARM_NISV         28
 #define KVM_EXIT_X86_RDMSR        29
 #define KVM_EXIT_X86_WRMSR        30
+#define KVM_EXIT_XEN              31
 
 /* For KVM_EXIT_INTERNAL_ERROR */
 /* Emulate instruction failed. */
@@ -426,6 +441,8 @@ struct kvm_run {
 			__u32 index; /* kernel -> user */
 			__u64 data; /* kernel <-> user */
 		} msr;
+		/* KVM_EXIT_XEN */
+		struct kvm_xen_exit xen;
 		/* Fix the size of the union. */
 		char padding[256];
 	};
@@ -1126,6 +1143,8 @@ struct kvm_x86_mce {
 #endif
 
 #ifdef KVM_CAP_XEN_HVM
+#define KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL	(1 << 1)
+
 struct kvm_xen_hvm_config {
 	__u32 flags;
 	__u32 msr;
diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
index 3d14ef77755e..d94abec627e6 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -59,6 +59,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/xss_msr_test
 TEST_GEN_PROGS_x86_64 += x86_64/debug_regs
 TEST_GEN_PROGS_x86_64 += x86_64/tsc_msrs_test
 TEST_GEN_PROGS_x86_64 += x86_64/user_msr_test
+TEST_GEN_PROGS_x86_64 += x86_64/xen_vmcall_test
 TEST_GEN_PROGS_x86_64 += demand_paging_test
 TEST_GEN_PROGS_x86_64 += dirty_log_test
 TEST_GEN_PROGS_x86_64 += dirty_log_perf_test
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 126c6727a6b0..6e96ae47d28c 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -1654,6 +1654,7 @@ static struct exit_reason {
 	{KVM_EXIT_INTERNAL_ERROR, "INTERNAL_ERROR"},
 	{KVM_EXIT_OSI, "OSI"},
 	{KVM_EXIT_PAPR_HCALL, "PAPR_HCALL"},
+	{KVM_EXIT_XEN, "XEN"},
 #ifdef KVM_EXIT_MEMORY_NOT_PRESENT
 	{KVM_EXIT_MEMORY_NOT_PRESENT, "MEMORY_NOT_PRESENT"},
 #endif
diff --git a/tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c b/tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c
new file mode 100644
index 000000000000..3f1dd93626e5
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * svm_vmcall_test
+ *
+ * Copyright © 2020 Amazon.com, Inc. or its affiliates.
+ *
+ * Userspace hypercall testing
+ */
+
+#include "test_util.h"
+#include "kvm_util.h"
+#include "processor.h"
+
+#define VCPU_ID		5
+
+#define HCALL_REGION_GPA	0xc0000000ULL
+#define HCALL_REGION_SLOT	10
+
+static struct kvm_vm *vm;
+
+#define INPUTVALUE 17
+#define ARGVALUE(x) (0xdeadbeef5a5a0000UL + x)
+#define RETVALUE 0xcafef00dfbfbffffUL
+
+#define XEN_HYPERCALL_MSR 0x40000000
+
+static void guest_code(void)
+{
+	unsigned long rax = INPUTVALUE;
+	unsigned long rdi = ARGVALUE(1);
+	unsigned long rsi = ARGVALUE(2);
+	unsigned long rdx = ARGVALUE(3);
+	register unsigned long r10 __asm__("r10") = ARGVALUE(4);
+	register unsigned long r8 __asm__("r8") = ARGVALUE(5);
+	register unsigned long r9 __asm__("r9") = ARGVALUE(6);
+
+	/* First a direct invocation of 'vmcall' */
+	__asm__ __volatile__("vmcall" :
+			     "=a"(rax) :
+			     "a"(rax), "D"(rdi), "S"(rsi), "d"(rdx),
+			     "r"(r10), "r"(r8), "r"(r9));
+	GUEST_ASSERT(rax == RETVALUE);
+
+	/* Now fill in the hypercall page */
+	__asm__ __volatile__("wrmsr" : : "c" (XEN_HYPERCALL_MSR),
+			     "a" (HCALL_REGION_GPA & 0xffffffff),
+			     "d" (HCALL_REGION_GPA >> 32));
+
+	/* And invoke the same hypercall that way */
+	__asm__ __volatile__("call *%1" : "=a"(rax) :
+			     "r"(HCALL_REGION_GPA + INPUTVALUE * 32),
+			     "a"(rax), "D"(rdi), "S"(rsi), "d"(rdx),
+			     "r"(r10), "r"(r8), "r"(r9));
+	GUEST_ASSERT(rax == RETVALUE);
+
+	GUEST_DONE();
+}
+
+int main(int argc, char *argv[])
+{
+	if (!(kvm_check_cap(KVM_CAP_XEN_HVM) &
+	      KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL) ) {
+		print_skip("KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL not available");
+		exit(KSFT_SKIP);
+	}
+
+	vm = vm_create_default(VCPU_ID, 0, (void *) guest_code);
+	vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid());
+
+	struct kvm_xen_hvm_config hvmc = {
+		.flags = KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL,
+		.msr = XEN_HYPERCALL_MSR,
+	};
+	vm_ioctl(vm, KVM_XEN_HVM_CONFIG, &hvmc);
+
+	/* Map a region for the hypercall page */
+	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
+                                    HCALL_REGION_GPA, HCALL_REGION_SLOT,
+				    getpagesize(), 0);
+	virt_map(vm, HCALL_REGION_GPA, HCALL_REGION_GPA, 1, 0);
+
+	for (;;) {
+		volatile struct kvm_run *run = vcpu_state(vm, VCPU_ID);
+		struct ucall uc;
+
+		vcpu_run(vm, VCPU_ID);
+
+		if (run->exit_reason == KVM_EXIT_XEN) {
+			ASSERT_EQ(run->xen.type, KVM_EXIT_XEN_HCALL);
+			ASSERT_EQ(run->xen.u.hcall.cpl, 0);
+			ASSERT_EQ(run->xen.u.hcall.longmode, 1);
+			ASSERT_EQ(run->xen.u.hcall.input, INPUTVALUE);
+			ASSERT_EQ(run->xen.u.hcall.params[0], ARGVALUE(1));
+			ASSERT_EQ(run->xen.u.hcall.params[1], ARGVALUE(2));
+			ASSERT_EQ(run->xen.u.hcall.params[2], ARGVALUE(3));
+			ASSERT_EQ(run->xen.u.hcall.params[3], ARGVALUE(4));
+			ASSERT_EQ(run->xen.u.hcall.params[4], ARGVALUE(5));
+			ASSERT_EQ(run->xen.u.hcall.params[5], ARGVALUE(6));
+			run->xen.u.hcall.result = RETVALUE;
+			continue;
+		}
+
+		TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
+			    "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n",
+			    run->exit_reason,
+			    exit_reason_str(run->exit_reason));
+
+		switch (get_ucall(vm, VCPU_ID, &uc)) {
+		case UCALL_ABORT:
+			TEST_FAIL("%s", (const char *)uc.args[0]);
+			/* NOT REACHED */
+		case UCALL_SYNC:
+			break;
+		case UCALL_DONE:
+			goto done;
+		default:
+			TEST_FAIL("Unknown ucall 0x%lx.", uc.cmd);
+		}
+	}
+done:
+	kvm_vm_free(vm);
+	return 0;
+}
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 04/15] KVM: x86/xen: Fix coexistence of Xen and Hyper-V hypercalls
  2020-12-04  1:18 [PATCH 00/15] KVM: Add Xen hypercall and shared info pages David Woodhouse
                   ` (2 preceding siblings ...)
  2020-12-04  1:18 ` [PATCH 03/15] KVM: x86/xen: intercept xen hypercalls if enabled David Woodhouse
@ 2020-12-04  1:18 ` David Woodhouse
  2020-12-04 18:34   ` Alexander Graf
  2020-12-04  1:18 ` [PATCH 05/15] KVM: x86/xen: add KVM_XEN_HVM_SET_ATTR/KVM_XEN_HVM_GET_ATTR David Woodhouse
                   ` (12 subsequent siblings)
  16 siblings, 1 reply; 33+ messages in thread
From: David Woodhouse @ 2020-12-04  1:18 UTC (permalink / raw)
  To: kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson

From: David Woodhouse <dwmw@amazon.co.uk>

Disambiguate Xen vs. Hyper-V calls by adding 'orl $0x80000000, %eax'
at the start of the Hyper-V hypercall page when Xen hypercalls are
also enabled.

That bit is reserved in the Hyper-V ABI, and those hypercall numbers
will never be used by Xen (because it does precisely the same trick).

Switch to using kvm_vcpu_write_guest() while we're at it, instead of
open-coding it.

Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
 arch/x86/kvm/hyperv.c                         | 40 ++++++++++++++-----
 arch/x86/kvm/xen.c                            |  6 +++
 .../selftests/kvm/x86_64/xen_vmcall_test.c    | 39 +++++++++++++++---
 3 files changed, 68 insertions(+), 17 deletions(-)

diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c
index 5c7c4060b45c..347ff9ad70b3 100644
--- a/arch/x86/kvm/hyperv.c
+++ b/arch/x86/kvm/hyperv.c
@@ -23,6 +23,7 @@
 #include "ioapic.h"
 #include "cpuid.h"
 #include "hyperv.h"
+#include "xen.h"
 
 #include <linux/cpu.h>
 #include <linux/kvm_host.h>
@@ -1139,9 +1140,9 @@ static int kvm_hv_set_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data,
 			hv->hv_hypercall &= ~HV_X64_MSR_HYPERCALL_ENABLE;
 		break;
 	case HV_X64_MSR_HYPERCALL: {
-		u64 gfn;
-		unsigned long addr;
-		u8 instructions[4];
+		u8 instructions[9];
+		int i = 0;
+		u64 addr;
 
 		/* if guest os id is not set hypercall should remain disabled */
 		if (!hv->hv_guest_os_id)
@@ -1150,16 +1151,33 @@ static int kvm_hv_set_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data,
 			hv->hv_hypercall = data;
 			break;
 		}
-		gfn = data >> HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT;
-		addr = gfn_to_hva(kvm, gfn);
-		if (kvm_is_error_hva(addr))
-			return 1;
-		kvm_x86_ops.patch_hypercall(vcpu, instructions);
-		((unsigned char *)instructions)[3] = 0xc3; /* ret */
-		if (__copy_to_user((void __user *)addr, instructions, 4))
+
+		/*
+		 * If Xen and Hyper-V hypercalls are both enabled, disambiguate
+		 * the same way Xen itself does, by setting the bit 31 of EAX
+		 * which is RsvdZ in the 32-bit Hyper-V hypercall ABI and just
+		 * going to be clobbered on 64-bit.
+		 */
+		if (kvm_xen_hypercall_enabled(kvm)) {
+			/* orl $0x80000000, %eax */
+			instructions[i++] = 0x0d;
+			instructions[i++] = 0x00;
+			instructions[i++] = 0x00;
+			instructions[i++] = 0x00;
+			instructions[i++] = 0x80;
+		}
+
+		/* vmcall/vmmcall */
+		kvm_x86_ops.patch_hypercall(vcpu, instructions + i);
+		i += 3;
+
+		/* ret */
+		((unsigned char *)instructions)[i++] = 0xc3;
+
+		addr = data & HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_MASK;
+		if (kvm_vcpu_write_guest(vcpu, addr, instructions, i))
 			return 1;
 		hv->hv_hypercall = data;
-		mark_page_dirty(kvm, gfn);
 		break;
 	}
 	case HV_X64_MSR_REFERENCE_TSC:
diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c
index b76d121a86c0..503935d8212e 100644
--- a/arch/x86/kvm/xen.c
+++ b/arch/x86/kvm/xen.c
@@ -8,6 +8,7 @@
 
 #include "x86.h"
 #include "xen.h"
+#include "hyperv.h"
 
 #include <linux/kvm_host.h>
 
@@ -99,6 +100,11 @@ int kvm_xen_hypercall(struct kvm_vcpu *vcpu)
 
 	input = (u64)kvm_register_read(vcpu, VCPU_REGS_RAX);
 
+	/* Hyper-V hypercalls get bit 31 set in EAX */
+	if ((input & 0x80000000) &&
+	    kvm_hv_hypercall_enabled(vcpu->kvm))
+		return kvm_hv_hypercall(vcpu);
+
 	longmode = is_64_bit_mode(vcpu);
 	if (!longmode) {
 		params[0] = (u32)kvm_rbx_read(vcpu);
diff --git a/tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c b/tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c
index 3f1dd93626e5..24f279e1a66b 100644
--- a/tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c
+++ b/tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c
@@ -15,6 +15,7 @@
 
 #define HCALL_REGION_GPA	0xc0000000ULL
 #define HCALL_REGION_SLOT	10
+#define PAGE_SIZE		4096
 
 static struct kvm_vm *vm;
 
@@ -22,7 +23,12 @@ static struct kvm_vm *vm;
 #define ARGVALUE(x) (0xdeadbeef5a5a0000UL + x)
 #define RETVALUE 0xcafef00dfbfbffffUL
 
-#define XEN_HYPERCALL_MSR 0x40000000
+#define XEN_HYPERCALL_MSR	0x40000200
+#define HV_GUEST_OS_ID_MSR	0x40000000
+#define HV_HYPERCALL_MSR	0x40000001
+
+#define HVCALL_SIGNAL_EVENT		0x005d
+#define HV_STATUS_INVALID_ALIGNMENT	4
 
 static void guest_code(void)
 {
@@ -30,6 +36,7 @@ static void guest_code(void)
 	unsigned long rdi = ARGVALUE(1);
 	unsigned long rsi = ARGVALUE(2);
 	unsigned long rdx = ARGVALUE(3);
+	unsigned long rcx;
 	register unsigned long r10 __asm__("r10") = ARGVALUE(4);
 	register unsigned long r8 __asm__("r8") = ARGVALUE(5);
 	register unsigned long r9 __asm__("r9") = ARGVALUE(6);
@@ -41,18 +48,38 @@ static void guest_code(void)
 			     "r"(r10), "r"(r8), "r"(r9));
 	GUEST_ASSERT(rax == RETVALUE);
 
-	/* Now fill in the hypercall page */
+	/* Fill in the Xen hypercall page */
 	__asm__ __volatile__("wrmsr" : : "c" (XEN_HYPERCALL_MSR),
 			     "a" (HCALL_REGION_GPA & 0xffffffff),
 			     "d" (HCALL_REGION_GPA >> 32));
 
-	/* And invoke the same hypercall that way */
+	/* Set Hyper-V Guest OS ID */
+	__asm__ __volatile__("wrmsr" : : "c" (HV_GUEST_OS_ID_MSR),
+			     "a" (0x5a), "d" (0));
+
+	/* Hyper-V hypercall page */
+	u64 msrval = HCALL_REGION_GPA + PAGE_SIZE + 1;
+	__asm__ __volatile__("wrmsr" : : "c" (HV_HYPERCALL_MSR),
+			     "a" (msrval & 0xffffffff),
+			     "d" (msrval >> 32));
+
+	/* Invoke a Xen hypercall */
 	__asm__ __volatile__("call *%1" : "=a"(rax) :
 			     "r"(HCALL_REGION_GPA + INPUTVALUE * 32),
 			     "a"(rax), "D"(rdi), "S"(rsi), "d"(rdx),
 			     "r"(r10), "r"(r8), "r"(r9));
 	GUEST_ASSERT(rax == RETVALUE);
 
+	/* Invoke a Hyper-V hypercall */
+	rax = 0;
+	rcx = HVCALL_SIGNAL_EVENT;	/* code */
+	rdx = 0x5a5a5a5a;		/* ingpa (badly aligned) */
+	__asm__ __volatile__("call *%1" : "=a"(rax) :
+			     "r"(HCALL_REGION_GPA + PAGE_SIZE),
+			     "a"(rax), "c"(rcx), "d"(rdx),
+			     "r"(r8));
+	GUEST_ASSERT(rax == HV_STATUS_INVALID_ALIGNMENT);
+
 	GUEST_DONE();
 }
 
@@ -73,11 +100,11 @@ int main(int argc, char *argv[])
 	};
 	vm_ioctl(vm, KVM_XEN_HVM_CONFIG, &hvmc);
 
-	/* Map a region for the hypercall page */
+	/* Map a region for the hypercall pages */
 	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
                                     HCALL_REGION_GPA, HCALL_REGION_SLOT,
-				    getpagesize(), 0);
-	virt_map(vm, HCALL_REGION_GPA, HCALL_REGION_GPA, 1, 0);
+				    2 * getpagesize(), 0);
+	virt_map(vm, HCALL_REGION_GPA, HCALL_REGION_GPA, 2, 0);
 
 	for (;;) {
 		volatile struct kvm_run *run = vcpu_state(vm, VCPU_ID);
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 05/15] KVM: x86/xen: add KVM_XEN_HVM_SET_ATTR/KVM_XEN_HVM_GET_ATTR
  2020-12-04  1:18 [PATCH 00/15] KVM: Add Xen hypercall and shared info pages David Woodhouse
                   ` (3 preceding siblings ...)
  2020-12-04  1:18 ` [PATCH 04/15] KVM: x86/xen: Fix coexistence of Xen and Hyper-V hypercalls David Woodhouse
@ 2020-12-04  1:18 ` David Woodhouse
  2020-12-04  1:18 ` [PATCH 06/15] KVM: x86/xen: latch long_mode when hypercall page is set up David Woodhouse
                   ` (11 subsequent siblings)
  16 siblings, 0 replies; 33+ messages in thread
From: David Woodhouse @ 2020-12-04  1:18 UTC (permalink / raw)
  To: kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson

From: Joao Martins <joao.m.martins@oracle.com>

This will be used to set up shared info pages etc.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
 arch/x86/kvm/x86.c       | 20 ++++++++++++++++++++
 arch/x86/kvm/xen.c       | 24 ++++++++++++++++++++++++
 arch/x86/kvm/xen.h       |  3 +++
 include/linux/kvm_host.h | 30 +++++++++++++++---------------
 include/uapi/linux/kvm.h | 11 +++++++++++
 5 files changed, 73 insertions(+), 15 deletions(-)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 1a7f016afb21..1cc4fe5ff52d 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -5594,6 +5594,26 @@ long kvm_arch_vm_ioctl(struct file *filp,
 		r = 0;
 		break;
 	}
+	case KVM_XEN_HVM_GET_ATTR: {
+		struct kvm_xen_hvm_attr xha;
+
+		r = -EFAULT;
+		if (copy_from_user(&xha, argp, sizeof(xha)))
+			goto out;
+		r = kvm_xen_hvm_get_attr(kvm, &xha);
+		if (copy_to_user(argp, &xha, sizeof(xha)))
+			goto out;
+		break;
+	}
+	case KVM_XEN_HVM_SET_ATTR: {
+		struct kvm_xen_hvm_attr xha;
+
+		r = -EFAULT;
+		if (copy_from_user(&xha, argp, sizeof(xha)))
+			goto out;
+		r = kvm_xen_hvm_set_attr(kvm, &xha);
+		break;
+	}
 	case KVM_SET_CLOCK: {
 		struct kvm_clock_data user_ns;
 		u64 now_ns;
diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c
index 503935d8212e..c0b2c67e0235 100644
--- a/arch/x86/kvm/xen.c
+++ b/arch/x86/kvm/xen.c
@@ -16,6 +16,30 @@
 
 #include "trace.h"
 
+int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
+{
+	int r = -ENOENT;
+
+	switch (data->type) {
+	default:
+		break;
+	}
+
+	return r;
+}
+
+int kvm_xen_hvm_get_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
+{
+	int r = -ENOENT;
+
+	switch (data->type) {
+	default:
+		break;
+	}
+
+	return r;
+}
+
 int kvm_xen_hvm_config(struct kvm_vcpu *vcpu, u64 data)
 {
 	struct kvm *kvm = vcpu->kvm;
diff --git a/arch/x86/kvm/xen.h b/arch/x86/kvm/xen.h
index 81e12f716d2e..afc6dad41fb5 100644
--- a/arch/x86/kvm/xen.h
+++ b/arch/x86/kvm/xen.h
@@ -9,8 +9,11 @@
 #ifndef __ARCH_X86_KVM_XEN_H__
 #define __ARCH_X86_KVM_XEN_H__
 
+int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data);
+int kvm_xen_hvm_get_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data);
 int kvm_xen_hypercall(struct kvm_vcpu *vcpu);
 int kvm_xen_hvm_config(struct kvm_vcpu *vcpu, u64 data);
+void kvm_xen_destroy_vm(struct kvm *kvm);
 
 static inline bool kvm_xen_hypercall_enabled(struct kvm *kvm)
 {
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 8eb5eb1399f5..846a010f5d5f 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -33,6 +33,21 @@
 
 #include <linux/kvm_types.h>
 
+struct kvm_host_map {
+	/*
+	 * Only valid if the 'pfn' is managed by the host kernel (i.e. There is
+	 * a 'struct page' for it. When using mem= kernel parameter some memory
+	 * can be used as guest memory but they are not managed by host
+	 * kernel).
+	 * If 'pfn' is not managed by the host kernel, this field is
+	 * initialized to KVM_UNMAPPED_PAGE.
+	 */
+	struct page *page;
+	void *hva;
+	kvm_pfn_t pfn;
+	kvm_pfn_t gfn;
+};
+
 #include <asm/kvm_host.h>
 
 #ifndef KVM_MAX_VCPU_ID
@@ -225,21 +240,6 @@ enum {
 
 #define KVM_UNMAPPED_PAGE	((void *) 0x500 + POISON_POINTER_DELTA)
 
-struct kvm_host_map {
-	/*
-	 * Only valid if the 'pfn' is managed by the host kernel (i.e. There is
-	 * a 'struct page' for it. When using mem= kernel parameter some memory
-	 * can be used as guest memory but they are not managed by host
-	 * kernel).
-	 * If 'pfn' is not managed by the host kernel, this field is
-	 * initialized to KVM_UNMAPPED_PAGE.
-	 */
-	struct page *page;
-	void *hva;
-	kvm_pfn_t pfn;
-	kvm_pfn_t gfn;
-};
-
 /*
  * Used to check if the mapping is valid or not. Never use 'kvm_host_map'
  * directly to check for that.
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 00221fe56994..f652b5deedde 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1576,6 +1576,17 @@ struct kvm_pv_cmd {
 /* Available with KVM_CAP_X86_MSR_FILTER */
 #define KVM_X86_SET_MSR_FILTER	_IOW(KVMIO,  0xc6, struct kvm_msr_filter)
 
+#define KVM_XEN_HVM_GET_ATTR	_IOWR(KVMIO, 0xc7, struct kvm_xen_hvm_attr)
+#define KVM_XEN_HVM_SET_ATTR	_IOW(KVMIO,  0xc8, struct kvm_xen_hvm_attr)
+
+struct kvm_xen_hvm_attr {
+	__u16 type;
+
+	union {
+		__u64 pad[4];
+	} u;
+};
+
 /* Secure Encrypted Virtualization command */
 enum sev_cmd_id {
 	/* Guest initialization commands */
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 06/15] KVM: x86/xen: latch long_mode when hypercall page is set up
  2020-12-04  1:18 [PATCH 00/15] KVM: Add Xen hypercall and shared info pages David Woodhouse
                   ` (4 preceding siblings ...)
  2020-12-04  1:18 ` [PATCH 05/15] KVM: x86/xen: add KVM_XEN_HVM_SET_ATTR/KVM_XEN_HVM_GET_ATTR David Woodhouse
@ 2020-12-04  1:18 ` David Woodhouse
  2020-12-04 18:38   ` Alexander Graf
  2020-12-04  1:18 ` [PATCH 07/15] KVM: x86/xen: add definitions of compat_shared_info, compat_vcpu_info David Woodhouse
                   ` (10 subsequent siblings)
  16 siblings, 1 reply; 33+ messages in thread
From: David Woodhouse @ 2020-12-04  1:18 UTC (permalink / raw)
  To: kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson

From: David Woodhouse <dwmw@amazon.co.uk>

Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
 arch/x86/include/asm/kvm_host.h |  6 ++++++
 arch/x86/kvm/xen.c              | 16 +++++++++++++++-
 include/uapi/linux/kvm.h        |  3 +++
 3 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 9de3229e91e1..c9a4feaee2e7 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -890,6 +890,11 @@ struct msr_bitmap_range {
 	unsigned long *bitmap;
 };
 
+/* Xen emulation context */
+struct kvm_xen {
+	bool long_mode;
+};
+
 enum kvm_irqchip_mode {
 	KVM_IRQCHIP_NONE,
 	KVM_IRQCHIP_KERNEL,       /* created with KVM_CREATE_IRQCHIP */
@@ -969,6 +974,7 @@ struct kvm_arch {
 	struct hlist_head mask_notifier_list;
 
 	struct kvm_hv hyperv;
+	struct kvm_xen xen;
 
 	#ifdef CONFIG_KVM_MMU_AUDIT
 	int audit_point;
diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c
index c0b2c67e0235..52cb9e465542 100644
--- a/arch/x86/kvm/xen.c
+++ b/arch/x86/kvm/xen.c
@@ -21,6 +21,13 @@ int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
 	int r = -ENOENT;
 
 	switch (data->type) {
+	case KVM_XEN_ATTR_TYPE_LONG_MODE:
+		if (!IS_ENABLED(CONFIG_64BIT) && data->u.long_mode)
+			return -EINVAL;
+
+		kvm->arch.xen.long_mode = !!data->u.long_mode;
+		r = 0;
+		break;
 	default:
 		break;
 	}
@@ -33,6 +40,10 @@ int kvm_xen_hvm_get_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
 	int r = -ENOENT;
 
 	switch (data->type) {
+	case KVM_XEN_ATTR_TYPE_LONG_MODE:
+		data->u.long_mode = kvm->arch.xen.long_mode;
+		r = 0;
+		break;
 	default:
 		break;
 	}
@@ -45,6 +56,10 @@ int kvm_xen_hvm_config(struct kvm_vcpu *vcpu, u64 data)
 	struct kvm *kvm = vcpu->kvm;
 	u32 page_num = data & ~PAGE_MASK;
 	u64 page_addr = data & PAGE_MASK;
+	bool lm = is_long_mode(vcpu);
+
+	/* Latch long_mode for shared_info pages etc. */
+	vcpu->kvm->arch.xen.long_mode = lm;
 
 	/*
 	 * If Xen hypercall intercept is enabled, fill the hypercall
@@ -79,7 +94,6 @@ int kvm_xen_hvm_config(struct kvm_vcpu *vcpu, u64 data)
 				return 1;
 		}
 	} else {
-		int lm = is_long_mode(vcpu);
 		u8 *blob_addr = lm ? (u8 *)(long)kvm->arch.xen_hvm_config.blob_addr_64
 				   : (u8 *)(long)kvm->arch.xen_hvm_config.blob_addr_32;
 		u8 blob_size = lm ? kvm->arch.xen_hvm_config.blob_size_64
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index f652b5deedde..e297c910f3e4 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1583,10 +1583,13 @@ struct kvm_xen_hvm_attr {
 	__u16 type;
 
 	union {
+		__u8 long_mode;
 		__u64 pad[4];
 	} u;
 };
 
+#define KVM_XEN_ATTR_TYPE_LONG_MODE		0x0
+
 /* Secure Encrypted Virtualization command */
 enum sev_cmd_id {
 	/* Guest initialization commands */
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 07/15] KVM: x86/xen: add definitions of compat_shared_info, compat_vcpu_info
  2020-12-04  1:18 [PATCH 00/15] KVM: Add Xen hypercall and shared info pages David Woodhouse
                   ` (5 preceding siblings ...)
  2020-12-04  1:18 ` [PATCH 06/15] KVM: x86/xen: latch long_mode when hypercall page is set up David Woodhouse
@ 2020-12-04  1:18 ` David Woodhouse
  2020-12-05 18:43   ` Joao Martins
  2020-12-04  1:18 ` [PATCH 08/15] KVM: x86/xen: register shared_info page David Woodhouse
                   ` (9 subsequent siblings)
  16 siblings, 1 reply; 33+ messages in thread
From: David Woodhouse @ 2020-12-04  1:18 UTC (permalink / raw)
  To: kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson

From: David Woodhouse <dwmw@amazon.co.uk>

There aren't a lot of differences for the things that the kernel needs
to care about, but there are a few.

Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
 arch/x86/kvm/xen.h | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/arch/x86/kvm/xen.h b/arch/x86/kvm/xen.h
index afc6dad41fb5..870ac7197a3a 100644
--- a/arch/x86/kvm/xen.h
+++ b/arch/x86/kvm/xen.h
@@ -21,4 +21,43 @@ static inline bool kvm_xen_hypercall_enabled(struct kvm *kvm)
 		KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL;
 }
 
+
+/* 32-bit compatibility definitions */
+#include <asm/pvclock-abi.h>
+#include <asm/xen/interface.h>
+
+struct compat_arch_vcpu_info {
+	unsigned int cr2;
+	unsigned int pad[5];
+};
+
+struct compat_vcpu_info {
+        uint8_t evtchn_upcall_pending;
+        uint8_t evtchn_upcall_mask;
+        uint32_t evtchn_pending_sel;
+        struct compat_arch_vcpu_info arch;
+        struct pvclock_vcpu_time_info time;
+}; /* 64 bytes (x86) */
+
+struct compat_arch_shared_info {
+	unsigned int max_pfn;
+	unsigned int pfn_to_mfn_frame_list_list;
+	unsigned int nmi_reason;
+	unsigned int p2m_cr3;
+	unsigned int p2m_vaddr;
+	unsigned int p2m_generation;
+	uint32_t wc_sec_hi;
+};
+
+struct compat_shared_info {
+	struct compat_vcpu_info vcpu_info[MAX_VIRT_CPUS];
+	uint32_t evtchn_pending[sizeof(compat_ulong_t) * 8];
+	uint32_t evtchn_mask[sizeof(compat_ulong_t) * 8];
+	uint32_t wc_version;
+	uint32_t wc_sec;
+	uint32_t wc_nsec;
+	struct compat_arch_shared_info arch;
+
+};
+
 #endif /* __ARCH_X86_KVM_XEN_H__ */
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 08/15] KVM: x86/xen: register shared_info page
  2020-12-04  1:18 [PATCH 00/15] KVM: Add Xen hypercall and shared info pages David Woodhouse
                   ` (6 preceding siblings ...)
  2020-12-04  1:18 ` [PATCH 07/15] KVM: x86/xen: add definitions of compat_shared_info, compat_vcpu_info David Woodhouse
@ 2020-12-04  1:18 ` David Woodhouse
  2020-12-04  1:18 ` [PATCH 09/15] KVM: x86/xen: setup pvclock updates David Woodhouse
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 33+ messages in thread
From: David Woodhouse @ 2020-12-04  1:18 UTC (permalink / raw)
  To: kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson

From: Joao Martins <joao.m.martins@oracle.com>

We add a new ioctl, XEN_HVM_SHARED_INFO, to allow hypervisor
to know where the guest's shared info page is.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
 arch/x86/include/asm/kvm_host.h |  2 +
 arch/x86/kvm/x86.c              |  1 +
 arch/x86/kvm/xen.c              | 69 +++++++++++++++++++++++++++++++++
 include/uapi/linux/kvm.h        |  4 ++
 4 files changed, 76 insertions(+)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index c9a4feaee2e7..b6eff9814c6a 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -893,6 +893,8 @@ struct msr_bitmap_range {
 /* Xen emulation context */
 struct kvm_xen {
 	bool long_mode;
+	struct kvm_host_map shinfo_map;
+	void *shinfo;
 };
 
 enum kvm_irqchip_mode {
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 1cc4fe5ff52d..156ce72ba9bf 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -10445,6 +10445,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
 	kvm_mmu_uninit_vm(kvm);
 	kvm_page_track_cleanup(kvm);
 	kvm_hv_destroy_vm(kvm);
+	kvm_xen_destroy_vm(kvm);
 }
 
 void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot)
diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c
index 52cb9e465542..c156ed1ef972 100644
--- a/arch/x86/kvm/xen.c
+++ b/arch/x86/kvm/xen.c
@@ -13,9 +13,51 @@
 #include <linux/kvm_host.h>
 
 #include <trace/events/kvm.h>
+#include <xen/interface/xen.h>
 
 #include "trace.h"
 
+static int kvm_xen_map_guest_page(struct kvm *kvm, struct kvm_host_map *map,
+				  void **hva, gpa_t gpa, size_t len)
+{
+	gfn_t gfn = gpa_to_gfn(gpa);
+	struct kvm_host_map new_map;
+	bool unmap = !!*hva;
+	int ret;
+
+	if (offset_in_page(gpa) + len > PAGE_SIZE)
+		return -EINVAL;
+
+	ret = kvm_map_gfn(kvm, gfn, &new_map, NULL, false);
+	if (ret)
+		return ret;
+
+	WRITE_ONCE(*hva, new_map.hva + offset_in_page(gpa));
+
+	if (unmap) {
+	        synchronize_srcu(&kvm->srcu);
+
+		kvm_unmap_gfn(kvm, map, NULL, true, false);
+	}
+
+	*map = new_map;
+	return 0;
+}
+
+static int kvm_xen_shared_info_init(struct kvm *kvm, gfn_t gfn)
+{
+	gpa_t gpa = gfn_to_gpa(gfn);
+	int ret;
+
+	ret = kvm_xen_map_guest_page(kvm, &kvm->arch.xen.shinfo_map,
+				     (void **)&kvm->arch.xen.shinfo, gpa,
+				     PAGE_SIZE);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
 int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
 {
 	int r = -ENOENT;
@@ -28,6 +70,14 @@ int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
 		kvm->arch.xen.long_mode = !!data->u.long_mode;
 		r = 0;
 		break;
+
+	case KVM_XEN_ATTR_TYPE_SHARED_INFO: {
+		gfn_t gfn = data->u.shared_info.gfn;
+
+		r = kvm_xen_shared_info_init(kvm, gfn);
+		break;
+	}
+
 	default:
 		break;
 	}
@@ -44,6 +94,15 @@ int kvm_xen_hvm_get_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
 		data->u.long_mode = kvm->arch.xen.long_mode;
 		r = 0;
 		break;
+
+	case KVM_XEN_ATTR_TYPE_SHARED_INFO: {
+		if (kvm->arch.xen.shinfo) {
+			data->u.shared_info.gfn = kvm->arch.xen.shinfo_map.gfn;
+			r = 0;
+		}
+		break;
+	}
+
 	default:
 		break;
 	}
@@ -182,3 +241,13 @@ int kvm_xen_hypercall(struct kvm_vcpu *vcpu)
 
 	return 0;
 }
+
+void kvm_xen_destroy_vm(struct kvm *kvm)
+{
+	struct kvm_xen *xen = &kvm->arch.xen;
+
+	if (xen->shinfo) {
+		kvm_unmap_gfn(kvm, &xen->shinfo_map, NULL, true, false);
+		xen->shinfo = NULL;
+	}
+}
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index e297c910f3e4..3bcd04e4e38f 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1584,11 +1584,15 @@ struct kvm_xen_hvm_attr {
 
 	union {
 		__u8 long_mode;
+		struct {
+			__u64 gfn;
+		} shared_info;
 		__u64 pad[4];
 	} u;
 };
 
 #define KVM_XEN_ATTR_TYPE_LONG_MODE		0x0
+#define KVM_XEN_ATTR_TYPE_SHARED_INFO		0x1
 
 /* Secure Encrypted Virtualization command */
 enum sev_cmd_id {
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 09/15] KVM: x86/xen: setup pvclock updates
  2020-12-04  1:18 [PATCH 00/15] KVM: Add Xen hypercall and shared info pages David Woodhouse
                   ` (7 preceding siblings ...)
  2020-12-04  1:18 ` [PATCH 08/15] KVM: x86/xen: register shared_info page David Woodhouse
@ 2020-12-04  1:18 ` David Woodhouse
  2020-12-04  1:18 ` [PATCH 10/15] xen: add wc_sec_hi to struct shared_info David Woodhouse
                   ` (7 subsequent siblings)
  16 siblings, 0 replies; 33+ messages in thread
From: David Woodhouse @ 2020-12-04  1:18 UTC (permalink / raw)
  To: kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson

From: Joao Martins <joao.m.martins@oracle.com>

This means when we set shared_info page GPA, and request a master
clock update. This will trigger all vcpus to update their respective
shared pvclock data with guests. We follow a similar approach
as Hyper-V and KVM and adjust it accordingly.

Note however that Xen differs a little on how pvclock pages are set up.
Specifically KVM assumes 4KiB page alignment and pvclock data starts in
the beginning of the page. Whereas Xen you can place that information
anywhere in the page.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
 arch/x86/kvm/x86.c |  2 ++
 arch/x86/kvm/xen.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++
 arch/x86/kvm/xen.h |  1 +
 3 files changed, 53 insertions(+)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 156ce72ba9bf..daf4a1f26811 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2719,6 +2719,8 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
 
 	if (vcpu->pv_time_enabled)
 		kvm_setup_pvclock_page(v);
+	if (ka->xen.shinfo)
+		kvm_xen_setup_pvclock_page(v);
 	if (v == kvm_get_vcpu(v->kvm, 0))
 		kvm_hv_setup_tsc_page(v->kvm, &vcpu->hv_clock);
 	return 0;
diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c
index c156ed1ef972..c0fd54f1c121 100644
--- a/arch/x86/kvm/xen.c
+++ b/arch/x86/kvm/xen.c
@@ -55,9 +55,59 @@ static int kvm_xen_shared_info_init(struct kvm *kvm, gfn_t gfn)
 	if (ret)
 		return ret;
 
+	kvm_make_all_cpus_request(kvm, KVM_REQ_MASTERCLOCK_UPDATE);
+
 	return 0;
 }
 
+void kvm_xen_setup_pvclock_page(struct kvm_vcpu *v)
+{
+	struct kvm_vcpu_arch *vcpu = &v->arch;
+	struct pvclock_vcpu_time_info *guest_hv_clock;
+	unsigned int offset;
+
+	if (v->vcpu_id >= MAX_VIRT_CPUS)
+		return;
+
+	BUILD_BUG_ON(offsetof(struct pvclock_vcpu_time_info, version) != 0);
+	BUILD_BUG_ON(offsetof(struct shared_info, vcpu_info) != 0);
+	BUILD_BUG_ON(offsetof(struct compat_shared_info, vcpu_info) != 0);
+	BUILD_BUG_ON(sizeof(struct vcpu_info) != sizeof(struct compat_vcpu_info));
+	BUILD_BUG_ON(offsetof(struct vcpu_info, time) !=
+		     offsetof(struct compat_vcpu_info, time));
+
+	offset = v->vcpu_id * sizeof(struct vcpu_info);
+	offset += offsetof(struct vcpu_info, time);
+
+	guest_hv_clock = v->kvm->arch.xen.shinfo + offset;
+
+	if (guest_hv_clock->version & 1)
+		++guest_hv_clock->version;  /* first time write, random junk */
+
+	vcpu->hv_clock.version = guest_hv_clock->version + 1;
+	guest_hv_clock->version = vcpu->hv_clock.version;
+
+	smp_wmb();
+
+	/* retain PVCLOCK_GUEST_STOPPED if set in guest copy */
+	vcpu->hv_clock.flags |= (guest_hv_clock->flags & PVCLOCK_GUEST_STOPPED);
+
+	if (vcpu->pvclock_set_guest_stopped_request) {
+		vcpu->hv_clock.flags |= PVCLOCK_GUEST_STOPPED;
+		vcpu->pvclock_set_guest_stopped_request = false;
+	}
+
+	trace_kvm_pvclock_update(v->vcpu_id, &vcpu->hv_clock);
+
+	*guest_hv_clock = vcpu->hv_clock;
+
+	smp_wmb();
+
+	vcpu->hv_clock.version++;
+
+	guest_hv_clock->version = vcpu->hv_clock.version;
+}
+
 int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
 {
 	int r = -ENOENT;
diff --git a/arch/x86/kvm/xen.h b/arch/x86/kvm/xen.h
index 870ac7197a3a..0b6bfe4ee108 100644
--- a/arch/x86/kvm/xen.h
+++ b/arch/x86/kvm/xen.h
@@ -9,6 +9,7 @@
 #ifndef __ARCH_X86_KVM_XEN_H__
 #define __ARCH_X86_KVM_XEN_H__
 
+void kvm_xen_setup_pvclock_page(struct kvm_vcpu *vcpu);
 int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data);
 int kvm_xen_hvm_get_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data);
 int kvm_xen_hypercall(struct kvm_vcpu *vcpu);
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 10/15] xen: add wc_sec_hi to struct shared_info
  2020-12-04  1:18 [PATCH 00/15] KVM: Add Xen hypercall and shared info pages David Woodhouse
                   ` (8 preceding siblings ...)
  2020-12-04  1:18 ` [PATCH 09/15] KVM: x86/xen: setup pvclock updates David Woodhouse
@ 2020-12-04  1:18 ` David Woodhouse
  2020-12-04  1:18 ` [PATCH 11/15] KVM: x86/xen: update wallclock region David Woodhouse
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 33+ messages in thread
From: David Woodhouse @ 2020-12-04  1:18 UTC (permalink / raw)
  To: kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson

From: David Woodhouse <dwmw@amazon.co.uk>

Xen added this in 2015 (Xen 4.6). On x86_64 and arm it fills what was
previously a 32-bit hole in the generic shared_info structure; on
i386 it had to go at the end of struct arch_shared_info.

Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
 arch/x86/include/asm/xen/interface.h | 3 +++
 include/xen/interface/xen.h          | 4 +++-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/asm/xen/interface.h b/arch/x86/include/asm/xen/interface.h
index 9139b3e86316..baca0b00ef76 100644
--- a/arch/x86/include/asm/xen/interface.h
+++ b/arch/x86/include/asm/xen/interface.h
@@ -182,6 +182,9 @@ struct arch_shared_info {
 	unsigned long p2m_cr3;		/* cr3 value of the p2m address space */
 	unsigned long p2m_vaddr;	/* virtual address of the p2m list */
 	unsigned long p2m_generation;	/* generation count of p2m mapping */
+#ifdef CONFIG_X86_32
+	uint32_t wc_sec_hi;
+#endif
 };
 #endif	/* !__ASSEMBLY__ */
 
diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h
index 8bfb242f433e..5ee37a296481 100644
--- a/include/xen/interface/xen.h
+++ b/include/xen/interface/xen.h
@@ -598,7 +598,9 @@ struct shared_info {
 	 * their gettimeofday() syscall on this wallclock-base value.
 	 */
 	struct pvclock_wall_clock wc;
-
+#ifndef CONFIG_X86_32
+	uint32_t wc_sec_hi;
+#endif
 	struct arch_shared_info arch;
 
 };
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 11/15] KVM: x86/xen: update wallclock region
  2020-12-04  1:18 [PATCH 00/15] KVM: Add Xen hypercall and shared info pages David Woodhouse
                   ` (9 preceding siblings ...)
  2020-12-04  1:18 ` [PATCH 10/15] xen: add wc_sec_hi to struct shared_info David Woodhouse
@ 2020-12-04  1:18 ` David Woodhouse
  2020-12-04  1:18 ` [PATCH 12/15] KVM: x86/xen: register vcpu info David Woodhouse
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 33+ messages in thread
From: David Woodhouse @ 2020-12-04  1:18 UTC (permalink / raw)
  To: kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson

From: Joao Martins <joao.m.martins@oracle.com>

Wallclock on Xen is written in the shared_info page.

To that purpose, export kvm_write_wall_clock() and pass on the GPA of
its location to populate the shared_info wall clock data.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
 arch/x86/kvm/x86.c | 17 ++++++++++++-----
 arch/x86/kvm/x86.h |  1 +
 arch/x86/kvm/xen.c | 21 ++++++++++++++++++++-
 arch/x86/kvm/xen.h |  4 +---
 4 files changed, 34 insertions(+), 9 deletions(-)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index daf4a1f26811..34f06394de7e 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1921,15 +1921,14 @@ static s64 get_kvmclock_base_ns(void)
 }
 #endif
 
-static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock)
+void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock, int sec_hi_ofs)
 {
 	int version;
 	int r;
 	struct pvclock_wall_clock wc;
+	u32 wc_sec_hi;
 	u64 wall_nsec;
 
-	kvm->arch.wall_clock = wall_clock;
-
 	if (!wall_clock)
 		return;
 
@@ -1958,6 +1957,12 @@ static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock)
 
 	kvm_write_guest(kvm, wall_clock, &wc, sizeof(wc));
 
+	if (sec_hi_ofs) {
+		wc_sec_hi = wall_nsec >> 32;
+		kvm_write_guest(kvm, wall_clock + sec_hi_ofs,
+				&wc_sec_hi, sizeof(wc_sec_hi));
+	}
+
 	version++;
 	kvm_write_guest(kvm, wall_clock, &version, sizeof(version));
 }
@@ -3117,13 +3122,15 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 		if (!guest_pv_has(vcpu, KVM_FEATURE_CLOCKSOURCE2))
 			return 1;
 
-		kvm_write_wall_clock(vcpu->kvm, data);
+		vcpu->kvm->arch.wall_clock = data;
+		kvm_write_wall_clock(vcpu->kvm, data, 0);
 		break;
 	case MSR_KVM_WALL_CLOCK:
 		if (!guest_pv_has(vcpu, KVM_FEATURE_CLOCKSOURCE))
 			return 1;
 
-		kvm_write_wall_clock(vcpu->kvm, data);
+		vcpu->kvm->arch.wall_clock = data;
+		kvm_write_wall_clock(vcpu->kvm, data, 0);
 		break;
 	case MSR_KVM_SYSTEM_TIME_NEW:
 		if (!guest_pv_has(vcpu, KVM_FEATURE_CLOCKSOURCE2))
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
index e7ca622a468f..cf8778410015 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -246,6 +246,7 @@ static inline bool kvm_vcpu_latch_init(struct kvm_vcpu *vcpu)
 	return is_smm(vcpu) || kvm_x86_ops.apic_init_signal_blocked(vcpu);
 }
 
+void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock, int sec_hi_ofs);
 void kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq, int inc_eip);
 
 void kvm_write_tsc(struct kvm_vcpu *vcpu, struct msr_data *msr);
diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c
index c0fd54f1c121..2e4e98297364 100644
--- a/arch/x86/kvm/xen.c
+++ b/arch/x86/kvm/xen.c
@@ -47,6 +47,7 @@ static int kvm_xen_map_guest_page(struct kvm *kvm, struct kvm_host_map *map,
 static int kvm_xen_shared_info_init(struct kvm *kvm, gfn_t gfn)
 {
 	gpa_t gpa = gfn_to_gpa(gfn);
+	int wc_ofs, sec_hi_ofs;
 	int ret;
 
 	ret = kvm_xen_map_guest_page(kvm, &kvm->arch.xen.shinfo_map,
@@ -55,6 +56,25 @@ static int kvm_xen_shared_info_init(struct kvm *kvm, gfn_t gfn)
 	if (ret)
 		return ret;
 
+	BUILD_BUG_ON(offsetof(struct compat_shared_info, wc) != 0x900);
+	BUILD_BUG_ON(offsetof(struct compat_shared_info, arch.wc_sec_hi) != 0x924);
+	BUILD_BUG_ON(offsetof(struct pvclock_vcpu_time_info, version) != 0);
+
+	/* 32-bit location by default */
+	wc_ofs = offsetof(struct compat_shared_info, wc);
+	sec_hi_ofs = offsetof(struct compat_shared_info, arch.wc_sec_hi);
+
+#ifdef CONFIG_64BIT
+	BUILD_BUG_ON(offsetof(struct shared_info, wc) != 0xc00);
+	BUILD_BUG_ON(offsetof(struct shared_info, wc_sec_hi) != 0xc0c);
+
+	if (kvm->arch.xen.long_mode) {
+		wc_ofs = offsetof(struct shared_info, wc);
+		sec_hi_ofs = offsetof(struct shared_info, wc_sec_hi);
+	}
+#endif
+
+	kvm_write_wall_clock(kvm, gpa + wc_ofs, sec_hi_ofs - wc_ofs);
 	kvm_make_all_cpus_request(kvm, KVM_REQ_MASTERCLOCK_UPDATE);
 
 	return 0;
@@ -69,7 +89,6 @@ void kvm_xen_setup_pvclock_page(struct kvm_vcpu *v)
 	if (v->vcpu_id >= MAX_VIRT_CPUS)
 		return;
 
-	BUILD_BUG_ON(offsetof(struct pvclock_vcpu_time_info, version) != 0);
 	BUILD_BUG_ON(offsetof(struct shared_info, vcpu_info) != 0);
 	BUILD_BUG_ON(offsetof(struct compat_shared_info, vcpu_info) != 0);
 	BUILD_BUG_ON(sizeof(struct vcpu_info) != sizeof(struct compat_vcpu_info));
diff --git a/arch/x86/kvm/xen.h b/arch/x86/kvm/xen.h
index 0b6bfe4ee108..4f73866b3d33 100644
--- a/arch/x86/kvm/xen.h
+++ b/arch/x86/kvm/xen.h
@@ -54,9 +54,7 @@ struct compat_shared_info {
 	struct compat_vcpu_info vcpu_info[MAX_VIRT_CPUS];
 	uint32_t evtchn_pending[sizeof(compat_ulong_t) * 8];
 	uint32_t evtchn_mask[sizeof(compat_ulong_t) * 8];
-	uint32_t wc_version;
-	uint32_t wc_sec;
-	uint32_t wc_nsec;
+	struct pvclock_wall_clock wc;
 	struct compat_arch_shared_info arch;
 
 };
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 12/15] KVM: x86/xen: register vcpu info
  2020-12-04  1:18 [PATCH 00/15] KVM: Add Xen hypercall and shared info pages David Woodhouse
                   ` (10 preceding siblings ...)
  2020-12-04  1:18 ` [PATCH 11/15] KVM: x86/xen: update wallclock region David Woodhouse
@ 2020-12-04  1:18 ` David Woodhouse
  2020-12-04  1:18 ` [PATCH 13/15] KVM: x86/xen: register vcpu time info region David Woodhouse
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 33+ messages in thread
From: David Woodhouse @ 2020-12-04  1:18 UTC (permalink / raw)
  To: kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson

From: Joao Martins <joao.m.martins@oracle.com>

The vcpu info supersedes the per vcpu area of the shared info page and
the guest vcpus will use this instead.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
Signed-off-by: Ankur Arora <ankur.a.arora@oracle.com>
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
 arch/x86/include/asm/kvm_host.h |  2 +
 arch/x86/kvm/x86.c              |  1 +
 arch/x86/kvm/xen.c              | 94 +++++++++++++++++++++++++++++++--
 arch/x86/kvm/xen.h              | 14 +++++
 include/uapi/linux/kvm.h        |  5 ++
 5 files changed, 113 insertions(+), 3 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index b6eff9814c6a..617c120d03a3 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -523,6 +523,8 @@ struct kvm_vcpu_hv {
 /* Xen HVM per vcpu emulation context */
 struct kvm_vcpu_xen {
 	u64 hypercall_rip;
+	struct kvm_host_map vcpu_info_map;
+	struct vcpu_info *vcpu_info;
 };
 
 struct kvm_vcpu_arch {
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 34f06394de7e..0a15748e3aa8 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -10003,6 +10003,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
 	kmem_cache_free(x86_fpu_cache, vcpu->arch.guest_fpu);
 
 	kvm_hv_vcpu_uninit(vcpu);
+	kvm_xen_vcpu_uninit(vcpu);
 	kvm_pmu_destroy(vcpu);
 	kfree(vcpu->arch.mce_banks);
 	kvm_free_lapic(vcpu);
diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c
index 2e4e98297364..f9ae2cfae0d2 100644
--- a/arch/x86/kvm/xen.c
+++ b/arch/x86/kvm/xen.c
@@ -80,13 +80,33 @@ static int kvm_xen_shared_info_init(struct kvm *kvm, gfn_t gfn)
 	return 0;
 }
 
+static void *xen_vcpu_info(struct kvm_vcpu *v)
+{
+	struct kvm_vcpu_xen *vcpu_xen = vcpu_to_xen_vcpu(v);
+	struct kvm_xen *kvm = &v->kvm->arch.xen;
+	unsigned int offset = 0;
+	void *hva = NULL;
+
+	if (vcpu_xen->vcpu_info)
+		return vcpu_xen->vcpu_info;
+
+	if (kvm->shinfo && v->vcpu_id < MAX_VIRT_CPUS) {
+		hva = kvm->shinfo;
+		offset += offsetof(struct shared_info, vcpu_info);
+		offset += v->vcpu_id * sizeof(struct vcpu_info);
+	}
+
+	return hva + offset;
+}
+
 void kvm_xen_setup_pvclock_page(struct kvm_vcpu *v)
 {
 	struct kvm_vcpu_arch *vcpu = &v->arch;
 	struct pvclock_vcpu_time_info *guest_hv_clock;
+	void *hva = xen_vcpu_info(v);
 	unsigned int offset;
 
-	if (v->vcpu_id >= MAX_VIRT_CPUS)
+	if (!hva)
 		return;
 
 	BUILD_BUG_ON(offsetof(struct shared_info, vcpu_info) != 0);
@@ -98,10 +118,10 @@ void kvm_xen_setup_pvclock_page(struct kvm_vcpu *v)
 	offset = v->vcpu_id * sizeof(struct vcpu_info);
 	offset += offsetof(struct vcpu_info, time);
 
-	guest_hv_clock = v->kvm->arch.xen.shinfo + offset;
+	guest_hv_clock = hva + offset;
 
 	if (guest_hv_clock->version & 1)
-		++guest_hv_clock->version;  /* first time write, random junk */
+		++guest_hv_clock->version;
 
 	vcpu->hv_clock.version = guest_hv_clock->version + 1;
 	guest_hv_clock->version = vcpu->hv_clock.version;
@@ -127,6 +147,20 @@ void kvm_xen_setup_pvclock_page(struct kvm_vcpu *v)
 	guest_hv_clock->version = vcpu->hv_clock.version;
 }
 
+static int vcpu_attr_loc(struct kvm_vcpu *vcpu, u16 type,
+			 struct kvm_host_map **map, void ***hva, size_t *sz)
+{
+	switch(type) {
+	case KVM_XEN_ATTR_TYPE_VCPU_INFO:
+		*map = &vcpu->arch.xen.vcpu_info_map;
+		*hva = (void **)&vcpu->arch.xen.vcpu_info;
+		if (sz)
+			*sz = sizeof(struct vcpu_info);
+		return 0;
+	}
+	return -EINVAL;
+}
+
 int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
 {
 	int r = -ENOENT;
@@ -147,6 +181,28 @@ int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
 		break;
 	}
 
+	case KVM_XEN_ATTR_TYPE_VCPU_INFO: {
+		gpa_t gpa = data->u.vcpu_attr.gpa;
+		struct kvm_host_map *map;
+		struct kvm_vcpu *v;
+		size_t sz;
+		void **hva;
+
+		v = kvm_get_vcpu(kvm, data->u.vcpu_attr.vcpu);
+		if (!v)
+			return -EINVAL;
+
+		r = vcpu_attr_loc(v, data->type, &map, &hva, &sz);
+		if (r)
+			return r;
+
+		r = kvm_xen_map_guest_page(kvm, map, hva, gpa, sz);
+		if (!r)
+			kvm_xen_setup_pvclock_page(v);
+
+		break;
+	}
+
 	default:
 		break;
 	}
@@ -172,6 +228,27 @@ int kvm_xen_hvm_get_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
 		break;
 	}
 
+	case KVM_XEN_ATTR_TYPE_VCPU_INFO: {
+		struct kvm_host_map *map;
+		struct kvm_vcpu *v;
+		void **hva;
+
+		v = kvm_get_vcpu(kvm, data->u.vcpu_attr.vcpu);
+		if (!v)
+			return -EINVAL;
+
+		r = vcpu_attr_loc(v, data->type, &map, &hva, NULL);
+		if (r)
+			return r;
+
+		if (*hva) {
+			data->u.vcpu_attr.gpa = gfn_to_gpa(map->gfn) +
+				offset_in_page(*hva);
+			r = 0;
+		}
+		break;
+	}
+
 	default:
 		break;
 	}
@@ -311,6 +388,17 @@ int kvm_xen_hypercall(struct kvm_vcpu *vcpu)
 	return 0;
 }
 
+void kvm_xen_vcpu_uninit(struct kvm_vcpu *vcpu)
+{
+	struct kvm_vcpu_xen *vcpu_xen = vcpu_to_xen_vcpu(vcpu);
+
+	if (vcpu_xen->vcpu_info) {
+		kvm_unmap_gfn(vcpu->kvm, &vcpu_xen->vcpu_info_map,
+			      NULL, true, false);
+		vcpu_xen->vcpu_info = NULL;
+	}
+}
+
 void kvm_xen_destroy_vm(struct kvm *kvm)
 {
 	struct kvm_xen *xen = &kvm->arch.xen;
diff --git a/arch/x86/kvm/xen.h b/arch/x86/kvm/xen.h
index 4f73866b3d33..6d09b46d3c2e 100644
--- a/arch/x86/kvm/xen.h
+++ b/arch/x86/kvm/xen.h
@@ -9,12 +9,26 @@
 #ifndef __ARCH_X86_KVM_XEN_H__
 #define __ARCH_X86_KVM_XEN_H__
 
+static inline struct kvm_vcpu_xen *vcpu_to_xen_vcpu(struct kvm_vcpu *vcpu)
+{
+	return &vcpu->arch.xen;
+}
+
+static inline struct kvm_vcpu *xen_vcpu_to_vcpu(struct kvm_vcpu_xen *xen_vcpu)
+{
+	struct kvm_vcpu_arch *arch;
+
+	arch = container_of(xen_vcpu, struct kvm_vcpu_arch, xen);
+	return container_of(arch, struct kvm_vcpu, arch);
+}
+
 void kvm_xen_setup_pvclock_page(struct kvm_vcpu *vcpu);
 int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data);
 int kvm_xen_hvm_get_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data);
 int kvm_xen_hypercall(struct kvm_vcpu *vcpu);
 int kvm_xen_hvm_config(struct kvm_vcpu *vcpu, u64 data);
 void kvm_xen_destroy_vm(struct kvm *kvm);
+void kvm_xen_vcpu_uninit(struct kvm_vcpu *vcpu);
 
 static inline bool kvm_xen_hypercall_enabled(struct kvm *kvm)
 {
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 3bcd04e4e38f..35b0d3b80f67 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1587,12 +1587,17 @@ struct kvm_xen_hvm_attr {
 		struct {
 			__u64 gfn;
 		} shared_info;
+		struct {
+			__u32 vcpu;
+			__u64 gpa;
+		} vcpu_attr;
 		__u64 pad[4];
 	} u;
 };
 
 #define KVM_XEN_ATTR_TYPE_LONG_MODE		0x0
 #define KVM_XEN_ATTR_TYPE_SHARED_INFO		0x1
+#define KVM_XEN_ATTR_TYPE_VCPU_INFO		0x2
 
 /* Secure Encrypted Virtualization command */
 enum sev_cmd_id {
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 13/15] KVM: x86/xen: register vcpu time info region
  2020-12-04  1:18 [PATCH 00/15] KVM: Add Xen hypercall and shared info pages David Woodhouse
                   ` (11 preceding siblings ...)
  2020-12-04  1:18 ` [PATCH 12/15] KVM: x86/xen: register vcpu info David Woodhouse
@ 2020-12-04  1:18 ` David Woodhouse
  2020-12-04  1:18 ` [PATCH 14/15] KVM: x86/xen: register runstate info David Woodhouse
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 33+ messages in thread
From: David Woodhouse @ 2020-12-04  1:18 UTC (permalink / raw)
  To: kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson

From: Joao Martins <joao.m.martins@oracle.com>

Allow the Xen emulated guest the ability to register secondary
vcpu time information. On Xen guests this is used in order to be
mapped to userspace and hence allow vdso gettimeofday to work.

In doing so, move kvm_xen_set_pvclock_page() logic to
kvm_xen_update_vcpu_time() and have the former a top-level
function which updates primary vcpu time info (in struct vcpu_info)
and secondary one.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
 arch/x86/include/asm/kvm_host.h |  2 ++
 arch/x86/kvm/xen.c              | 53 ++++++++++++++++++++++-----------
 include/uapi/linux/kvm.h        |  1 +
 3 files changed, 38 insertions(+), 18 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 617c120d03a3..ec9425289209 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -525,6 +525,8 @@ struct kvm_vcpu_xen {
 	u64 hypercall_rip;
 	struct kvm_host_map vcpu_info_map;
 	struct vcpu_info *vcpu_info;
+	struct kvm_host_map pv_time_map;
+	struct pvclock_vcpu_time_info *pv_time;
 };
 
 struct kvm_vcpu_arch {
diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c
index f9ae2cfae0d2..5c67d9038651 100644
--- a/arch/x86/kvm/xen.c
+++ b/arch/x86/kvm/xen.c
@@ -99,26 +99,10 @@ static void *xen_vcpu_info(struct kvm_vcpu *v)
 	return hva + offset;
 }
 
-void kvm_xen_setup_pvclock_page(struct kvm_vcpu *v)
+static void kvm_xen_update_vcpu_time(struct kvm_vcpu *v,
+				     struct pvclock_vcpu_time_info *guest_hv_clock)
 {
 	struct kvm_vcpu_arch *vcpu = &v->arch;
-	struct pvclock_vcpu_time_info *guest_hv_clock;
-	void *hva = xen_vcpu_info(v);
-	unsigned int offset;
-
-	if (!hva)
-		return;
-
-	BUILD_BUG_ON(offsetof(struct shared_info, vcpu_info) != 0);
-	BUILD_BUG_ON(offsetof(struct compat_shared_info, vcpu_info) != 0);
-	BUILD_BUG_ON(sizeof(struct vcpu_info) != sizeof(struct compat_vcpu_info));
-	BUILD_BUG_ON(offsetof(struct vcpu_info, time) !=
-		     offsetof(struct compat_vcpu_info, time));
-
-	offset = v->vcpu_id * sizeof(struct vcpu_info);
-	offset += offsetof(struct vcpu_info, time);
-
-	guest_hv_clock = hva + offset;
 
 	if (guest_hv_clock->version & 1)
 		++guest_hv_clock->version;
@@ -147,6 +131,25 @@ void kvm_xen_setup_pvclock_page(struct kvm_vcpu *v)
 	guest_hv_clock->version = vcpu->hv_clock.version;
 }
 
+void kvm_xen_setup_pvclock_page(struct kvm_vcpu *v)
+{
+	struct kvm_vcpu_xen *vcpu_xen = vcpu_to_xen_vcpu(v);
+	struct vcpu_info *vcpu_info = xen_vcpu_info(v);
+
+	BUILD_BUG_ON(offsetof(struct shared_info, vcpu_info) != 0);
+	BUILD_BUG_ON(offsetof(struct compat_shared_info, vcpu_info) != 0);
+	BUILD_BUG_ON(sizeof(struct vcpu_info) != sizeof(struct compat_vcpu_info));
+	BUILD_BUG_ON(offsetof(struct vcpu_info, time) !=
+		     offsetof(struct compat_vcpu_info, time));
+
+	if (likely(vcpu_info))
+		kvm_xen_update_vcpu_time(v, &vcpu_info->time);
+
+	/* Update secondary pvclock region if registered */
+	if (vcpu_xen->pv_time)
+		kvm_xen_update_vcpu_time(v, vcpu_xen->pv_time);
+}
+
 static int vcpu_attr_loc(struct kvm_vcpu *vcpu, u16 type,
 			 struct kvm_host_map **map, void ***hva, size_t *sz)
 {
@@ -157,6 +160,13 @@ static int vcpu_attr_loc(struct kvm_vcpu *vcpu, u16 type,
 		if (sz)
 			*sz = sizeof(struct vcpu_info);
 		return 0;
+
+	case KVM_XEN_ATTR_TYPE_VCPU_TIME_INFO:
+		*map = &vcpu->arch.xen.pv_time_map;
+		*hva = (void **)&vcpu->arch.xen.pv_time;
+		if (sz)
+			*sz = sizeof(struct pvclock_vcpu_time_info);
+		return 0;
 	}
 	return -EINVAL;
 }
@@ -181,6 +191,7 @@ int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
 		break;
 	}
 
+	case KVM_XEN_ATTR_TYPE_VCPU_TIME_INFO:
 	case KVM_XEN_ATTR_TYPE_VCPU_INFO: {
 		gpa_t gpa = data->u.vcpu_attr.gpa;
 		struct kvm_host_map *map;
@@ -228,6 +239,7 @@ int kvm_xen_hvm_get_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
 		break;
 	}
 
+	case KVM_XEN_ATTR_TYPE_VCPU_TIME_INFO:
 	case KVM_XEN_ATTR_TYPE_VCPU_INFO: {
 		struct kvm_host_map *map;
 		struct kvm_vcpu *v;
@@ -397,6 +409,11 @@ void kvm_xen_vcpu_uninit(struct kvm_vcpu *vcpu)
 			      NULL, true, false);
 		vcpu_xen->vcpu_info = NULL;
 	}
+	if (vcpu_xen->pv_time) {
+		kvm_unmap_gfn(vcpu->kvm, &vcpu_xen->pv_time_map,
+			      NULL, true, false);
+		vcpu_xen->pv_time = NULL;
+	}
 }
 
 void kvm_xen_destroy_vm(struct kvm *kvm)
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 35b0d3b80f67..8a1914a9e206 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1598,6 +1598,7 @@ struct kvm_xen_hvm_attr {
 #define KVM_XEN_ATTR_TYPE_LONG_MODE		0x0
 #define KVM_XEN_ATTR_TYPE_SHARED_INFO		0x1
 #define KVM_XEN_ATTR_TYPE_VCPU_INFO		0x2
+#define KVM_XEN_ATTR_TYPE_VCPU_TIME_INFO	0x3
 
 /* Secure Encrypted Virtualization command */
 enum sev_cmd_id {
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 14/15] KVM: x86/xen: register runstate info
  2020-12-04  1:18 [PATCH 00/15] KVM: Add Xen hypercall and shared info pages David Woodhouse
                   ` (12 preceding siblings ...)
  2020-12-04  1:18 ` [PATCH 13/15] KVM: x86/xen: register vcpu time info region David Woodhouse
@ 2020-12-04  1:18 ` David Woodhouse
  2020-12-04  1:18 ` [PATCH 15/15] KVM: x86: declare Xen HVM shared info capability and add test case David Woodhouse
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 33+ messages in thread
From: David Woodhouse @ 2020-12-04  1:18 UTC (permalink / raw)
  To: kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson

From: Joao Martins <joao.m.martins@oracle.com>

Allow emulator to register vcpu runstates which allow Xen guests
to use that for steal clock. The 'preempted' state of KVM steal clock
equates to 'runnable' state, 'running' has similar meanings for both and
'offline' is used when system admin needs to bring vcpu offline or
hotplug.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
 arch/x86/include/asm/kvm_host.h |   5 ++
 arch/x86/kvm/x86.c              |  10 +++
 arch/x86/kvm/xen.c              | 123 +++++++++++++++++++++++++++++++-
 arch/x86/kvm/xen.h              |   9 ++-
 include/uapi/linux/kvm.h        |   1 +
 5 files changed, 144 insertions(+), 4 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index ec9425289209..d8716ef27728 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -527,6 +527,11 @@ struct kvm_vcpu_xen {
 	struct vcpu_info *vcpu_info;
 	struct kvm_host_map pv_time_map;
 	struct pvclock_vcpu_time_info *pv_time;
+	struct kvm_host_map runstate_map;
+	void *runstate;
+	uint32_t current_runstate;
+	uint64_t last_steal;
+	uint64_t last_state_ns;
 };
 
 struct kvm_vcpu_arch {
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 0a15748e3aa8..17ae827ae8cc 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2935,6 +2935,11 @@ static void record_steal_time(struct kvm_vcpu *vcpu)
 	struct kvm_host_map map;
 	struct kvm_steal_time *st;
 
+	if (vcpu->arch.xen.runstate) {
+		kvm_xen_setup_runstate_page(vcpu);
+		return;
+	}
+
 	if (!(vcpu->arch.st.msr_val & KVM_MSR_ENABLED))
 		return;
 
@@ -3962,6 +3967,11 @@ static void kvm_steal_time_set_preempted(struct kvm_vcpu *vcpu)
 	struct kvm_host_map map;
 	struct kvm_steal_time *st;
 
+	if (vcpu->arch.xen.runstate) {
+		kvm_xen_runstate_set_preempted(vcpu);
+		return;
+	}
+
 	if (!(vcpu->arch.st.msr_val & KVM_MSR_ENABLED))
 		return;
 
diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c
index 5c67d9038651..e49e59f93828 100644
--- a/arch/x86/kvm/xen.c
+++ b/arch/x86/kvm/xen.c
@@ -11,9 +11,11 @@
 #include "hyperv.h"
 
 #include <linux/kvm_host.h>
+#include <linux/sched/stat.h>
 
 #include <trace/events/kvm.h>
 #include <xen/interface/xen.h>
+#include <xen/interface/vcpu.h>
 
 #include "trace.h"
 
@@ -131,6 +133,98 @@ static void kvm_xen_update_vcpu_time(struct kvm_vcpu *v,
 	guest_hv_clock->version = vcpu->hv_clock.version;
 }
 
+static void kvm_xen_update_runstate(struct kvm_vcpu *vcpu, int state, u64 steal_ns)
+{
+	struct kvm_vcpu_xen *vcpu_xen = vcpu_to_xen_vcpu(vcpu);
+	struct compat_vcpu_runstate_info *runstate;
+	u32 *runstate_state;
+	u64 now, delta;
+
+	BUILD_BUG_ON(sizeof(struct compat_vcpu_runstate_info) != 0x2c);
+	BUILD_BUG_ON(offsetof(struct vcpu_runstate_info, state) !=
+		     offsetof(struct compat_vcpu_runstate_info, state));
+	BUILD_BUG_ON(sizeof(((struct vcpu_runstate_info *)0)->state) !=
+		     sizeof(((struct compat_vcpu_runstate_info *)0)->state));
+
+	runstate = vcpu_xen->runstate;
+	runstate_state = &runstate->state;
+
+#ifdef CONFIG_64BIT
+	/*
+	 * The only different is alignment of uint64_t in 32-bit.
+	 * So the first field 'state' is accessed via *runstate_state
+	 * which is unmodified, while the other fields are accessed
+	 * through 'runstate->' which we tweak here by adding 4.
+	 */
+	BUILD_BUG_ON(offsetof(struct vcpu_runstate_info, state_entry_time) !=
+		     offsetof(struct compat_vcpu_runstate_info, state_entry_time) + 4);
+	BUILD_BUG_ON(offsetof(struct vcpu_runstate_info, time) !=
+		     offsetof(struct compat_vcpu_runstate_info, time) + 4);
+	if (vcpu->kvm->arch.xen.long_mode)
+		runstate = ((void *)runstate) + 4;
+#endif
+	/*
+	 * Although it's called "state_entry_time" and explicitly documented
+	 * as being "the system time at which the VCPU was last scheduled to
+	 * run", Xen just treats it as a counter for HVM domains too.
+	 */
+	runstate->state_entry_time = XEN_RUNSTATE_UPDATE |
+		(runstate->state_entry_time + 1);
+	smp_wmb();
+
+	now = ktime_get_ns();
+	delta = now - vcpu_xen->last_state_ns - steal_ns;
+
+	*runstate_state = state;
+	runstate->time[vcpu_xen->current_runstate] += delta;
+	if (steal_ns)
+		runstate->time[RUNSTATE_runnable] += steal_ns;
+	smp_wmb();
+	vcpu_xen->current_runstate = state;
+	vcpu_xen->last_state_ns = now;
+
+	runstate->state_entry_time &= ~XEN_RUNSTATE_UPDATE;
+	smp_wmb();
+}
+
+void kvm_xen_runstate_set_preempted(struct kvm_vcpu *vcpu)
+{
+	struct kvm_vcpu_xen *vcpu_xen = vcpu_to_xen_vcpu(vcpu);
+	int new_state;
+
+	BUILD_BUG_ON(sizeof(struct compat_vcpu_runstate_info) != 0x2c);
+	BUILD_BUG_ON(offsetof(struct vcpu_runstate_info, state) !=
+		     offsetof(struct compat_vcpu_runstate_info, state));
+	BUILD_BUG_ON(sizeof(((struct vcpu_runstate_info *)0)->state) !=
+		     sizeof(((struct compat_vcpu_runstate_info *)0)->state));
+
+	if (vcpu->preempted) {
+		new_state = RUNSTATE_runnable;
+	} else {
+		new_state = RUNSTATE_blocked;
+		vcpu_xen->last_steal = current->sched_info.run_delay;
+	}
+
+	kvm_xen_update_runstate(vcpu, new_state, 0);
+}
+
+void kvm_xen_setup_runstate_page(struct kvm_vcpu *vcpu)
+{
+	struct kvm_vcpu_xen *vcpu_xen = vcpu_to_xen_vcpu(vcpu);
+	u64 steal_time = 0;
+
+	/*
+	 * If the CPU was blocked when it last stopped, presumably
+	 * it became unblocked at some point because it's being run
+	 * again now. The scheduler run_delay is the runnable time,
+	 * to be subtracted from the blocked time.
+	 */
+	if (vcpu_xen->current_runstate == RUNSTATE_blocked)
+		steal_time = current->sched_info.run_delay - vcpu_xen->last_steal;
+
+	kvm_xen_update_runstate(vcpu, RUNSTATE_running, steal_time);
+}
+
 void kvm_xen_setup_pvclock_page(struct kvm_vcpu *v)
 {
 	struct kvm_vcpu_xen *vcpu_xen = vcpu_to_xen_vcpu(v);
@@ -167,6 +261,15 @@ static int vcpu_attr_loc(struct kvm_vcpu *vcpu, u16 type,
 		if (sz)
 			*sz = sizeof(struct pvclock_vcpu_time_info);
 		return 0;
+
+	case KVM_XEN_ATTR_TYPE_VCPU_RUNSTATE:
+		*map = &vcpu->arch.xen.runstate_map;
+		*hva = (void **)&vcpu->arch.xen.runstate;
+		if (sz)
+			*sz = vcpu->kvm->arch.xen.long_mode ?
+				sizeof(struct shared_info) :
+				sizeof(struct compat_shared_info);
+		return 0;
 	}
 	return -EINVAL;
 }
@@ -191,6 +294,10 @@ int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
 		break;
 	}
 
+	case KVM_XEN_ATTR_TYPE_VCPU_RUNSTATE:
+		if (unlikely(!sched_info_on()))
+			return -ENOTSUPP;
+	/* fallthrough */
 	case KVM_XEN_ATTR_TYPE_VCPU_TIME_INFO:
 	case KVM_XEN_ATTR_TYPE_VCPU_INFO: {
 		gpa_t gpa = data->u.vcpu_attr.gpa;
@@ -208,9 +315,13 @@ int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
 			return r;
 
 		r = kvm_xen_map_guest_page(kvm, map, hva, gpa, sz);
-		if (!r)
-			kvm_xen_setup_pvclock_page(v);
-
+		if (!r) {
+			if (data->type == KVM_XEN_ATTR_TYPE_VCPU_RUNSTATE) {
+				v->arch.xen.current_runstate = RUNSTATE_runnable;
+				v->arch.xen.last_state_ns = ktime_get_ns();
+			} else
+				kvm_xen_setup_pvclock_page(v);
+		}
 		break;
 	}
 
@@ -239,6 +350,7 @@ int kvm_xen_hvm_get_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
 		break;
 	}
 
+	case KVM_XEN_ATTR_TYPE_VCPU_RUNSTATE:
 	case KVM_XEN_ATTR_TYPE_VCPU_TIME_INFO:
 	case KVM_XEN_ATTR_TYPE_VCPU_INFO: {
 		struct kvm_host_map *map;
@@ -414,6 +526,11 @@ void kvm_xen_vcpu_uninit(struct kvm_vcpu *vcpu)
 			      NULL, true, false);
 		vcpu_xen->pv_time = NULL;
 	}
+	if (vcpu_xen->runstate) {
+		kvm_unmap_gfn(vcpu->kvm, &vcpu_xen->runstate_map,
+			      NULL, true, false);
+		vcpu_xen->runstate = NULL;
+	}
 }
 
 void kvm_xen_destroy_vm(struct kvm *kvm)
diff --git a/arch/x86/kvm/xen.h b/arch/x86/kvm/xen.h
index 6d09b46d3c2e..42a9cc9f49a4 100644
--- a/arch/x86/kvm/xen.h
+++ b/arch/x86/kvm/xen.h
@@ -23,6 +23,8 @@ static inline struct kvm_vcpu *xen_vcpu_to_vcpu(struct kvm_vcpu_xen *xen_vcpu)
 }
 
 void kvm_xen_setup_pvclock_page(struct kvm_vcpu *vcpu);
+void kvm_xen_setup_runstate_page(struct kvm_vcpu *vcpu);
+void kvm_xen_runstate_set_preempted(struct kvm_vcpu *vcpu);
 int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data);
 int kvm_xen_hvm_get_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data);
 int kvm_xen_hypercall(struct kvm_vcpu *vcpu);
@@ -70,7 +72,12 @@ struct compat_shared_info {
 	uint32_t evtchn_mask[sizeof(compat_ulong_t) * 8];
 	struct pvclock_wall_clock wc;
 	struct compat_arch_shared_info arch;
-
 };
 
+struct compat_vcpu_runstate_info {
+    int state;
+    uint64_t state_entry_time;
+    uint64_t time[4];
+} __attribute__((packed));
+
 #endif /* __ARCH_X86_KVM_XEN_H__ */
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 8a1914a9e206..cb2777c37ae5 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1599,6 +1599,7 @@ struct kvm_xen_hvm_attr {
 #define KVM_XEN_ATTR_TYPE_SHARED_INFO		0x1
 #define KVM_XEN_ATTR_TYPE_VCPU_INFO		0x2
 #define KVM_XEN_ATTR_TYPE_VCPU_TIME_INFO	0x3
+#define KVM_XEN_ATTR_TYPE_VCPU_RUNSTATE		0x4
 
 /* Secure Encrypted Virtualization command */
 enum sev_cmd_id {
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 15/15] KVM: x86: declare Xen HVM shared info capability and add test case
  2020-12-04  1:18 [PATCH 00/15] KVM: Add Xen hypercall and shared info pages David Woodhouse
                   ` (13 preceding siblings ...)
  2020-12-04  1:18 ` [PATCH 14/15] KVM: x86/xen: register runstate info David Woodhouse
@ 2020-12-04  1:18 ` David Woodhouse
  2020-12-04  9:11 ` [PATCH 16/15] KVM: Add documentation for Xen hypercall and shared_info updates David Woodhouse
  2020-12-05 10:48 ` [PATCH 00/15] KVM: Add Xen hypercall and shared info pages David Woodhouse
  16 siblings, 0 replies; 33+ messages in thread
From: David Woodhouse @ 2020-12-04  1:18 UTC (permalink / raw)
  To: kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson

From: David Woodhouse <dwmw@amazon.co.uk>

Instead of adding a plethora of new KVM_CAP_XEN_FOO capabilities, just
add bits to the return value of KVM_CAP_XEN_HVM.

Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
 arch/x86/kvm/x86.c                            |   3 +-
 include/uapi/linux/kvm.h                      |   3 +
 tools/testing/selftests/kvm/Makefile          |   1 +
 .../selftests/kvm/x86_64/xen_shinfo_test.c    | 187 ++++++++++++++++++
 4 files changed, 193 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 17ae827ae8cc..870108c9ab89 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3731,7 +3731,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 		r = 1;
 		break;
 	case KVM_CAP_XEN_HVM:
-		r = 1 | KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL;
+		r = 1 | KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL |
+			KVM_XEN_HVM_CONFIG_SHARED_INFO;
 		break;
 	case KVM_CAP_SYNC_REGS:
 		r = KVM_SYNC_X86_VALID_FIELDS;
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index cb2777c37ae5..91a33675c739 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1144,6 +1144,7 @@ struct kvm_x86_mce {
 
 #ifdef KVM_CAP_XEN_HVM
 #define KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL	(1 << 1)
+#define KVM_XEN_HVM_CONFIG_SHARED_INFO		(1 << 2)
 
 struct kvm_xen_hvm_config {
 	__u32 flags;
@@ -1576,6 +1577,7 @@ struct kvm_pv_cmd {
 /* Available with KVM_CAP_X86_MSR_FILTER */
 #define KVM_X86_SET_MSR_FILTER	_IOW(KVMIO,  0xc6, struct kvm_msr_filter)
 
+/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO */
 #define KVM_XEN_HVM_GET_ATTR	_IOWR(KVMIO, 0xc7, struct kvm_xen_hvm_attr)
 #define KVM_XEN_HVM_SET_ATTR	_IOW(KVMIO,  0xc8, struct kvm_xen_hvm_attr)
 
@@ -1595,6 +1597,7 @@ struct kvm_xen_hvm_attr {
 	} u;
 };
 
+/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO */
 #define KVM_XEN_ATTR_TYPE_LONG_MODE		0x0
 #define KVM_XEN_ATTR_TYPE_SHARED_INFO		0x1
 #define KVM_XEN_ATTR_TYPE_VCPU_INFO		0x2
diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
index d94abec627e6..3d1d93947bda 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -59,6 +59,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/xss_msr_test
 TEST_GEN_PROGS_x86_64 += x86_64/debug_regs
 TEST_GEN_PROGS_x86_64 += x86_64/tsc_msrs_test
 TEST_GEN_PROGS_x86_64 += x86_64/user_msr_test
+TEST_GEN_PROGS_x86_64 += x86_64/xen_shinfo_test
 TEST_GEN_PROGS_x86_64 += x86_64/xen_vmcall_test
 TEST_GEN_PROGS_x86_64 += demand_paging_test
 TEST_GEN_PROGS_x86_64 += dirty_log_test
diff --git a/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c b/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c
new file mode 100644
index 000000000000..911d3f1ed2e0
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * svm_vmcall_test
+ *
+ * Copyright © 2020 Amazon.com, Inc. or its affiliates.
+ *
+ * Xen shared_info / pvclock testing
+ */
+
+#include "test_util.h"
+#include "kvm_util.h"
+#include "processor.h"
+
+#include <stdint.h>
+#include <time.h>
+
+#define VCPU_ID		5
+
+#define SHINFO_REGION_GPA	0xc0000000ULL
+#define SHINFO_REGION_SLOT	10
+#define PAGE_SIZE		4096
+
+#define PVTIME_ADDR	(SHINFO_REGION_GPA + PAGE_SIZE)
+#define RUNSTATE_ADDR	(SHINFO_REGION_GPA + PAGE_SIZE + 0x20)
+
+static struct kvm_vm *vm;
+
+#define XEN_HYPERCALL_MSR	0x40000000
+
+struct pvclock_vcpu_time_info {
+        u32   version;
+        u32   pad0;
+        u64   tsc_timestamp;
+        u64   system_time;
+        u32   tsc_to_system_mul;
+        s8    tsc_shift;
+        u8    flags;
+        u8    pad[2];
+} __attribute__((__packed__)); /* 32 bytes */
+
+struct pvclock_wall_clock {
+        u32   version;
+        u32   sec;
+        u32   nsec;
+} __attribute__((__packed__));
+
+struct vcpu_runstate_info {
+    uint32_t state;
+    uint64_t state_entry_time;
+    uint64_t time[4];
+};
+
+static void guest_code(void)
+{
+	struct vcpu_runstate_info *rs = (void *)RUNSTATE_ADDR;
+
+	/* Scribble on the runstate, just to make sure that... */
+	rs->state = 0x5a;
+
+	GUEST_SYNC(1);
+
+	/* ... it is being set to RUNSTATE_running */
+	GUEST_ASSERT(rs->state == 0);
+	GUEST_DONE();
+}
+
+static int cmp_timespec(struct timespec *a, struct timespec *b)
+{
+	if (a->tv_sec > b->tv_sec)
+		return 1;
+	else if (a->tv_sec < b->tv_sec)
+		return -1;
+	else if (a->tv_nsec > b->tv_nsec)
+		return 1;
+	else if (a->tv_nsec < b->tv_nsec)
+		return -1;
+	else
+		return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	struct timespec min_ts, max_ts, vm_ts;
+
+	if (!(kvm_check_cap(KVM_CAP_XEN_HVM) &
+	      KVM_XEN_HVM_CONFIG_SHARED_INFO) ) {
+		print_skip("KVM_XEN_HVM_CONFIG_SHARED_INFO not available");
+		exit(KSFT_SKIP);
+	}
+
+	clock_gettime(CLOCK_REALTIME, &min_ts);
+
+	vm = vm_create_default(VCPU_ID, 0, (void *) guest_code);
+	vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid());
+
+	/* Map a region for the shared_info page */
+	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
+                                    SHINFO_REGION_GPA, SHINFO_REGION_SLOT,
+				    2 * getpagesize(), 0);
+	virt_map(vm, SHINFO_REGION_GPA, SHINFO_REGION_GPA, 2, 0);
+
+	struct kvm_xen_hvm_attr lm = {
+		.type = KVM_XEN_ATTR_TYPE_LONG_MODE,
+		.u.long_mode = 1,
+	};
+	vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &lm);
+
+	struct kvm_xen_hvm_attr ha = {
+		.type = KVM_XEN_ATTR_TYPE_SHARED_INFO,
+		.u.shared_info.gfn = SHINFO_REGION_GPA / PAGE_SIZE,
+	};
+	vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &ha);
+
+	struct kvm_xen_hvm_attr pvclock = {
+		.type = KVM_XEN_ATTR_TYPE_VCPU_TIME_INFO,
+		.u.vcpu_attr.vcpu = VCPU_ID,
+		.u.vcpu_attr.gpa = PVTIME_ADDR,
+	};
+	vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &pvclock);
+
+	struct kvm_xen_hvm_attr st = {
+		.type = KVM_XEN_ATTR_TYPE_VCPU_RUNSTATE,
+		.u.vcpu_attr.vcpu = VCPU_ID,
+		.u.vcpu_attr.gpa = RUNSTATE_ADDR,
+	};
+	vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &st);
+
+	for (;;) {
+		volatile struct kvm_run *run = vcpu_state(vm, VCPU_ID);
+		struct ucall uc;
+
+		vcpu_run(vm, VCPU_ID);
+
+		TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
+			    "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n",
+			    run->exit_reason,
+			    exit_reason_str(run->exit_reason));
+
+		switch (get_ucall(vm, VCPU_ID, &uc)) {
+		case UCALL_ABORT:
+			TEST_FAIL("%s", (const char *)uc.args[0]);
+			/* NOT REACHED */
+		case UCALL_SYNC:
+			break;
+		case UCALL_DONE:
+			goto done;
+		default:
+			TEST_FAIL("Unknown ucall 0x%lx.", uc.cmd);
+		}
+	}
+
+ done:
+	clock_gettime(CLOCK_REALTIME, &max_ts);
+
+	/*
+	 * Just a *really* basic check that things are being put in the
+	 * right place. The actual calculations are much the same for
+	 * Xen as they are for the KVM variants, so no need to check.
+	 */
+	struct pvclock_wall_clock *wc;
+	struct pvclock_vcpu_time_info *ti, *ti2;
+	struct vcpu_runstate_info *rs;
+
+	wc = addr_gva2hva(vm, SHINFO_REGION_GPA + 0xc00);
+	ti = addr_gva2hva(vm, SHINFO_REGION_GPA + 0x40 * VCPU_ID + 0x20);
+	ti2 = addr_gva2hva(vm, PVTIME_ADDR);
+	rs = addr_gva2hva(vm, RUNSTATE_ADDR);
+
+	vm_ts.tv_sec = wc->sec;
+	vm_ts.tv_nsec = wc->nsec;
+        TEST_ASSERT(wc->version && !(wc->version & 1),
+		    "Bad wallclock version %x", wc->version);
+	TEST_ASSERT(cmp_timespec(&min_ts, &vm_ts) <= 0, "VM time too old");
+	TEST_ASSERT(cmp_timespec(&max_ts, &vm_ts) >= 0, "VM time too new");
+
+	TEST_ASSERT(ti->version && !(ti->version & 1),
+		    "Bad time_info version %x", ti->version);
+	TEST_ASSERT(ti2->version && !(ti2->version & 1),
+		    "Bad time_info version %x", ti->version);
+
+	/* Check for RUNSTATE_blocked */
+	TEST_ASSERT(rs->state == 2, "Not RUNSTATE_blocked");
+	TEST_ASSERT(rs->time[0], "No RUNSTATE_running time");
+	TEST_ASSERT(rs->time[2], "No RUNSTATE_blocked time");
+	kvm_vm_free(vm);
+	return 0;
+}
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 16/15]  KVM: Add documentation for Xen hypercall and shared_info updates
  2020-12-04  1:18 [PATCH 00/15] KVM: Add Xen hypercall and shared info pages David Woodhouse
                   ` (14 preceding siblings ...)
  2020-12-04  1:18 ` [PATCH 15/15] KVM: x86: declare Xen HVM shared info capability and add test case David Woodhouse
@ 2020-12-04  9:11 ` David Woodhouse
  2020-12-05 10:48 ` [PATCH 00/15] KVM: Add Xen hypercall and shared info pages David Woodhouse
  16 siblings, 0 replies; 33+ messages in thread
From: David Woodhouse @ 2020-12-04  9:11 UTC (permalink / raw)
  To: kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson

[-- Attachment #1: Type: text/plain, Size: 5088 bytes --]

From: David Woodhouse <dwmw@amazon.co.uk>

Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
 Documentation/virt/kvm/api.rst | 119 +++++++++++++++++++++++++++++++++
 1 file changed, 119 insertions(+)

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index e00a66d72372..d98c2ff90880 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -944,6 +944,13 @@ memory.
 	__u8 pad2[30];
   };
 
+If the KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL flag is returned from the
+KVM_CAP_XEN_HVM check, it may be set in the flags field of this ioctl.
+This requests KVM to generate the contents of the hypercall page
+automatically, and also to intercept hypercalls with KVM_EXIT_XEN.
+In this case, all of the blob size and address fields must be zero.
+
+No other flags are currently valid.
 
 4.29 KVM_GET_CLOCK
 ------------------
@@ -4807,6 +4814,67 @@ into user space.
 If a vCPU is in running state while this ioctl is invoked, the vCPU may
 experience inconsistent filtering behavior on MSR accesses.
 
+4.127 KVM_XEN_HVM_SET_ATTR
+--------------------------
+
+:Capability: KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO
+:Architectures: x86
+:Type: vm ioctl
+:Parameters: struct kvm_xen_hvm_attr
+:Returns: 0 on success, < 0 on error
+
+::
+
+  struct kvm_xen_hvm_attr {
+	__u16 type;
+
+	union {
+		__u8 long_mode;
+		struct {
+			__u64 gfn;
+		} shared_info;
+		struct {
+			__u32 vcpu;
+			__u64 gpa;
+		} vcpu_attr;
+		__u64 pad[4];
+	} u;
+  };
+
+type values:
+
+KVM_XEN_ATTR_TYPE_LONG_MODE
+  Sets the ABI mode of the VM to 32-bit or 64-bit (long mode). This
+  determines the layout of the shared info pages exposed to the VM.
+
+KVM_XEN_ATTR_TYPE_SHARED_INFO
+  Sets the guest physical frame number at which the Xen "shared info"
+  page resides. It is the default location for the vcpu_info for the
+  first 32 vCPUs, and contains other VM-wide data structures shared
+  between the VM and the host.
+
+KVM_XEN_ATTR_TYPE_VCPU_INFO
+  Sets the guest physical address of the vcpu_info for a given vCPU.
+
+KVM_XEN_ATTR_TYPE_VCPU_TIME_INFO
+  Sets the guest physical address of an additional pvclock structure
+  for a given vCPU. This is typically used for guest vsyscall support.
+
+KVM_XEN_ATTR_TYPE_VCPU_RUNSTATE
+  Sets the guest physical address of the vcpu_runstate_info for a given
+  vCPU. This is how a Xen guest tracks CPU state such as steal time.
+
+4.128 KVM_XEN_HVM_GET_ATTR
+--------------------------
+
+:Capability: KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO
+:Architectures: x86
+:Type: vm ioctl
+:Parameters: struct kvm_xen_hvm_attr
+:Returns: 0 on success, < 0 on error
+
+Allows Xen VM attributes to be read. For the structure and types,
+see KVM_XEN_HVM_SET_ATTR above.
 
 5. The kvm_run structure
 ========================
@@ -5303,6 +5371,34 @@ wants to write. Once finished processing the event, user space must continue
 vCPU execution. If the MSR write was unsuccessful, user space also sets the
 "error" field to "1".
 
+::
+
+
+		struct kvm_xen_exit {
+  #define KVM_EXIT_XEN_HCALL          1
+			__u32 type;
+			union {
+				struct {
+					__u32 longmode;
+					__u32 cpl;
+					__u64 input;
+					__u64 result;
+					__u64 params[6];
+				} hcall;
+			} u;
+		};
+		/* KVM_EXIT_XEN */
+                struct kvm_hyperv_exit xen;
+
+Indicates that the VCPU exits into userspace to process some tasks
+related to Xen emulation.
+
+Valid values for 'type' are:
+
+  - KVM_EXIT_XEN_HCALL -- synchronously notify user-space about Xen hypercall.
+    Userspace is expected to place the hypercall result into the appropriate
+    field before invoking KVM_RUN again.
+
 ::
 
 		/* Fix the size of the union. */
@@ -6390,3 +6486,26 @@ When enabled, KVM will disable paravirtual features provided to the
 guest according to the bits in the KVM_CPUID_FEATURES CPUID leaf
 (0x40000001). Otherwise, a guest may use the paravirtual features
 regardless of what has actually been exposed through the CPUID leaf.
+
+8.29 KVM_CAP_XEN_HVM
+--------------------
+
+:Architectures: x86
+
+This capability indicates the features that Xen supports for hosting Xen
+PVHVM guests. Valid flags are::
+
+  #define KVM_XEN_HVM_CONFIG_HYPERCALL_MSR	(1 << 0)
+  #define KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL	(1 << 1)
+  #define KVM_XEN_HVM_CONFIG_SHARED_INFO	(1 << 2)
+
+The KVM_XEN_HVM_CONFIG_HYPERCALL_MSR flag indicates that the KVM_XEN_HVM_CONFIG
+ioctl is available, for the guest to set its hypercall page.
+
+If KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL is also set, the same flag may also be
+provided in the flags to KVM_XEN_HVM_CONFIG, without providing hypercall page
+contents, to request that KVM generate hypercall page content automatically
+and also enable interception of guest hypercalls with KVM_EXIT_XEN.
+
+The KVM_XEN_HVM_CONFIG_SHARED_INFO flag indicates the availability of the
+KVM_XEN_HVM_SET_ATTR and KVM_XEN_HVM_GET_ATTR ioctls.
-- 
2.17.1


[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 5174 bytes --]

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: [PATCH 02/15] KVM: x86/xen: fix Xen hypercall page msr handling
  2020-12-04  1:18 ` [PATCH 02/15] KVM: x86/xen: fix Xen hypercall page msr handling David Woodhouse
@ 2020-12-04 18:26   ` Alexander Graf
  2020-12-04 18:54     ` David Woodhouse
  0 siblings, 1 reply; 33+ messages in thread
From: Alexander Graf @ 2020-12-04 18:26 UTC (permalink / raw)
  To: David Woodhouse, kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson

On 04.12.20 02:18, David Woodhouse wrote:
> From: Joao Martins <joao.m.martins@oracle.com>
> 
> Xen usually places its MSR at 0x40000000 or 0x40000200 depending on
> whether it is running in viridian mode or not. Note that this is not
> ABI guaranteed, so it is possible for Xen to advertise the MSR some
> place else.
> 
> Given the way xen_hvm_config() is handled, if the former address is
> selected, this will conflict with Hyper-V's MSR
> (HV_X64_MSR_GUEST_OS_ID) which unconditionally uses the same address.
> 
> Given that the MSR location is arbitrary, move the xen_hvm_config()
> handling to the top of kvm_set_msr_common() before falling through.
> 
> Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
> Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
> ---
>   arch/x86/kvm/x86.c | 5 +++--
>   1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index c7f1ba21212e..13ba4a64f748 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -3001,6 +3001,9 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
>   	u32 msr = msr_info->index;
>   	u64 data = msr_info->data;
>   
> +	if (msr && (msr == vcpu->kvm->arch.xen_hvm_config.msr))
> +		return xen_hvm_config(vcpu, data);

How much of this can we handle with the MSR allow listing and MSR 
trapping in user space?


Alex



Amazon Development Center Germany GmbH
Krausenstr. 38
10117 Berlin
Geschaeftsfuehrung: Christian Schlaeger, Jonathan Weiss
Eingetragen am Amtsgericht Charlottenburg unter HRB 149173 B
Sitz: Berlin
Ust-ID: DE 289 237 879




^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 03/15] KVM: x86/xen: intercept xen hypercalls if enabled
  2020-12-04  1:18 ` [PATCH 03/15] KVM: x86/xen: intercept xen hypercalls if enabled David Woodhouse
@ 2020-12-04 18:26   ` Alexander Graf
  2020-12-04 18:58     ` David Woodhouse
  2020-12-05 18:42   ` Joao Martins
  1 sibling, 1 reply; 33+ messages in thread
From: Alexander Graf @ 2020-12-04 18:26 UTC (permalink / raw)
  To: David Woodhouse, kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson

On 04.12.20 02:18, David Woodhouse wrote:
> From: Joao Martins <joao.m.martins@oracle.com>
> 
> Add a new exit reason for emulator to handle Xen hypercalls.
> 
> Since this means KVM owns the ABI, dispense with the facility for the
> VMM to provide its own copy of the hypercall pages; just fill them in
> directly using VMCALL/VMMCALL as we do for the Hyper-V hypercall page.
> 
> This behaviour is enabled by a new INTERCEPT_HCALL flag in the
> KVM_XEN_HVM_CONFIG ioctl structure, and advertised by the same flag
> being returned from the KVM_CAP_XEN_HVM check.
> 
> Add a test case and shift xen_hvm_config() to the nascent xen.c while
> we're at it.
> 
> Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
> Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>

Why does any of this have to live in kernel space? I would expect user 
space to own the MSR and hcall number space and push it down to KVM. 
That means it can also provide the shims it needs.


Alex



Amazon Development Center Germany GmbH
Krausenstr. 38
10117 Berlin
Geschaeftsfuehrung: Christian Schlaeger, Jonathan Weiss
Eingetragen am Amtsgericht Charlottenburg unter HRB 149173 B
Sitz: Berlin
Ust-ID: DE 289 237 879



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 01/15] KVM: Fix arguments to kvm_{un,}map_gfn()
  2020-12-04  1:18 ` [PATCH 01/15] KVM: Fix arguments to kvm_{un,}map_gfn() David Woodhouse
@ 2020-12-04 18:27   ` Alexander Graf
  2020-12-04 19:02     ` David Woodhouse
  0 siblings, 1 reply; 33+ messages in thread
From: Alexander Graf @ 2020-12-04 18:27 UTC (permalink / raw)
  To: David Woodhouse, kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson

On 04.12.20 02:18, David Woodhouse wrote:
> From: David Woodhouse <dwmw@amazon.co.uk>
> 
> It shouldn't take a vcpu.

This is not a patch description. Please provide an actual rationale.


Alex



Amazon Development Center Germany GmbH
Krausenstr. 38
10117 Berlin
Geschaeftsfuehrung: Christian Schlaeger, Jonathan Weiss
Eingetragen am Amtsgericht Charlottenburg unter HRB 149173 B
Sitz: Berlin
Ust-ID: DE 289 237 879




^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 04/15] KVM: x86/xen: Fix coexistence of Xen and Hyper-V hypercalls
  2020-12-04  1:18 ` [PATCH 04/15] KVM: x86/xen: Fix coexistence of Xen and Hyper-V hypercalls David Woodhouse
@ 2020-12-04 18:34   ` Alexander Graf
  2020-12-04 19:04     ` David Woodhouse
  0 siblings, 1 reply; 33+ messages in thread
From: Alexander Graf @ 2020-12-04 18:34 UTC (permalink / raw)
  To: David Woodhouse, kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson

On 04.12.20 02:18, David Woodhouse wrote:
> From: David Woodhouse <dwmw@amazon.co.uk>
> 
> Disambiguate Xen vs. Hyper-V calls by adding 'orl $0x80000000, %eax'
> at the start of the Hyper-V hypercall page when Xen hypercalls are
> also enabled.
> 
> That bit is reserved in the Hyper-V ABI, and those hypercall numbers
> will never be used by Xen (because it does precisely the same trick).
> 
> Switch to using kvm_vcpu_write_guest() while we're at it, instead of
> open-coding it.
> 
> Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>

I'm not a big fan of the implicit assumption that "xen hypercall 
enabled" means "this will be the offset". Can we make that something 
more explicit, say through an ENABLE_CAP?


Alex



Amazon Development Center Germany GmbH
Krausenstr. 38
10117 Berlin
Geschaeftsfuehrung: Christian Schlaeger, Jonathan Weiss
Eingetragen am Amtsgericht Charlottenburg unter HRB 149173 B
Sitz: Berlin
Ust-ID: DE 289 237 879




^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 06/15] KVM: x86/xen: latch long_mode when hypercall page is set up
  2020-12-04  1:18 ` [PATCH 06/15] KVM: x86/xen: latch long_mode when hypercall page is set up David Woodhouse
@ 2020-12-04 18:38   ` Alexander Graf
  2020-12-04 19:08     ` David Woodhouse
  0 siblings, 1 reply; 33+ messages in thread
From: Alexander Graf @ 2020-12-04 18:38 UTC (permalink / raw)
  To: David Woodhouse, kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson

On 04.12.20 02:18, David Woodhouse wrote:
> From: David Woodhouse <dwmw@amazon.co.uk>

If the shared_info page was maintained by user space, you wouldn't need 
any of this, right?


Alex




Amazon Development Center Germany GmbH
Krausenstr. 38
10117 Berlin
Geschaeftsfuehrung: Christian Schlaeger, Jonathan Weiss
Eingetragen am Amtsgericht Charlottenburg unter HRB 149173 B
Sitz: Berlin
Ust-ID: DE 289 237 879




^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 02/15] KVM: x86/xen: fix Xen hypercall page msr handling
  2020-12-04 18:26   ` Alexander Graf
@ 2020-12-04 18:54     ` David Woodhouse
  0 siblings, 0 replies; 33+ messages in thread
From: David Woodhouse @ 2020-12-04 18:54 UTC (permalink / raw)
  To: Alexander Graf, kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson



On 4 December 2020 18:26:36 GMT, Alexander Graf <graf@amazon.com> wrote:
>How much of this can we handle with the MSR allow listing and MSR 
>trapping in user space?

We resisted that trapping for a long time but have it now, and both the existing Xen and Hyper-V support — as well as a bunch of other things that KVM has historically done in-kernel on trapping MSRs — could *theoretically* be done in userspace.

But they all already exist in the kernel. This is just a bug fix because the Hyper-V support broke it for Xen due to the conflict.

-- 
Sent from my Android device with K-9 Mail. Please excuse my brevity.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 03/15] KVM: x86/xen: intercept xen hypercalls if enabled
  2020-12-04 18:26   ` Alexander Graf
@ 2020-12-04 18:58     ` David Woodhouse
  0 siblings, 0 replies; 33+ messages in thread
From: David Woodhouse @ 2020-12-04 18:58 UTC (permalink / raw)
  To: Alexander Graf, kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson



On 4 December 2020 18:26:54 GMT, Alexander Graf <graf@amazon.com> wrote:
>Why does any of this have to live in kernel space? I would expect user 
>space to own the MSR and hcall number space and push it down to KVM. 
>That means it can also provide the shims it needs.

Because the kernel is already trapping the VMCALL and handling all the KVM hypercalls, because it's much more efficient to do so.

This is just a way to allow userspace to see those exits and handle the hypercalls *instead* of the kernel.

I suppose you can make the case that none of the KVM hypercalls should be handled in-kernel and it could all be done by trapping to userspace. But that ship sailed long ago, even if you were right and the additional latency of handling the KVM hypercalls was indeed acceptable.

-- 
Sent from my Android device with K-9 Mail. Please excuse my brevity.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 01/15] KVM: Fix arguments to kvm_{un,}map_gfn()
  2020-12-04 18:27   ` Alexander Graf
@ 2020-12-04 19:02     ` David Woodhouse
  0 siblings, 0 replies; 33+ messages in thread
From: David Woodhouse @ 2020-12-04 19:02 UTC (permalink / raw)
  To: Alexander Graf, kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson



On 4 December 2020 18:27:34 GMT, Alexander Graf <graf@amazon.com> wrote:
>On 04.12.20 02:18, David Woodhouse wrote:
>> From: David Woodhouse <dwmw@amazon.co.uk>
>> 
>> It shouldn't take a vcpu.
>
>This is not a patch description. Please provide an actual rationale.

What?

If you aren't familiar with the KVM function nomenclature... since the function name is kvm_xxx() and it operates on the struct KVM, not kvm_vcpu_xxx() and it doesn't actually use the vCPU it's given except to get vcpu->kvm and operate on that... it shouldn't take a vcpu.

But most of those words are superfluous to anyone who's paying attention.

The rationale in the patch seems perfectly clear to me.
>
>
>
>Amazon Development Center Germany GmbH
>Krausenstr. 38
>10117 Berlin
>Geschaeftsfuehrung: Christian Schlaeger, Jonathan Weiss
>Eingetragen am Amtsgericht Charlottenburg unter HRB 149173 B
>Sitz: Berlin
>Ust-ID: DE 289 237 879

-- 
Sent from my Android device with K-9 Mail. Please excuse my brevity.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 04/15] KVM: x86/xen: Fix coexistence of Xen and Hyper-V hypercalls
  2020-12-04 18:34   ` Alexander Graf
@ 2020-12-04 19:04     ` David Woodhouse
  0 siblings, 0 replies; 33+ messages in thread
From: David Woodhouse @ 2020-12-04 19:04 UTC (permalink / raw)
  To: Alexander Graf, kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson



On 4 December 2020 18:34:40 GMT, Alexander Graf <graf@amazon.com> wrote:
>On 04.12.20 02:18, David Woodhouse wrote:
>> From: David Woodhouse <dwmw@amazon.co.uk>
>> 
>> Disambiguate Xen vs. Hyper-V calls by adding 'orl $0x80000000, %eax'
>> at the start of the Hyper-V hypercall page when Xen hypercalls are
>> also enabled.
>> 
>> That bit is reserved in the Hyper-V ABI, and those hypercall numbers
>> will never be used by Xen (because it does precisely the same trick).
>> 
>> Switch to using kvm_vcpu_write_guest() while we're at it, instead of
>> open-coding it.
>> 
>> Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
>
>I'm not a big fan of the implicit assumption that "xen hypercall 
>enabled" means "this will be the offset". Can we make that something 
>more explicit, say through an ENABLE_CAP?

Nah. The kernel owns the ABI, and it would be complete overkill to allow more gratuitous tweakable options here.

Can you explain a reason why anyone would ever want to change it?
-- 
Sent from my Android device with K-9 Mail. Please excuse my brevity.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 06/15] KVM: x86/xen: latch long_mode when hypercall page is set up
  2020-12-04 18:38   ` Alexander Graf
@ 2020-12-04 19:08     ` David Woodhouse
  0 siblings, 0 replies; 33+ messages in thread
From: David Woodhouse @ 2020-12-04 19:08 UTC (permalink / raw)
  To: Alexander Graf, kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson



On 4 December 2020 18:38:05 GMT, Alexander Graf <graf@amazon.com> wrote:
>On 04.12.20 02:18, David Woodhouse wrote:
>> From: David Woodhouse <dwmw@amazon.co.uk>
>
>If the shared_info page was maintained by user space, you wouldn't need
>
>any of this, right?

That may be the case. But what we put in the shared_info page and in the vcpu_info is time keeping information which KVM has done for guests — from the kernel — for a very long time.

Again, you could make the argument that some of this stuff *could* be done — albeit less efficiently — form userspace.

But again, that ship sailed years ago.
-- 
Sent from my Android device with K-9 Mail. Please excuse my brevity.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 00/15] KVM: Add Xen hypercall and shared info pages
  2020-12-04  1:18 [PATCH 00/15] KVM: Add Xen hypercall and shared info pages David Woodhouse
                   ` (15 preceding siblings ...)
  2020-12-04  9:11 ` [PATCH 16/15] KVM: Add documentation for Xen hypercall and shared_info updates David Woodhouse
@ 2020-12-05 10:48 ` David Woodhouse
  16 siblings, 0 replies; 33+ messages in thread
From: David Woodhouse @ 2020-12-05 10:48 UTC (permalink / raw)
  To: kvm
  Cc: Paolo Bonzini, Ankur Arora, Joao Martins, Boris Ostrovsky,
	Sean Christopherson

[-- Attachment #1: Type: text/plain, Size: 4442 bytes --]

On Fri, 2020-12-04 at 01:18 +0000, David Woodhouse wrote:
> Reviving the first section (so far) of a patch set that Joao posted as 
> RFC last year:
> 
> https://lore.kernel.org/kvm/20190220201609.28290-1-joao.m.martins@oracle.com/
> 
> This adds basic hypercall interception support, and adds support for
> timekeeping and runstate-related shared info regions.
> 
> I've updated and reworked the original a bit, including:
>  • Support for 32-bit guests
>  • 64-bit second support in wallclock
>  • Time counters for runnable/blocked states in runstate support
>  • Self-tests
>  • Fixed Viridian coexistence
>  • No new KVM_CAP_XEN_xxx, just more bits returned by KVM_CAP_XEN_HVM
> 
> I'm about to do the event channel support, but this part stands alone
> and should be sufficient to get a fully functional Xen HVM guest running.

I also realise I forgot to include the RCU read-critical sections
around using the pointers that might get invalidated. (This is the
model I think can we use for the KVM pvclock and other pages that we
currently pin too, FWIW.)

That looks a bit like this. Unless there's any other useful and
relevant feedback I'll post a V2 of the series over the weekend or on
Monday.

diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c
index e49e59f93828..4aa776c1ad57 100644
--- a/arch/x86/kvm/xen.c
+++ b/arch/x86/kvm/xen.c
@@ -86,19 +86,21 @@ static void *xen_vcpu_info(struct kvm_vcpu *v)
 {
 	struct kvm_vcpu_xen *vcpu_xen = vcpu_to_xen_vcpu(v);
 	struct kvm_xen *kvm = &v->kvm->arch.xen;
-	unsigned int offset = 0;
-	void *hva = NULL;
+	void *hva;
 
-	if (vcpu_xen->vcpu_info)
-		return vcpu_xen->vcpu_info;
+	hva = READ_ONCE(vcpu_xen->vcpu_info);
+	if (hva)
+		return hva;
 
-	if (kvm->shinfo && v->vcpu_id < MAX_VIRT_CPUS) {
-		hva = kvm->shinfo;
-		offset += offsetof(struct shared_info, vcpu_info);
-		offset += v->vcpu_id * sizeof(struct vcpu_info);
+	if (v->vcpu_id < MAX_VIRT_CPUS)
+		hva = READ_ONCE(kvm->shinfo);
+
+	if (hva) {
+		hva += offsetof(struct shared_info, vcpu_info);
+		hva += v->vcpu_id * sizeof(struct vcpu_info);
 	}
 
-	return hva + offset;
+	return hva;
 }
 
 static void kvm_xen_update_vcpu_time(struct kvm_vcpu *v,
@@ -139,6 +141,7 @@ static void kvm_xen_update_runstate(struct kvm_vcpu *vcpu, int state, u64 steal_
 	struct compat_vcpu_runstate_info *runstate;
 	u32 *runstate_state;
 	u64 now, delta;
+	int idx;
 
 	BUILD_BUG_ON(sizeof(struct compat_vcpu_runstate_info) != 0x2c);
 	BUILD_BUG_ON(offsetof(struct vcpu_runstate_info, state) !=
@@ -146,7 +149,8 @@ static void kvm_xen_update_runstate(struct kvm_vcpu *vcpu, int state, u64 steal_
 	BUILD_BUG_ON(sizeof(((struct vcpu_runstate_info *)0)->state) !=
 		     sizeof(((struct compat_vcpu_runstate_info *)0)->state));
 
-	runstate = vcpu_xen->runstate;
+	idx = srcu_read_lock(&vcpu->kvm->srcu);
+	runstate = READ_ONCE(vcpu_xen->runstate);
 	runstate_state = &runstate->state;
 
 #ifdef CONFIG_64BIT
@@ -185,6 +189,8 @@ static void kvm_xen_update_runstate(struct kvm_vcpu *vcpu, int state, u64 steal_
 
 	runstate->state_entry_time &= ~XEN_RUNSTATE_UPDATE;
 	smp_wmb();
+
+	srcu_read_unlock(&vcpu->kvm->srcu, idx);
 }
 
 void kvm_xen_runstate_set_preempted(struct kvm_vcpu *vcpu)
@@ -228,7 +234,9 @@ void kvm_xen_setup_runstate_page(struct kvm_vcpu *vcpu)
 void kvm_xen_setup_pvclock_page(struct kvm_vcpu *v)
 {
 	struct kvm_vcpu_xen *vcpu_xen = vcpu_to_xen_vcpu(v);
-	struct vcpu_info *vcpu_info = xen_vcpu_info(v);
+	struct vcpu_info *vcpu_info;
+	struct pvclock_vcpu_time_info *pv_info;
+	int idx;
 
 	BUILD_BUG_ON(offsetof(struct shared_info, vcpu_info) != 0);
 	BUILD_BUG_ON(offsetof(struct compat_shared_info, vcpu_info) != 0);
@@ -236,12 +244,17 @@ void kvm_xen_setup_pvclock_page(struct kvm_vcpu *v)
 	BUILD_BUG_ON(offsetof(struct vcpu_info, time) !=
 		     offsetof(struct compat_vcpu_info, time));
 
+	idx = srcu_read_lock(&v->kvm->srcu);
+	vcpu_info = xen_vcpu_info(v);
 	if (likely(vcpu_info))
 		kvm_xen_update_vcpu_time(v, &vcpu_info->time);
 
 	/* Update secondary pvclock region if registered */
-	if (vcpu_xen->pv_time)
-		kvm_xen_update_vcpu_time(v, vcpu_xen->pv_time);
+	pv_info = READ_ONCE(vcpu_xen->pv_time);
+	if (pv_info)
+		kvm_xen_update_vcpu_time(v, pv_info);
+
+	srcu_read_unlock(&v->kvm->srcu, idx);
 }
 
 static int vcpu_attr_loc(struct kvm_vcpu *vcpu, u16 type,


[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 5174 bytes --]

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: [PATCH 03/15] KVM: x86/xen: intercept xen hypercalls if enabled
  2020-12-04  1:18 ` [PATCH 03/15] KVM: x86/xen: intercept xen hypercalls if enabled David Woodhouse
  2020-12-04 18:26   ` Alexander Graf
@ 2020-12-05 18:42   ` Joao Martins
  2020-12-05 18:51     ` David Woodhouse
  1 sibling, 1 reply; 33+ messages in thread
From: Joao Martins @ 2020-12-05 18:42 UTC (permalink / raw)
  To: David Woodhouse
  Cc: Paolo Bonzini, Ankur Arora, Boris Ostrovsky, Sean Christopherson, kvm

On 12/4/20 1:18 AM, David Woodhouse wrote:
> @@ -3742,6 +3716,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
>  	case KVM_CAP_ENFORCE_PV_FEATURE_CPUID:
>  		r = 1;
>  		break;
> +	case KVM_CAP_XEN_HVM:
> +		r = 1 | KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL;
> +		break;

Maybe:

	r = KVM_XEN_HVM_CONFIG_HYPERCALL_MSR |
		KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL;

>  	case KVM_CAP_SYNC_REGS:
>  		r = KVM_SYNC_X86_VALID_FIELDS;
>  		break;
> @@ -5603,7 +5580,15 @@ long kvm_arch_vm_ioctl(struct file *filp,
>  		if (copy_from_user(&xhc, argp, sizeof(xhc)))
>  			goto out;
>  		r = -EINVAL;
> -		if (xhc.flags)
> +		if (xhc.flags & ~KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL)
> +			goto out;
> +		/*
> +		 * With hypercall interception the kernel generates its own
> +		 * hypercall page so it must not be provided.
> +		 */
> +		if ((xhc.flags & KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL) &&
> +		    (xhc.blob_addr_32 || xhc.blob_addr_64 ||
> +		     xhc.blob_size_32 || xhc.blob_size_64))
>  			goto out;

I suppose it makes sense restricting to INTERCEPT_HCALL to make sure that the kernel only
forwards the hcall if it is control off what it put there in the hypercall page (i.e.
vmmcall/vmcall). hcall userspace exiting without INTERCEPT_HCALL would break ABI over how
this ioctl was used before the new flag... In case kvm_xen_hypercall_enabled() would
return true with KVM_XEN_HVM_CONFIG_HYPERCALL_MSR, as now it needs to handle a new
userspace exit.

If we're are being pedantic, the Xen hypercall MSR is a utility more than a necessity as
the OS can always do without the hcall msr IIUC. But it is defacto used by enlightened Xen
guests included FreeBSD.

If we were to lift the restriction in the conditional above to forward hcall without
INTERCEPT_HCALL flag then kvm_xen_hypercall_enabled() would return true with
CONFIG_HYPERCALL_MSR and CONFIG_INTERCEPT_HCALL. And on wrmsr time, we would only look at
whether we had a blob_size* passed in when handling the msr and initializing the hcall
page. The only added gain is that guests which do vmcalls without an hypercall page would
still be handled.

But I am not sure it's worth the trouble. I feel its good the way this is now, given that
this is new behaviour of forward vmmcall/vmcall to userspace.

> +#endif /* __ARCH_X86_KVM_XEN_H__ */> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index ca41220b40b8..00221fe56994 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -216,6 +216,20 @@ struct kvm_hyperv_exit {
>  	} u;
>  };
>  
> +struct kvm_xen_exit {
> +#define KVM_EXIT_XEN_HCALL          1
> +	__u32 type;
> +	union {
> +		struct {
> +			__u32 longmode;
> +			__u32 cpl;
> +			__u64 input;
> +			__u64 result;
> +			__u64 params[6];
> +		} hcall;
> +	} u;
> +};
> +
>  #define KVM_S390_GET_SKEYS_NONE   1
>  #define KVM_S390_SKEYS_MAX        1048576
>  
> @@ -250,6 +264,7 @@ struct kvm_hyperv_exit {
>  #define KVM_EXIT_ARM_NISV         28
>  #define KVM_EXIT_X86_RDMSR        29
>  #define KVM_EXIT_X86_WRMSR        30
> +#define KVM_EXIT_XEN              31
>  
>  /* For KVM_EXIT_INTERNAL_ERROR */
>  /* Emulate instruction failed. */
> @@ -426,6 +441,8 @@ struct kvm_run {
>  			__u32 index; /* kernel -> user */
>  			__u64 data; /* kernel <-> user */
>  		} msr;
> +		/* KVM_EXIT_XEN */
> +		struct kvm_xen_exit xen;
>  		/* Fix the size of the union. */
>  		char padding[256];
>  	};
> @@ -1126,6 +1143,8 @@ struct kvm_x86_mce {
>  #endif
>  
>  #ifdef KVM_CAP_XEN_HVM
> +#define KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL	(1 << 1)
> +

And adding:

#define KVM_XEN_HVM_CONFIG_HYPERCALL_MSR	(1 << 0)

Of course, this is a nit for readability only, but it aligns with what you write
in the docs update you do in the last patch.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 07/15] KVM: x86/xen: add definitions of compat_shared_info, compat_vcpu_info
  2020-12-04  1:18 ` [PATCH 07/15] KVM: x86/xen: add definitions of compat_shared_info, compat_vcpu_info David Woodhouse
@ 2020-12-05 18:43   ` Joao Martins
  2020-12-05 19:48     ` David Woodhouse
  0 siblings, 1 reply; 33+ messages in thread
From: Joao Martins @ 2020-12-05 18:43 UTC (permalink / raw)
  To: David Woodhouse, kvm
  Cc: Paolo Bonzini, Ankur Arora, Boris Ostrovsky, Sean Christopherson

On 12/4/20 1:18 AM, David Woodhouse wrote:
> From: David Woodhouse <dwmw@amazon.co.uk>
> 
> There aren't a lot of differences for the things that the kernel needs
> to care about, but there are a few.
> 
> Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
> ---
>  arch/x86/kvm/xen.h | 39 +++++++++++++++++++++++++++++++++++++++
>  1 file changed, 39 insertions(+)
> 
> diff --git a/arch/x86/kvm/xen.h b/arch/x86/kvm/xen.h
> index afc6dad41fb5..870ac7197a3a 100644
> --- a/arch/x86/kvm/xen.h
> +++ b/arch/x86/kvm/xen.h
> @@ -21,4 +21,43 @@ static inline bool kvm_xen_hypercall_enabled(struct kvm *kvm)
>  		KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL;
>  }
>  
> +
> +/* 32-bit compatibility definitions */
> +#include <asm/pvclock-abi.h>
> +#include <asm/xen/interface.h>
> +
> +struct compat_arch_vcpu_info {
> +	unsigned int cr2;
> +	unsigned int pad[5];
> +};
> +
> +struct compat_vcpu_info {
> +        uint8_t evtchn_upcall_pending;
> +        uint8_t evtchn_upcall_mask;
> +        uint32_t evtchn_pending_sel;
> +        struct compat_arch_vcpu_info arch;
> +        struct pvclock_vcpu_time_info time;
> +}; /* 64 bytes (x86) */
> +
> +struct compat_arch_shared_info {
> +	unsigned int max_pfn;
> +	unsigned int pfn_to_mfn_frame_list_list;
> +	unsigned int nmi_reason;
> +	unsigned int p2m_cr3;
> +	unsigned int p2m_vaddr;
> +	unsigned int p2m_generation;
> +	uint32_t wc_sec_hi;
> +};
> +
> +struct compat_shared_info {
> +	struct compat_vcpu_info vcpu_info[MAX_VIRT_CPUS];
> +	uint32_t evtchn_pending[sizeof(compat_ulong_t) * 8];
> +	uint32_t evtchn_mask[sizeof(compat_ulong_t) * 8];
> +	uint32_t wc_version;
> +	uint32_t wc_sec;
> +	uint32_t wc_nsec;
> +	struct compat_arch_shared_info arch;
> +
> +};
> +
>  #endif /* __ARCH_X86_KVM_XEN_H__ */
> 
I would fold this into the next patch.

For it makes sense to keep separate the xen canonical headers update (patch 10).

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 03/15] KVM: x86/xen: intercept xen hypercalls if enabled
  2020-12-05 18:42   ` Joao Martins
@ 2020-12-05 18:51     ` David Woodhouse
  2020-12-05 19:13       ` Joao Martins
  0 siblings, 1 reply; 33+ messages in thread
From: David Woodhouse @ 2020-12-05 18:51 UTC (permalink / raw)
  To: Joao Martins
  Cc: Paolo Bonzini, Ankur Arora, Boris Ostrovsky, Sean Christopherson, kvm



On 5 December 2020 18:42:53 GMT, Joao Martins <joao.m.martins@oracle.com> wrote:
>On 12/4/20 1:18 AM, David Woodhouse wrote:
>> @@ -3742,6 +3716,9 @@ int kvm_vm_ioctl_check_extension(struct kvm
>*kvm, long ext)
>>  	case KVM_CAP_ENFORCE_PV_FEATURE_CPUID:
>>  		r = 1;
>>  		break;
>> +	case KVM_CAP_XEN_HVM:
>> +		r = 1 | KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL;
>> +		break;
>
>Maybe:
>
>	r = KVM_XEN_HVM_CONFIG_HYPERCALL_MSR |
>		KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL;

Yeah, I already did that as I did the docs. In my tree it's already folded into this patch for when I post v2. Thanks.


>I suppose it makes sense restricting to INTERCEPT_HCALL to make sure
>that the kernel only
>forwards the hcall if it is control off what it put there in the
>hypercall page (i.e.
>vmmcall/vmcall). hcall userspace exiting without INTERCEPT_HCALL would
>break ABI over how
>this ioctl was used before the new flag... In case
>kvm_xen_hypercall_enabled() would
>return true with KVM_XEN_HVM_CONFIG_HYPERCALL_MSR, as now it needs to
>handle a new
>userspace exit.

Right. 

>If we're are being pedantic, the Xen hypercall MSR is a utility more
>than a necessity as
>the OS can always do without the hcall msr IIUC. But it is defacto used
>by enlightened Xen
>guests included FreeBSD.

Not sure about that. Xen doesn't guarantee that the hypercall will be VMCALL; the ABI *is* ",use the hypercall page MSR and call it" I believe.

But if they do just do the VMCALL, that *will* work as I have it, won't it?

>
>And adding:
>
>#define KVM_XEN_HVM_CONFIG_HYPERCALL_MSR	(1 << 0)
>
>Of course, this is a nit for readability only, but it aligns with what
>you write
>in the docs update you do in the last patch.

Yep, already there. Thanks.

-- 
Sent from my Android device with K-9 Mail. Please excuse my brevity.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 03/15] KVM: x86/xen: intercept xen hypercalls if enabled
  2020-12-05 18:51     ` David Woodhouse
@ 2020-12-05 19:13       ` Joao Martins
  0 siblings, 0 replies; 33+ messages in thread
From: Joao Martins @ 2020-12-05 19:13 UTC (permalink / raw)
  To: David Woodhouse
  Cc: Paolo Bonzini, Ankur Arora, Boris Ostrovsky, Sean Christopherson, kvm

On 12/5/20 6:51 PM, David Woodhouse wrote:
> On 5 December 2020 18:42:53 GMT, Joao Martins <joao.m.martins@oracle.com> wrote:
>> I suppose it makes sense restricting to INTERCEPT_HCALL to make sure
>> that the kernel only
>> forwards the hcall if it is control off what it put there in the
>> hypercall page (i.e.
>> vmmcall/vmcall). hcall userspace exiting without INTERCEPT_HCALL would
>> break ABI over how
>> this ioctl was used before the new flag... In case
>> kvm_xen_hypercall_enabled() would
>> return true with KVM_XEN_HVM_CONFIG_HYPERCALL_MSR, as now it needs to
>> handle a new
>> userspace exit.
> 
> Right. 
> 
>> If we're are being pedantic, the Xen hypercall MSR is a utility more
>> than a necessity as
>> the OS can always do without the hcall msr IIUC. But it is defacto used
>> by enlightened Xen
>> guests included FreeBSD.
> 
> Not sure about that. Xen doesn't guarantee that the hypercall will be VMCALL; the ABI *is* ",use the hypercall page MSR and call it" I believe.
> 
You might be right. I had always had the impression that the above was is geared towards
PV guests hypercalls IIRC which are not VMMCALL/VMCALL. Xen doesn't explicitly check you
initialized an hypercall page for HVM guests.

> But if they do just do the VMCALL, that *will* work as I have it, won't it?
> 
It would work indeed.

What I was mentioning is the possibility that you let userspace fill the hcall page data,
while enabling hcall intercept () so 0x3 as xen hvm config flags i.e. you pass a blob with
hcall intercept set.

I think it's good as is given that interception is tied in with what you fill in the hcall
page.

>>
>> And adding:
>>
>> #define KVM_XEN_HVM_CONFIG_HYPERCALL_MSR	(1 << 0)
>>
>> Of course, this is a nit for readability only, but it aligns with what
>> you write
>> in the docs update you do in the last patch.
> 
> Yep, already there. Thanks.
> 

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 07/15] KVM: x86/xen: add definitions of compat_shared_info, compat_vcpu_info
  2020-12-05 18:43   ` Joao Martins
@ 2020-12-05 19:48     ` David Woodhouse
  0 siblings, 0 replies; 33+ messages in thread
From: David Woodhouse @ 2020-12-05 19:48 UTC (permalink / raw)
  To: Joao Martins, kvm
  Cc: Paolo Bonzini, Ankur Arora, Boris Ostrovsky, Sean Christopherson

[-- Attachment #1: Type: text/plain, Size: 492 bytes --]

On Sat, 2020-12-05 at 18:43 +0000, Joao Martins wrote:
> I would fold this into the next patch.

Except it's not just the next patch; it's piecemeal across the next
three or four. I started out that way but figured it was better to add
them in one go.

> For it makes sense to keep separate the xen canonical headers update
> (patch 10).

Right, that affects the structures used for Xen guests too (albeit not
really since we don't use that field). That one is indeed separate.


[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 5174 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

end of thread, other threads:[~2020-12-05 19:49 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-04  1:18 [PATCH 00/15] KVM: Add Xen hypercall and shared info pages David Woodhouse
2020-12-04  1:18 ` [PATCH 01/15] KVM: Fix arguments to kvm_{un,}map_gfn() David Woodhouse
2020-12-04 18:27   ` Alexander Graf
2020-12-04 19:02     ` David Woodhouse
2020-12-04  1:18 ` [PATCH 02/15] KVM: x86/xen: fix Xen hypercall page msr handling David Woodhouse
2020-12-04 18:26   ` Alexander Graf
2020-12-04 18:54     ` David Woodhouse
2020-12-04  1:18 ` [PATCH 03/15] KVM: x86/xen: intercept xen hypercalls if enabled David Woodhouse
2020-12-04 18:26   ` Alexander Graf
2020-12-04 18:58     ` David Woodhouse
2020-12-05 18:42   ` Joao Martins
2020-12-05 18:51     ` David Woodhouse
2020-12-05 19:13       ` Joao Martins
2020-12-04  1:18 ` [PATCH 04/15] KVM: x86/xen: Fix coexistence of Xen and Hyper-V hypercalls David Woodhouse
2020-12-04 18:34   ` Alexander Graf
2020-12-04 19:04     ` David Woodhouse
2020-12-04  1:18 ` [PATCH 05/15] KVM: x86/xen: add KVM_XEN_HVM_SET_ATTR/KVM_XEN_HVM_GET_ATTR David Woodhouse
2020-12-04  1:18 ` [PATCH 06/15] KVM: x86/xen: latch long_mode when hypercall page is set up David Woodhouse
2020-12-04 18:38   ` Alexander Graf
2020-12-04 19:08     ` David Woodhouse
2020-12-04  1:18 ` [PATCH 07/15] KVM: x86/xen: add definitions of compat_shared_info, compat_vcpu_info David Woodhouse
2020-12-05 18:43   ` Joao Martins
2020-12-05 19:48     ` David Woodhouse
2020-12-04  1:18 ` [PATCH 08/15] KVM: x86/xen: register shared_info page David Woodhouse
2020-12-04  1:18 ` [PATCH 09/15] KVM: x86/xen: setup pvclock updates David Woodhouse
2020-12-04  1:18 ` [PATCH 10/15] xen: add wc_sec_hi to struct shared_info David Woodhouse
2020-12-04  1:18 ` [PATCH 11/15] KVM: x86/xen: update wallclock region David Woodhouse
2020-12-04  1:18 ` [PATCH 12/15] KVM: x86/xen: register vcpu info David Woodhouse
2020-12-04  1:18 ` [PATCH 13/15] KVM: x86/xen: register vcpu time info region David Woodhouse
2020-12-04  1:18 ` [PATCH 14/15] KVM: x86/xen: register runstate info David Woodhouse
2020-12-04  1:18 ` [PATCH 15/15] KVM: x86: declare Xen HVM shared info capability and add test case David Woodhouse
2020-12-04  9:11 ` [PATCH 16/15] KVM: Add documentation for Xen hypercall and shared_info updates David Woodhouse
2020-12-05 10:48 ` [PATCH 00/15] KVM: Add Xen hypercall and shared info pages David Woodhouse

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.