ddf0fd9ae1
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>
45 lines
1.4 KiB
C
45 lines
1.4 KiB
C
/*
|
|
* 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
|
|
|
|
#include "hw/sysbus.h"
|
|
|
|
void xen_evtchn_create(void);
|
|
int xen_evtchn_soft_reset(void);
|
|
int xen_evtchn_set_callback_param(uint64_t param);
|
|
void xen_evtchn_connect_gsis(qemu_irq *system_gsis);
|
|
void xen_evtchn_set_callback_level(int level);
|
|
|
|
struct evtchn_status;
|
|
struct evtchn_close;
|
|
struct evtchn_unmask;
|
|
struct evtchn_bind_virq;
|
|
struct evtchn_bind_ipi;
|
|
struct evtchn_send;
|
|
struct evtchn_alloc_unbound;
|
|
struct evtchn_bind_interdomain;
|
|
struct evtchn_bind_vcpu;
|
|
struct evtchn_reset;
|
|
int xen_evtchn_status_op(struct evtchn_status *status);
|
|
int xen_evtchn_close_op(struct evtchn_close *close);
|
|
int xen_evtchn_unmask_op(struct evtchn_unmask *unmask);
|
|
int xen_evtchn_bind_virq_op(struct evtchn_bind_virq *virq);
|
|
int xen_evtchn_bind_ipi_op(struct evtchn_bind_ipi *ipi);
|
|
int xen_evtchn_send_op(struct evtchn_send *send);
|
|
int xen_evtchn_alloc_unbound_op(struct evtchn_alloc_unbound *alloc);
|
|
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);
|
|
|
|
#endif /* QEMU_XEN_EVTCHN_H */
|