@@ -1669,4 +1669,7 @@ static inline int kvm_cpu_get_apicid(int mps_cpu)
#define put_smstate(type, buf, offset, val) \
*(type *)((buf) + (offset) - 0x7e00) = val
+void kvm_xen_register_lcall(struct kvm_xen *shim);
+void kvm_xen_unregister_lcall(void);
+
#endif /* _ASM_X86_KVM_HOST_H */
@@ -10,7 +10,7 @@ kvm-$(CONFIG_KVM_ASYNC_PF) += $(KVM)/async_pf.o
kvm-y += x86.o mmu.o emulate.o i8259.o irq.o lapic.o \
i8254.o ioapic.o irq_comm.o cpuid.o pmu.o mtrr.o \
- hyperv.o xen.o page_track.o debugfs.o
+ hyperv.o xen-asm.o xen.o page_track.o debugfs.o
kvm-intel-y += vmx/vmx.o vmx/vmenter.o vmx/pmu_intel.o vmx/vmcs12.o vmx/evmcs.o vmx/nested.o
kvm-amd-y += svm.o pmu_amd.o
new file mode 100644
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved. */
+#include <linux/linkage.h>
+#include <asm/asm.h>
+#include <asm/frame.h>
+#include <asm/page_types.h>
+#include <asm/unwind_hints.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/xen-mca.h>
+#include <asm/xen/interface.h>
+
+ .balign PAGE_SIZE
+ENTRY(kvm_xen_hypercall_page)
+ hcall=0
+ .rept (PAGE_SIZE / 32)
+ FRAME_BEGIN
+ push %rcx /* Push call clobbered registers */
+ push %r9
+ push %r11
+ mov $hcall, %rax
+
+ call kvm_xen_host_hcall
+ pop %r11
+ pop %r9
+ pop %rcx
+
+ FRAME_END
+ ret
+ .balign 32
+ hcall = hcall + 1
+ .endr
+/*
+ * Hypercall symbols are used for unwinding the stack, so we give them names
+ * prefixed with kvm_xen_ (Xen hypercalls have symbols prefixed with xen_.)
+ */
+#define HYPERCALL(n) \
+ .equ kvm_xen_hypercall_##n, kvm_xen_hypercall_page + __HYPERVISOR_##n * 32; \
+ .type kvm_xen_hypercall_##n, @function; \
+ .size kvm_xen_hypercall_##n, 32
+#include <asm/xen-hypercalls.h>
+#undef HYPERCALL
+END(kvm_xen_hypercall_page)
+
+/*
+ * Some call stubs generated above do not have associated symbols. Generate
+ * bogus symbols for those hypercall blocks to stop objtool from complaining
+ * about unreachable code.
+ */
+.altmacro
+.macro hypercall_missing N
+ .equ kvm_xen_hypercall_missing_\N, kvm_xen_hypercall_page + \N * 32;
+ .type kvm_xen_hypercall_missing_\N, @function;
+ .size kvm_xen_hypercall_missing_\N, 32;
+.endm
+
+.macro hypercalls_missing N count=1
+ .set n,\N
+ .rept \count
+ hypercall_missing %n
+ .set n,n+1
+ .endr
+.endm
+
+hypercalls_missing 11 1
+hypercalls_missing 42 6
+hypercalls_missing 56 72
@@ -12,6 +12,7 @@
#include <linux/kvm_host.h>
#include <linux/eventfd.h>
#include <linux/sched/stat.h>
+#include <linux/linkage.h>
#include <trace/events/kvm.h>
#include <xen/interface/xen.h>
@@ -19,6 +20,10 @@
#include <xen/interface/event_channel.h>
#include <xen/interface/grant_table.h>
#include <xen/interface/sched.h>
+#include <xen/interface/version.h>
+#include <xen/xen.h>
+#include <xen/features.h>
+#include <asm/xen/hypercall.h>
#include "trace.h"
@@ -43,6 +48,7 @@ struct evtchnfd {
static int kvm_xen_evtchn_send(struct kvm_vcpu *vcpu, int port);
static void *xen_vcpu_info(struct kvm_vcpu *v);
static void kvm_xen_gnttab_free(struct kvm_xen *xen);
+static int shim_hypercall(u64 code, u64 a0, u64 a1, u64 a2, u64 a3, u64 a4);
#define XEN_DOMID_MIN 1
#define XEN_DOMID_MAX (DOMID_FIRST_RESERVED - 1)
@@ -50,6 +56,9 @@ static void kvm_xen_gnttab_free(struct kvm_xen *xen);
static rwlock_t domid_lock;
static struct idr domid_to_kvm;
+static struct hypercall_entry *hypercall_page_save;
+static struct kvm_xen *xen_shim __read_mostly;
+
static int kvm_xen_domid_init(struct kvm *kvm, bool any, domid_t domid)
{
u16 min = XEN_DOMID_MIN, max = XEN_DOMID_MAX;
@@ -1271,3 +1280,62 @@ int kvm_vm_ioctl_xen_gnttab(struct kvm *kvm, struct kvm_xen_gnttab *op)
return r;
}
+
+asmlinkage int kvm_xen_host_hcall(void)
+{
+ register unsigned long a0 asm(__HYPERCALL_RETREG);
+ register unsigned long a1 asm(__HYPERCALL_ARG1REG);
+ register unsigned long a2 asm(__HYPERCALL_ARG2REG);
+ register unsigned long a3 asm(__HYPERCALL_ARG3REG);
+ register unsigned long a4 asm(__HYPERCALL_ARG4REG);
+ register unsigned long a5 asm(__HYPERCALL_ARG5REG);
+ int ret;
+
+ preempt_disable();
+ ret = shim_hypercall(a0, a1, a2, a3, a4, a5);
+ preempt_enable();
+
+ return ret;
+}
+
+void kvm_xen_register_lcall(struct kvm_xen *shim)
+{
+ hypercall_page_save = hypercall_page;
+ hypercall_page = kvm_xen_hypercall_page;
+ xen_shim = shim;
+}
+EXPORT_SYMBOL_GPL(kvm_xen_register_lcall);
+
+void kvm_xen_unregister_lcall(void)
+{
+ hypercall_page = hypercall_page_save;
+ hypercall_page_save = NULL;
+}
+EXPORT_SYMBOL_GPL(kvm_xen_unregister_lcall);
+
+static int shim_hcall_version(int op, struct xen_feature_info *fi)
+{
+ if (op != XENVER_get_features || !fi || fi->submap_idx != 0)
+ return -EINVAL;
+
+ /*
+ * We need a limited set of features for a pseudo dom0.
+ */
+ fi->submap = (1U << XENFEAT_auto_translated_physmap);
+ return 0;
+}
+
+static int shim_hypercall(u64 code, u64 a0, u64 a1, u64 a2, u64 a3, u64 a4)
+{
+ int ret = -ENOSYS;
+
+ switch (code) {
+ case __HYPERVISOR_xen_version:
+ ret = shim_hcall_version((int)a0, (void *)a1);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
@@ -3,6 +3,8 @@
#ifndef __ARCH_X86_KVM_XEN_H__
#define __ARCH_X86_KVM_XEN_H__
+#include <asm/xen/hypercall.h>
+
static inline struct kvm_vcpu_xen *vcpu_to_xen_vcpu(struct kvm_vcpu *vcpu)
{
return &vcpu->arch.xen;
@@ -48,4 +50,6 @@ int kvm_xen_has_pending_timer(struct kvm_vcpu *vcpu);
void kvm_xen_inject_timer_irqs(struct kvm_vcpu *vcpu);
bool kvm_xen_timer_enabled(struct kvm_vcpu *vcpu);
+extern struct hypercall_entry kvm_xen_hypercall_page[128];
+
#endif