--- /dev/null
+/* 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
#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>
#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"
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)
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;
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;
+}