#include "sysemu/sysemu.h"
#include "trace.h"
+XenDeviceHandler *xen_dev_handler;
+
static char *xen_device_get_backend_path(XenDevice *xendev)
{
XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
XenEventChannel *channel = g_new0(XenEventChannel, 1);
xenevtchn_port_or_error_t local_port;
+ if ((xen_mode == XEN_EMULATE) &&
+ !xen_dev_handler(port, handler, opaque)) {
+ local_port = port;
+ goto emulate;
+ }
+
local_port = xenevtchn_bind_interdomain(xendev->xeh,
xendev->frontend_id,
port);
return NULL;
}
+emulate:
channel->local_port = local_port;
channel->handler = handler;
channel->opaque = opaque;
return;
}
+ if ((xen_mode == XEN_EMULATE) && xen_gnt_ops.send_notify) {
+ xen_gnt_ops.send_notify(xendev, channel->local_port, errp);
+ return;
+ }
+
if (xenevtchn_notify(xendev->xeh, channel->local_port) < 0) {
error_setg_errno(errp, errno, "xenevtchn_notify failed");
}
notifier_remove(&channel->notifier);
- if (xenevtchn_unbind(xendev->xeh, channel->local_port) < 0) {
+ if ((xen_mode != XEN_EMULATE) &&
+ xenevtchn_unbind(xendev->xeh, channel->local_port) < 0) {
error_setg_errno(errp, errno, "xenevtchn_unbind failed");
}
/* ------------------------------------------------------------- */
/* public */
+XenEvtchnHandler *xen_legacy_handler;
struct xs_handle *xenstore;
const char *xen_protocol;
return rc;
}
+int xen_send_notify(struct XenLegacyDevice *xendev)
+{
+ return xenevtchn_notify(xendev->evtchndev, xendev->local_port);
+}
+
struct XenLegacyBackendOps xen_legacy_gnt_ops = {
.set_max_grefs = xen_set_max_grant_refs,
.map_grefs = xen_map_grant_refs,
.unmap_grefs = xen_unmap_grant_refs,
.copy_grefs = xen_copy_grant_refs,
+ .send_notify = xen_send_notify,
};
void xen_be_set_max_grant_refs(struct XenLegacyDevice *xendev,
if (xendev->local_port != -1) {
return 0;
}
+
+ if ((xen_mode == XEN_EMULATE) &&
+ !xen_legacy_handler(xendev->remote_port, xendev->ops->event, xendev)) {
+ xendev->local_port = xendev->remote_port;
+ return 0;
+ }
+
xendev->local_port = xenevtchn_bind_interdomain
(xendev->evtchndev, xendev->dom, xendev->remote_port);
if (xendev->local_port == -1) {
void xen_pv_unbind_evtchn(struct XenLegacyDevice *xendev)
{
- if (xendev->local_port == -1) {
+ if (xendev->local_port == -1 ||
+ xen_mode == XEN_EMULATE) {
return;
}
qemu_set_fd_handler(xenevtchn_fd(xendev->evtchndev), NULL, NULL, NULL);
int xen_pv_send_notify(struct XenLegacyDevice *xendev)
{
- return xenevtchn_notify(xendev->evtchndev, xendev->local_port);
+ return xen_legacy_gnt_ops.send_notify(xendev);
}
/* ------------------------------------------------------------- */
void (*copy_grefs)(struct XenDevice *xendev, bool to_domain,
XenDeviceGrantCopySegment segs[], unsigned int nr_segs,
Error **errp);
+ void (*send_notify)(struct XenDevice *xendev, int port, Error **errp);
};
+typedef int XenDeviceHandler(int port, XenEventHandler cb, void *opaque);
+
extern struct XenBackendOps xen_gnt_ops;
+extern XenDeviceHandler *xen_dev_handler;
#endif /* HW_XEN_BUS_H */
#define XENBACKEND_DEVICE(obj) \
OBJECT_CHECK(XenLegacyDevice, (obj), TYPE_XENBACKEND)
+typedef void XenLegacyDeviceHandler(struct XenLegacyDevice *device);
+typedef int XenEvtchnHandler(int port, XenLegacyDeviceHandler *cb,
+ struct XenLegacyDevice *dev);
+
/* variables */
extern struct xs_handle *xenstore;
extern const char *xen_protocol;
extern DeviceState *xen_sysdev;
extern BusState *xen_sysbus;
+extern XenEvtchnHandler *xen_legacy_handler;
int xenstore_mkdir(char *path, int p);
int xenstore_write_be_str(struct XenLegacyDevice *xendev, const char *node,
return xen_be_unmap_grant_refs(xendev, ptr, 1);
}
+int xen_send_notify(struct XenLegacyDevice *xendev);
+
struct XenLegacyBackendOps {
void (*set_max_grefs)(struct XenLegacyDevice *xendev, unsigned int nr_refs);
void * (*map_grefs)(struct XenLegacyDevice *xendev, uint32_t *refs,
unsigned int nr_refs);
int (*copy_grefs)(struct XenLegacyDevice *xendev, bool to_domain,
XenGrantCopySegment segs[], unsigned int nr_segs);
+ int (*send_notify)(struct XenLegacyDevice *xendev);
};
extern struct XenLegacyBackendOps xen_legacy_gnt_ops;
#ifndef TARGET_I386_XEN_PROTO_H
#define TARGET_I386_XEN_PROTO_H
+#include "hw/xen/xen-bus.h"
#include "hw/xen/xen-legacy-backend.h"
typedef struct XenGrantTable {
#define XEN_EVTCHN_STATE_INUSE 1
#define XEN_EVTCHN_STATE_UNBOUND 2
int state;
+
+ bool is_legacy;
+ union {
+ XenLegacyDeviceHandler *legacy_handler;
+ XenEventHandler handler;
+ } callback;
+ union {
+ struct XenLegacyDevice *dev;
+ void *opaque;
+ } callback_arg;
} XenEvtChn;
typedef struct XenState {
#include "qapi/error.h"
#include "qom/cpu.h"
#include "hw/xen/xen.h"
+#include "hw/xen/xen_pvdev.h"
#include "hw/xen/xen-legacy-backend.h"
#include "hw/xen/xen-bus.h"
}
}
+static void xen_dev_send_notify(struct XenDevice *xendev, int port,
+ Error **errp)
+{
+ kvm_xen_evtchn_host_send(port);
+}
+
static struct XenBackendOps xen_dev_ops = {
.set_max_grefs = xen_dev_set_max_grant_refs,
.map_grefs = xen_dev_map_grant_refs,
.unmap_grefs = xen_dev_unmap_grant_refs,
.copy_grefs = xen_dev_copy_grant_refs,
+ .send_notify = xen_dev_send_notify,
};
static void xen_legacy_dev_set_max_grant_refs(struct XenLegacyDevice *xendev,
return 0;
}
+static int xen_legacy_dev_device_notify(struct XenLegacyDevice *xendev)
+{
+ kvm_xen_evtchn_host_send(xendev->local_port);
+ return 0;
+}
+
static struct XenLegacyBackendOps xen_legacy_dev_ops = {
.set_max_grefs = xen_legacy_dev_set_max_grant_refs,
.map_grefs = xen_legacy_dev_map_grant_refs,
.unmap_grefs = xen_legacy_dev_unmap_grant_refs,
.copy_grefs = xen_legacy_dev_copy_grant_refs,
+ .send_notify = xen_legacy_dev_device_notify,
};
int kvm_xen_set_hypercall_page(CPUState *env)
kvm_xen_evtchn_init(xen);
+ /* grant and device emulation ops */
+ xen_legacy_handler = kvm_xen_evtchn_set_legacyhandler;
xen_legacy_gnt_ops = xen_legacy_dev_ops;
+
+ xen_dev_handler = kvm_xen_evtchn_set_devhandler;
xen_gnt_ops = xen_dev_ops;
}
return __kvm_set_xen_event(s, e, n, KVM_XEN_EVENTFD_UPDATE);
}
+int kvm_xen_evtchn_set_legacyhandler(int port, XenLegacyDeviceHandler *cb,
+ struct XenLegacyDevice *dev)
+{
+ struct XenEvtChn *evtchn;
+ CPUState *cpu;
+
+ evtchn = evtchn_from_port(port);
+ if (!evtchn) {
+ return -ENOENT;
+ }
+
+ cpu = qemu_get_cpu(evtchn->notify_vcpu_id);
+ if (!cpu) {
+ return -EINVAL;
+ }
+
+ kvm_clear_xen_event(cpu->kvm_state, evtchn);
+ evtchn->callback.legacy_handler = cb;
+ evtchn->callback_arg.dev = dev;
+ evtchn->is_legacy = true;
+
+ return 0;
+}
+
+int kvm_xen_evtchn_set_devhandler(int port, XenEventHandler cb, void *opaque)
+{
+ struct XenEvtChn *evtchn;
+ CPUState *cpu;
+
+ evtchn = evtchn_from_port(port);
+ if (!evtchn) {
+ return -ENOENT;
+ }
+
+ cpu = qemu_get_cpu(evtchn->notify_vcpu_id);
+ if (!cpu) {
+ return -EINVAL;
+ }
+
+ kvm_clear_xen_event(cpu->kvm_state, evtchn);
+ evtchn->callback.handler = cb;
+ evtchn->callback_arg.opaque = opaque;
+ evtchn->is_legacy = false;
+
+ return 0;
+}
+
int kvm_xen_evtchn_bind_ipi(X86CPU *cpu, void *arg)
{
struct evtchn_bind_ipi *out = arg;
return -EINVAL;
}
- evtchn_2l_set_pending(X86_CPU(dest), evtchn);
+ if (!evtchn->callback.handler) {
+ evtchn_2l_set_pending(X86_CPU(dest), evtchn);
+ } else if (evtchn->is_legacy) {
+ evtchn->callback.legacy_handler(evtchn->callback_arg.dev);
+ } else {
+ evtchn->callback.handler(evtchn->callback_arg.opaque);
+ }
trace_kvm_xen_evtchn_send(CPU(cpu)->cpu_index, evtchn->notify_vcpu_id,
send.port);
return 0;
}
+int kvm_xen_evtchn_host_send(int port)
+{
+ struct XenEvtChn *evtchn;
+ CPUState *dest;
+
+ evtchn = evtchn_from_port(port);
+ if (!evtchn) {
+ return -ENOENT;
+ }
+
+ dest = qemu_get_cpu(evtchn->notify_vcpu_id);
+ if (!dest) {
+ return -EINVAL;
+ }
+
+ evtchn_2l_set_pending(X86_CPU(dest), evtchn);
+
+ trace_kvm_xen_evtchn_send(-1, evtchn->notify_vcpu_id, port);
+ return 0;
+}
+
int kvm_xen_evtchn_vcpu_init(X86CPU *cpu, struct vcpu_info *vcpu)
{
int i;
int kvm_xen_evtchn_unmask(X86CPU *cpu, void *arg);
int kvm_xen_evtchn_status(X86CPU *cpu, void *arg);
int kvm_xen_evtchn_send(X86CPU *cpu, void *arg);
+int kvm_xen_evtchn_host_send(int port);
int kvm_xen_evtchn_vcpu_init(X86CPU *cpu, struct vcpu_info *info);
+int kvm_xen_evtchn_set_legacyhandler(int port, XenLegacyDeviceHandler *cb,
+ struct XenLegacyDevice *dev);
+int kvm_xen_evtchn_set_devhandler(int port, XenEventHandler cb, void *opaque);
void evtchn_2l_set_pending(X86CPU *cpu, XenEvtChn *evtchn);