2022-12-16 17:02:29 +03:00
|
|
|
/*
|
|
|
|
* QEMU Xen emulation: Event channel support
|
|
|
|
*
|
|
|
|
* Copyright © 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Authors: David Woodhouse <dwmw2@infradead.org>
|
|
|
|
*
|
|
|
|
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
|
|
|
* See the COPYING file in the top-level directory.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef QEMU_XEN_EVTCHN_H
|
|
|
|
#define QEMU_XEN_EVTCHN_H
|
|
|
|
|
hw/xen: Support HVM_PARAM_CALLBACK_TYPE_GSI callback
The GSI callback (and later PCI_INTX) is a level triggered interrupt. It
is asserted when an event channel is delivered to vCPU0, and is supposed
to be cleared when the vcpu_info->evtchn_upcall_pending field for vCPU0
is cleared again.
Thankfully, Xen does *not* assert the GSI if the guest sets its own
evtchn_upcall_pending field; we only need to assert the GSI when we
have delivered an event for ourselves. So that's the easy part, kind of.
There's a slight complexity in that we need to hold the BQL before we
can call qemu_set_irq(), and we definitely can't do that while holding
our own port_lock (because we'll need to take that from the qemu-side
functions that the PV backend drivers will call). So if we end up
wanting to set the IRQ in a context where we *don't* already hold the
BQL, defer to a BH.
However, we *do* need to poll for the evtchn_upcall_pending flag being
cleared. In an ideal world we would poll that when the EOI happens on
the PIC/IOAPIC. That's how it works in the kernel with the VFIO eventfd
pairs — one is used to trigger the interrupt, and the other works in the
other direction to 'resample' on EOI, and trigger the first eventfd
again if the line is still active.
However, QEMU doesn't seem to do that. Even VFIO level interrupts seem
to be supported by temporarily unmapping the device's BARs from the
guest when an interrupt happens, then trapping *all* MMIO to the device
and sending the 'resample' event on *every* MMIO access until the IRQ
is cleared! Maybe in future we'll plumb the 'resample' concept through
QEMU's irq framework but for now we'll do what Xen itself does: just
check the flag on every vmexit if the upcall GSI is known to be
asserted.
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
Reviewed-by: Paul Durrant <paul@xen.org>
2022-12-15 23:35:24 +03:00
|
|
|
#include "hw/sysbus.h"
|
|
|
|
|
2022-12-28 00:20:07 +03:00
|
|
|
typedef uint32_t evtchn_port_t;
|
|
|
|
|
hw/xen: Simplify emulated Xen platform init
I initially put the basic platform init (overlay pages, grant tables,
event channels) into mc->kvm_type because that was the earliest place
that could sensibly test for xen_mode==XEN_EMULATE.
The intent was to do this early enough that we could then initialise the
XenBus and other parts which would have depended on them, from a generic
location for both Xen and KVM/Xen in the PC-specific code, as seen in
https://lore.kernel.org/qemu-devel/20230116221919.1124201-16-dwmw2@infradead.org/
However, then the Xen on Arm patches came along, and *they* wanted to
do the XenBus init from a 'generic' Xen-specific location instead:
https://lore.kernel.org/qemu-devel/20230210222729.957168-4-sstabellini@kernel.org/
Since there's no generic location that covers all three, I conceded to
do it for XEN_EMULATE mode in pc_basic_devices_init().
And now there's absolutely no point in having some of the platform init
done from pc_machine_kvm_type(); we can move it all up to live in a
single place in pc_basic_devices_init(). This has the added benefit that
we can drop the separate xen_evtchn_connect_gsis() function completely,
and pass just the system GSIs in directly to xen_evtchn_create().
While I'm at it, it does no harm to explicitly pass in the *number* of
said GSIs, because it does make me twitch a bit to pass an array of
impicit size. During the lifetime of the KVM/Xen patchset, that had
already changed (albeit just cosmetically) from GSI_NUM_PINS to
IOAPIC_NUM_PINS.
And document a bit better that this is for the *output* GSI for raising
CPU0's events when the per-CPU vector isn't available. The fact that
we create a whole set of them and then only waggle the one we're told
to, instead of having a single output and only *connecting* it to the
GSI that it should be connected to, is still non-intuitive for me.
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
Reviewed-by: Paul Durrant <paul@xen.org>
Message-Id: <20230412185102.441523-2-dwmw2@infradead.org>
Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
2023-04-12 21:50:58 +03:00
|
|
|
void xen_evtchn_create(unsigned int nr_gsis, qemu_irq *system_gsis);
|
2022-12-14 22:36:15 +03:00
|
|
|
int xen_evtchn_soft_reset(void);
|
2022-12-16 17:02:29 +03:00
|
|
|
int xen_evtchn_set_callback_param(uint64_t param);
|
hw/xen: Support HVM_PARAM_CALLBACK_TYPE_GSI callback
The GSI callback (and later PCI_INTX) is a level triggered interrupt. It
is asserted when an event channel is delivered to vCPU0, and is supposed
to be cleared when the vcpu_info->evtchn_upcall_pending field for vCPU0
is cleared again.
Thankfully, Xen does *not* assert the GSI if the guest sets its own
evtchn_upcall_pending field; we only need to assert the GSI when we
have delivered an event for ourselves. So that's the easy part, kind of.
There's a slight complexity in that we need to hold the BQL before we
can call qemu_set_irq(), and we definitely can't do that while holding
our own port_lock (because we'll need to take that from the qemu-side
functions that the PV backend drivers will call). So if we end up
wanting to set the IRQ in a context where we *don't* already hold the
BQL, defer to a BH.
However, we *do* need to poll for the evtchn_upcall_pending flag being
cleared. In an ideal world we would poll that when the EOI happens on
the PIC/IOAPIC. That's how it works in the kernel with the VFIO eventfd
pairs — one is used to trigger the interrupt, and the other works in the
other direction to 'resample' on EOI, and trigger the first eventfd
again if the line is still active.
However, QEMU doesn't seem to do that. Even VFIO level interrupts seem
to be supported by temporarily unmapping the device's BARs from the
guest when an interrupt happens, then trapping *all* MMIO to the device
and sending the 'resample' event on *every* MMIO access until the IRQ
is cleared! Maybe in future we'll plumb the 'resample' concept through
QEMU's irq framework but for now we'll do what Xen itself does: just
check the flag on every vmexit if the upcall GSI is known to be
asserted.
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
Reviewed-by: Paul Durrant <paul@xen.org>
2022-12-15 23:35:24 +03:00
|
|
|
void xen_evtchn_set_callback_level(int level);
|
2022-12-16 17:02:29 +03:00
|
|
|
|
2018-09-17 14:04:54 +03:00
|
|
|
int xen_evtchn_set_port(uint16_t port);
|
|
|
|
|
2023-01-13 23:41:19 +03:00
|
|
|
bool xen_evtchn_set_gsi(int gsi, int level);
|
2023-01-14 02:35:46 +03:00
|
|
|
void xen_evtchn_snoop_msi(PCIDevice *dev, bool is_msix, unsigned int vector,
|
|
|
|
uint64_t addr, uint32_t data, bool is_masked);
|
|
|
|
void xen_evtchn_remove_pci_device(PCIDevice *dev);
|
|
|
|
struct kvm_irq_routing_entry;
|
|
|
|
int xen_evtchn_translate_pirq_msi(struct kvm_irq_routing_entry *route,
|
|
|
|
uint64_t address, uint32_t data);
|
|
|
|
bool xen_evtchn_deliver_pirq_msi(uint64_t address, uint32_t data);
|
|
|
|
|
2023-01-13 23:41:19 +03:00
|
|
|
|
2022-12-28 00:20:07 +03:00
|
|
|
/*
|
|
|
|
* These functions mirror the libxenevtchn library API, providing the QEMU
|
|
|
|
* backend side of "interdomain" event channels.
|
|
|
|
*/
|
|
|
|
struct xenevtchn_handle;
|
|
|
|
struct xenevtchn_handle *xen_be_evtchn_open(void);
|
|
|
|
int xen_be_evtchn_bind_interdomain(struct xenevtchn_handle *xc, uint32_t domid,
|
|
|
|
evtchn_port_t guest_port);
|
|
|
|
int xen_be_evtchn_unbind(struct xenevtchn_handle *xc, evtchn_port_t port);
|
|
|
|
int xen_be_evtchn_close(struct xenevtchn_handle *xc);
|
|
|
|
int xen_be_evtchn_fd(struct xenevtchn_handle *xc);
|
|
|
|
int xen_be_evtchn_notify(struct xenevtchn_handle *xc, evtchn_port_t port);
|
|
|
|
int xen_be_evtchn_unmask(struct xenevtchn_handle *xc, evtchn_port_t port);
|
|
|
|
int xen_be_evtchn_pending(struct xenevtchn_handle *xc);
|
|
|
|
/* Apart from this which is a local addition */
|
|
|
|
int xen_be_evtchn_get_guest_port(struct xenevtchn_handle *xc);
|
|
|
|
|
2022-12-13 16:29:46 +03:00
|
|
|
struct evtchn_status;
|
2022-12-13 16:57:44 +03:00
|
|
|
struct evtchn_close;
|
2022-12-13 20:20:46 +03:00
|
|
|
struct evtchn_unmask;
|
2022-12-14 01:40:56 +03:00
|
|
|
struct evtchn_bind_virq;
|
2023-01-13 22:51:32 +03:00
|
|
|
struct evtchn_bind_pirq;
|
2022-12-14 02:12:59 +03:00
|
|
|
struct evtchn_bind_ipi;
|
2022-12-14 03:11:07 +03:00
|
|
|
struct evtchn_send;
|
2022-12-14 19:39:48 +03:00
|
|
|
struct evtchn_alloc_unbound;
|
2022-12-14 20:26:32 +03:00
|
|
|
struct evtchn_bind_interdomain;
|
2022-12-14 22:27:38 +03:00
|
|
|
struct evtchn_bind_vcpu;
|
2022-12-14 22:36:15 +03:00
|
|
|
struct evtchn_reset;
|
2022-12-13 16:29:46 +03:00
|
|
|
int xen_evtchn_status_op(struct evtchn_status *status);
|
2022-12-13 16:57:44 +03:00
|
|
|
int xen_evtchn_close_op(struct evtchn_close *close);
|
2022-12-13 20:20:46 +03:00
|
|
|
int xen_evtchn_unmask_op(struct evtchn_unmask *unmask);
|
2022-12-14 01:40:56 +03:00
|
|
|
int xen_evtchn_bind_virq_op(struct evtchn_bind_virq *virq);
|
2023-01-13 22:51:32 +03:00
|
|
|
int xen_evtchn_bind_pirq_op(struct evtchn_bind_pirq *pirq);
|
2022-12-14 02:12:59 +03:00
|
|
|
int xen_evtchn_bind_ipi_op(struct evtchn_bind_ipi *ipi);
|
2022-12-14 03:11:07 +03:00
|
|
|
int xen_evtchn_send_op(struct evtchn_send *send);
|
2022-12-14 19:39:48 +03:00
|
|
|
int xen_evtchn_alloc_unbound_op(struct evtchn_alloc_unbound *alloc);
|
2022-12-14 20:26:32 +03:00
|
|
|
int xen_evtchn_bind_interdomain_op(struct evtchn_bind_interdomain *interdomain);
|
2022-12-14 22:27:38 +03:00
|
|
|
int xen_evtchn_bind_vcpu_op(struct evtchn_bind_vcpu *vcpu);
|
2022-12-14 22:36:15 +03:00
|
|
|
int xen_evtchn_reset_op(struct evtchn_reset *reset);
|
2022-12-13 16:29:46 +03:00
|
|
|
|
2023-01-13 03:24:40 +03:00
|
|
|
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);
|
|
|
|
|
2022-12-16 17:02:29 +03:00
|
|
|
#endif /* QEMU_XEN_EVTCHN_H */
|