aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/i386/kvm/xen_evtchn.c25
-rw-r--r--hw/i386/kvm/xen_evtchn.h11
-rw-r--r--target/i386/kvm/xen-compat.h19
-rw-r--r--target/i386/kvm/xen-emu.c118
4 files changed, 173 insertions, 0 deletions
diff --git a/hw/i386/kvm/xen_evtchn.c b/hw/i386/kvm/xen_evtchn.c
index 6c39627..b95ee9b 100644
--- a/hw/i386/kvm/xen_evtchn.c
+++ b/hw/i386/kvm/xen_evtchn.c
@@ -1349,6 +1349,31 @@ int xen_evtchn_set_port(uint16_t port)
return ret;
}
+int xen_physdev_map_pirq(struct physdev_map_pirq *map)
+{
+ return -ENOTSUP;
+}
+
+int xen_physdev_unmap_pirq(struct physdev_unmap_pirq *unmap)
+{
+ return -ENOTSUP;
+}
+
+int xen_physdev_eoi_pirq(struct physdev_eoi *eoi)
+{
+ return -ENOTSUP;
+}
+
+int xen_physdev_query_pirq(struct physdev_irq_status_query *query)
+{
+ return -ENOTSUP;
+}
+
+int xen_physdev_get_free_pirq(struct physdev_get_free_pirq *get)
+{
+ return -ENOTSUP;
+}
+
struct xenevtchn_handle *xen_be_evtchn_open(void)
{
struct xenevtchn_handle *xc = g_new0(struct xenevtchn_handle, 1);
diff --git a/hw/i386/kvm/xen_evtchn.h b/hw/i386/kvm/xen_evtchn.h
index 5a71ffb..352c875 100644
--- a/hw/i386/kvm/xen_evtchn.h
+++ b/hw/i386/kvm/xen_evtchn.h
@@ -62,4 +62,15 @@ int xen_evtchn_bind_interdomain_op(struct evtchn_bind_interdomain *interdomain);
int xen_evtchn_bind_vcpu_op(struct evtchn_bind_vcpu *vcpu);
int xen_evtchn_reset_op(struct evtchn_reset *reset);
+struct physdev_map_pirq;
+struct physdev_unmap_pirq;
+struct physdev_eoi;
+struct physdev_irq_status_query;
+struct physdev_get_free_pirq;
+int xen_physdev_map_pirq(struct physdev_map_pirq *map);
+int xen_physdev_unmap_pirq(struct physdev_unmap_pirq *unmap);
+int xen_physdev_eoi_pirq(struct physdev_eoi *eoi);
+int xen_physdev_query_pirq(struct physdev_irq_status_query *query);
+int xen_physdev_get_free_pirq(struct physdev_get_free_pirq *get);
+
#endif /* QEMU_XEN_EVTCHN_H */
diff --git a/target/i386/kvm/xen-compat.h b/target/i386/kvm/xen-compat.h
index 448336d..7f30180 100644
--- a/target/i386/kvm/xen-compat.h
+++ b/target/i386/kvm/xen-compat.h
@@ -48,4 +48,23 @@ struct compat_xen_add_to_physmap_batch {
COMPAT_HANDLE(int) errs;
};
+struct compat_physdev_map_pirq {
+ domid_t domid;
+ uint16_t pad;
+ /* IN */
+ int type;
+ /* IN (ignored for ..._MULTI_MSI) */
+ int index;
+ /* IN or OUT */
+ int pirq;
+ /* IN - high 16 bits hold segment for ..._MSI_SEG and ..._MULTI_MSI */
+ int bus;
+ /* IN */
+ int devfn;
+ /* IN (also OUT for ..._MULTI_MSI) */
+ int entry_nr;
+ /* IN */
+ uint64_t table_base;
+} __attribute__((packed));
+
#endif /* QEMU_I386_XEN_COMPAT_H */
diff --git a/target/i386/kvm/xen-emu.c b/target/i386/kvm/xen-emu.c
index 50965b5..fe15696 100644
--- a/target/i386/kvm/xen-emu.c
+++ b/target/i386/kvm/xen-emu.c
@@ -1539,6 +1539,121 @@ static bool kvm_xen_hcall_gnttab_op(struct kvm_xen_exit *exit, X86CPU *cpu,
return true;
}
+static bool kvm_xen_hcall_physdev_op(struct kvm_xen_exit *exit, X86CPU *cpu,
+ int cmd, uint64_t arg)
+{
+ CPUState *cs = CPU(cpu);
+ int err;
+
+ switch (cmd) {
+ case PHYSDEVOP_map_pirq: {
+ struct physdev_map_pirq map;
+
+ if (hypercall_compat32(exit->u.hcall.longmode)) {
+ struct compat_physdev_map_pirq *map32 = (void *)↦
+
+ if (kvm_copy_from_gva(cs, arg, map32, sizeof(*map32))) {
+ return -EFAULT;
+ }
+
+ /*
+ * The only thing that's different is the alignment of the
+ * uint64_t table_base at the end, which gets padding to make
+ * it 64-bit aligned in the 64-bit version.
+ */
+ qemu_build_assert(sizeof(*map32) == 36);
+ qemu_build_assert(offsetof(struct physdev_map_pirq, entry_nr) ==
+ offsetof(struct compat_physdev_map_pirq, entry_nr));
+ memmove(&map.table_base, &map32->table_base, sizeof(map.table_base));
+ } else {
+ if (kvm_copy_from_gva(cs, arg, &map, sizeof(map))) {
+ err = -EFAULT;
+ break;
+ }
+ }
+ err = xen_physdev_map_pirq(&map);
+ /*
+ * Since table_base is an IN parameter and won't be changed, just
+ * copy the size of the compat structure back to the guest.
+ */
+ if (!err && kvm_copy_to_gva(cs, arg, &map,
+ sizeof(struct compat_physdev_map_pirq))) {
+ err = -EFAULT;
+ }
+ break;
+ }
+ case PHYSDEVOP_unmap_pirq: {
+ struct physdev_unmap_pirq unmap;
+
+ qemu_build_assert(sizeof(unmap) == 8);
+ if (kvm_copy_from_gva(cs, arg, &unmap, sizeof(unmap))) {
+ err = -EFAULT;
+ break;
+ }
+
+ err = xen_physdev_unmap_pirq(&unmap);
+ if (!err && kvm_copy_to_gva(cs, arg, &unmap, sizeof(unmap))) {
+ err = -EFAULT;
+ }
+ break;
+ }
+ case PHYSDEVOP_eoi: {
+ struct physdev_eoi eoi;
+
+ qemu_build_assert(sizeof(eoi) == 4);
+ if (kvm_copy_from_gva(cs, arg, &eoi, sizeof(eoi))) {
+ err = -EFAULT;
+ break;
+ }
+
+ err = xen_physdev_eoi_pirq(&eoi);
+ if (!err && kvm_copy_to_gva(cs, arg, &eoi, sizeof(eoi))) {
+ err = -EFAULT;
+ }
+ break;
+ }
+ case PHYSDEVOP_irq_status_query: {
+ struct physdev_irq_status_query query;
+
+ qemu_build_assert(sizeof(query) == 8);
+ if (kvm_copy_from_gva(cs, arg, &query, sizeof(query))) {
+ err = -EFAULT;
+ break;
+ }
+
+ err = xen_physdev_query_pirq(&query);
+ if (!err && kvm_copy_to_gva(cs, arg, &query, sizeof(query))) {
+ err = -EFAULT;
+ }
+ break;
+ }
+ case PHYSDEVOP_get_free_pirq: {
+ struct physdev_get_free_pirq get;
+
+ qemu_build_assert(sizeof(get) == 8);
+ if (kvm_copy_from_gva(cs, arg, &get, sizeof(get))) {
+ err = -EFAULT;
+ break;
+ }
+
+ err = xen_physdev_get_free_pirq(&get);
+ if (!err && kvm_copy_to_gva(cs, arg, &get, sizeof(get))) {
+ err = -EFAULT;
+ }
+ break;
+ }
+ case PHYSDEVOP_pirq_eoi_gmfn_v2: /* FreeBSD 13 makes this hypercall */
+ err = -ENOSYS;
+ break;
+
+ default:
+ return false;
+ }
+
+ exit->u.hcall.result = err;
+ return true;
+}
+
static bool do_kvm_xen_handle_exit(X86CPU *cpu, struct kvm_xen_exit *exit)
{
uint16_t code = exit->u.hcall.input;
@@ -1580,6 +1695,9 @@ static bool do_kvm_xen_handle_exit(X86CPU *cpu, struct kvm_xen_exit *exit)
case __HYPERVISOR_memory_op:
return kvm_xen_hcall_memory_op(exit, cpu, exit->u.hcall.params[0],
exit->u.hcall.params[1]);
+ case __HYPERVISOR_physdev_op:
+ return kvm_xen_hcall_physdev_op(exit, cpu, exit->u.hcall.params[0],
+ exit->u.hcall.params[1]);
case __HYPERVISOR_xen_version:
return kvm_xen_hcall_xen_version(exit, cpu, exit->u.hcall.params[0],
exit->u.hcall.params[1]);