static long evtchn_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int rc; struct per_user_data *u = file->private_data; void __user *uarg = (void __user *) arg; /* Prevent bind from racing with unbind */ mutex_lock(&u->bind_mutex); switch (cmd) { case IOCTL_EVTCHN_BIND_VIRQ: { struct ioctl_evtchn_bind_virq bind; struct evtchn_bind_virq bind_virq; rc = -EFAULT; if (copy_from_user(&bind, uarg, sizeof(bind))) break; bind_virq.virq = bind.virq; bind_virq.vcpu = 0; rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, &bind_virq); if (rc != 0) break; rc = evtchn_bind_to_user(u, bind_virq.port); if (rc == 0)
static long evtchn_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int rc; struct per_user_data *u = file->private_data; void __user *uarg = (void __user *) arg; /* Prevent bind from racing with unbind */ mutex_lock(&u->bind_mutex); switch (cmd) { case IOCTL_EVTCHN_BIND_VIRQ: { struct ioctl_evtchn_bind_virq bind; struct evtchn_bind_virq bind_virq; rc = -EFAULT; if (copy_from_user(&bind, uarg, sizeof(bind))) break; bind_virq.virq = bind.virq; bind_virq.vcpu = 0; rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, &bind_virq); if (rc != 0) break; rc = evtchn_bind_to_user(u, bind_virq.port); if (rc == 0) rc = bind_virq.port; break; } case IOCTL_EVTCHN_BIND_INTERDOMAIN: { struct ioctl_evtchn_bind_interdomain bind; struct evtchn_bind_interdomain bind_interdomain; rc = -EFAULT; if (copy_from_user(&bind, uarg, sizeof(bind))) break; bind_interdomain.remote_dom = bind.remote_domain; bind_interdomain.remote_port = bind.remote_port; rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain, &bind_interdomain); if (rc != 0) break; rc = evtchn_bind_to_user(u, bind_interdomain.local_port); if (rc == 0) rc = bind_interdomain.local_port; break; } case IOCTL_EVTCHN_BIND_UNBOUND_PORT: { struct ioctl_evtchn_bind_unbound_port bind; struct evtchn_alloc_unbound alloc_unbound; rc = -EFAULT; if (copy_from_user(&bind, uarg, sizeof(bind))) break; alloc_unbound.dom = DOMID_SELF; alloc_unbound.remote_dom = bind.remote_domain; rc = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &alloc_unbound); if (rc != 0) break; rc = evtchn_bind_to_user(u, alloc_unbound.port); if (rc == 0) rc = alloc_unbound.port; break; } case IOCTL_EVTCHN_UNBIND: { struct ioctl_evtchn_unbind unbind; rc = -EFAULT; if (copy_from_user(&unbind, uarg, sizeof(unbind))) break; rc = -EINVAL; if (unbind.port >= NR_EVENT_CHANNELS) break; rc = -ENOTCONN; if (get_port_user(unbind.port) != u) break; disable_irq(irq_from_evtchn(unbind.port)); evtchn_unbind_from_user(u, unbind.port); rc = 0; break; } case IOCTL_EVTCHN_NOTIFY: { struct ioctl_evtchn_notify notify; rc = -EFAULT; if (copy_from_user(¬ify, uarg, sizeof(notify))) break; if (notify.port >= NR_EVENT_CHANNELS) { rc = -EINVAL; } else if (get_port_user(notify.port) != u) { rc = -ENOTCONN; } else { notify_remote_via_evtchn(notify.port); rc = 0; } break; } case IOCTL_EVTCHN_RESET: { /* Initialise the ring to empty. Clear errors. */ mutex_lock(&u->ring_cons_mutex); spin_lock_irq(&port_user_lock); u->ring_cons = u->ring_prod = u->ring_overflow = 0; spin_unlock_irq(&port_user_lock); mutex_unlock(&u->ring_cons_mutex); rc = 0; break; } default: rc = -ENOSYS; break; } mutex_unlock(&u->bind_mutex); return rc; }
/* ARGSUSED */ static int evtchndrv_ioctl(dev_t dev, int cmd, intptr_t data, int flag, cred_t *cr, int *rvalp) { int err = 0; struct evtsoftdata *ep; minor_t minor = getminor(dev); if (secpolicy_xvm_control(cr)) return (EPERM); ep = EVTCHNDRV_INST2SOFTS(EVTCHNDRV_MINOR2INST(minor)); *rvalp = 0; switch (cmd) { case IOCTL_EVTCHN_BIND_VIRQ: { struct ioctl_evtchn_bind_virq bind; if (copyin((void *)data, &bind, sizeof (bind))) { err = EFAULT; break; } if ((err = xen_bind_virq(bind.virq, 0, rvalp)) != 0) break; evtchn_bind_to_user(ep, *rvalp); break; } case IOCTL_EVTCHN_BIND_INTERDOMAIN: { struct ioctl_evtchn_bind_interdomain bind; if (copyin((void *)data, &bind, sizeof (bind))) { err = EFAULT; break; } if ((err = xen_bind_interdomain(bind.remote_domain, bind.remote_port, rvalp)) != 0) break; ec_bind_vcpu(*rvalp, 0); evtchn_bind_to_user(ep, *rvalp); break; } case IOCTL_EVTCHN_BIND_UNBOUND_PORT: { struct ioctl_evtchn_bind_unbound_port bind; if (copyin((void *)data, &bind, sizeof (bind))) { err = EFAULT; break; } if ((err = xen_alloc_unbound_evtchn(bind.remote_domain, rvalp)) != 0) break; evtchn_bind_to_user(ep, *rvalp); break; } case IOCTL_EVTCHN_UNBIND: { struct ioctl_evtchn_unbind unbind; if (copyin((void *)data, &unbind, sizeof (unbind))) { err = EFAULT; break; } if (unbind.port >= NR_EVENT_CHANNELS) { err = EFAULT; break; } mutex_enter(&port_user_lock); if (port_user[unbind.port] != ep) { mutex_exit(&port_user_lock); err = ENOTCONN; break; } evtchndrv_close_evtchn(unbind.port); mutex_exit(&port_user_lock); break; } case IOCTL_EVTCHN_NOTIFY: { struct ioctl_evtchn_notify notify; if (copyin((void *)data, ¬ify, sizeof (notify))) { err = EFAULT; break; } if (notify.port >= NR_EVENT_CHANNELS) { err = EINVAL; } else if (port_user[notify.port] != ep) { err = ENOTCONN; } else { ec_notify_via_evtchn(notify.port); } break; } default: err = ENOSYS; } return (err); }