void unbind_all_ports(void) { int i; int cpu = 0; shared_info_t *s = HYPERVISOR_shared_info; vcpu_info_t *vcpu_info = &s->vcpu_info[cpu]; int rc; for ( i = 0; i < NR_EVS; i++ ) { if ( i == start_info.console.domU.evtchn || i == start_info.store_evtchn) continue; if ( test_and_clear_bit(i, bound_ports) ) { struct evtchn_close close; printk("port %d still bound!\n", i); mask_evtchn(i); close.port = i; rc = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close); if ( rc ) printk("WARN: close_port %s failed rc=%d. ignored\n", i, rc); clear_evtchn(i); } } vcpu_info->evtchn_upcall_pending = 0; vcpu_info->evtchn_pending_sel = 0; }
/* Set up event channel for xenstored which is run as a local process * (this is normally used only in dom0) */ static int __init xenstored_local_init(void) { int err = 0; unsigned long page = 0; struct evtchn_alloc_unbound alloc_unbound; /* Allocate Xenstore page */ page = get_zeroed_page(GFP_KERNEL); if (!page) goto out_err; xen_store_gfn = xen_start_info->store_mfn = virt_to_gfn((void *)page); /* Next allocate a local port which xenstored can bind to */ alloc_unbound.dom = DOMID_SELF; alloc_unbound.remote_dom = DOMID_SELF; err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &alloc_unbound); if (err == -ENOSYS) goto out_err; BUG_ON(err); xen_store_evtchn = xen_start_info->store_evtchn = alloc_unbound.port; return 0; out_err: if (page != 0) free_page(page); return err; }
static int bind_virq_to_irq(unsigned int virq, unsigned int cpu) { struct evtchn_bind_virq bind_virq; int evtchn = 0, irq; mtx_lock_spin(&irq_mapping_update_lock); if ((irq = pcpu_find(cpu)->pc_virq_to_irq[virq]) == -1) { if ((irq = find_unbound_irq()) < 0) goto out; bind_virq.virq = virq; bind_virq.vcpu = cpu; HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, &bind_virq); evtchn = bind_virq.port; evtchn_to_irq[evtchn] = irq; irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn); pcpu_find(cpu)->pc_virq_to_irq[virq] = irq; bind_evtchn_to_cpu(evtchn, cpu); } irq_bindcount[irq]++; unmask_evtchn(evtchn); out: mtx_unlock_spin(&irq_mapping_update_lock); return irq; }
static int bind_local_port_to_irq(unsigned int local_port) { int irq; mtx_lock_spin(&irq_mapping_update_lock); KASSERT(evtchn_to_irq[local_port] == -1, ("evtchn_to_irq inconsistent")); if ((irq = find_unbound_irq()) < 0) { struct evtchn_close close = { .port = local_port }; HYPERVISOR_event_channel_op(EVTCHNOP_close, &close); goto out; } evtchn_to_irq[local_port] = irq; irq_info[irq] = mk_irq_info(IRQT_LOCAL_PORT, 0, local_port); irq_bindcount[irq]++; unmask_evtchn(local_port); out: mtx_unlock_spin(&irq_mapping_update_lock); return irq; }
int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu) { struct evtchn_bind_ipi bind_ipi; int irq; int evtchn = 0; mtx_lock_spin(&irq_mapping_update_lock); if ((irq = pcpu_find(cpu)->pc_ipi_to_irq[ipi]) == -1) { if ((irq = find_unbound_irq()) < 0) goto out; bind_ipi.vcpu = cpu; HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi, &bind_ipi); evtchn = bind_ipi.port; evtchn_to_irq[evtchn] = irq; irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn); pcpu_find(cpu)->pc_ipi_to_irq[ipi] = irq; bind_evtchn_to_cpu(evtchn, cpu); } irq_bindcount[irq]++; unmask_evtchn(evtchn); out: mtx_unlock_spin(&irq_mapping_update_lock); return irq; }
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_v
static void unbind_from_irq(int irq) { struct evtchn_close close; int evtchn = evtchn_from_irq(irq); int cpu; mtx_lock_spin(&irq_mapping_update_lock); if ((--irq_bindcount[irq] == 0) && VALID_EVTCHN(evtchn)) { close.port = evtchn; HYPERVISOR_event_channel_op(EVTCHNOP_close, &close); switch (type_from_irq(irq)) { case IRQT_VIRQ: cpu = cpu_from_evtchn(evtchn); pcpu_find(cpu)->pc_virq_to_irq[index_from_irq(irq)] = -1; break; case IRQT_IPI: cpu = cpu_from_evtchn(evtchn); pcpu_find(cpu)->pc_ipi_to_irq[index_from_irq(irq)] = -1; break; default: break; } /* Closed ports are implicitly re-bound to VCPU0. */ bind_evtchn_to_cpu(evtchn, 0); evtchn_to_irq[evtchn] = -1; irq_info[irq] = IRQ_UNBOUND; } mtx_unlock_spin(&irq_mapping_update_lock); }
void unmask_evtchn(int port) { shared_info_t *s = HYPERVISOR_shared_info; unsigned int cpu = smp_processor_id(); vcpu_info_t *vcpu_info = &s->vcpu_info[cpu]; BUG_ON(!irqs_disabled()); /* Slow path (hypercall) if this is a non-local port. */ if (unlikely(cpu != cpu_from_evtchn(port))) { struct evtchn_unmask unmask = { .port = port }; (void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask); return; } synch_clear_bit(port, &s->evtchn_mask[0]); /* * The following is basically the equivalent of 'hw_resend_irq'. Just * like a real IO-APIC we 'lose the interrupt edge' if the channel is * masked. */ if (synch_test_bit(port, &s->evtchn_pending[0]) && !synch_test_and_set_bit(port / BITS_PER_LONG, &vcpu_info->evtchn_pending_sel)) { vcpu_info->evtchn_upcall_pending = 1; if (!vcpu_info->evtchn_upcall_mask) force_evtchn_callback(); } }
static unsigned int startup_pirq(unsigned int irq) { struct evtchn_bind_pirq bind_pirq; int evtchn = evtchn_from_irq(irq); if (VALID_EVTCHN(evtchn)) goto out; bind_pirq.pirq = irq; /* NB. We are happy to share unless we are probing. */ bind_pirq.flags = probing_irq(irq) ? 0 : BIND_PIRQ__WILL_SHARE; if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_pirq, &bind_pirq) != 0) { if (!probing_irq(irq)) printk(KERN_INFO "Failed to obtain physical IRQ %d\n", irq); return 0; } evtchn = bind_pirq.port; pirq_query_unmask(irq_to_pirq(irq)); evtchn_to_irq[evtchn] = irq; bind_evtchn_to_cpu(evtchn, 0); irq_info[irq] = mk_irq_info(IRQT_PIRQ, irq, evtchn); out: unmask_evtchn(evtchn); pirq_unmask_notify(irq_to_pirq(irq)); return 0; }
static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu) { struct evtchn_bind_ipi bind_ipi; int evtchn, irq; spin_lock(&irq_mapping_update_lock); if ((irq = per_cpu(ipi_to_irq, cpu)[ipi]) == -1) { if ((irq = find_unbound_irq()) < 0) goto out; bind_ipi.vcpu = cpu; if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi, &bind_ipi) != 0) BUG(); evtchn = bind_ipi.port; evtchn_to_irq[evtchn] = irq; irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn); per_cpu(ipi_to_irq, cpu)[ipi] = irq; bind_evtchn_to_cpu(evtchn, cpu); } irq_bindcount[irq]++; out: spin_unlock(&irq_mapping_update_lock); return irq; }
static int evtchn_bind_to_user(struct per_user_data *u, int port) { int rc = 0; /* * Ports are never reused, so every caller should pass in a * unique port. * * (Locking not necessary because we haven't registered the * interrupt handler yet, and our caller has already * serialized bind operations.) */ BUG_ON(get_port_user(port) != NULL); set_port_user(port, u); set_port_enabled(port, true); /* start enabled */ rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, IRQF_DISABLED, u->name, (void *)(unsigned long)port); if (rc >= 0) rc = evtchn_make_refcounted(port); else { /* bind failed, should close the port now */ struct evtchn_close close; close.port = port; if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0) BUG(); set_port_user(port, NULL); } return rc; }
static int bind_virq_to_irq(unsigned int virq, unsigned int cpu) { struct evtchn_bind_virq bind_virq; int evtchn, irq; spin_lock(&irq_mapping_update_lock); if ((irq = per_cpu(virq_to_irq, cpu)[virq]) == -1) { bind_virq.virq = virq; bind_virq.vcpu = cpu; if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, &bind_virq) != 0) BUG(); evtchn = bind_virq.port; irq = find_unbound_irq(); evtchn_to_irq[evtchn] = irq; irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn); per_cpu(virq_to_irq, cpu)[virq] = irq; bind_evtchn_to_cpu(evtchn, cpu); } irq_bindcount[irq]++; spin_unlock(&irq_mapping_update_lock); return irq; }
static void xenevt_free(struct xenevt_d *d) { int i; KASSERT(mutex_owned(&devevent_lock)); KASSERT(mutex_owned(&d->lock)); for (i = 0; i < NR_EVENT_CHANNELS; i++ ) { if (devevent[i] == d) { evtchn_op_t op = { .cmd = 0 }; int error; hypervisor_mask_event(i); xen_atomic_clear_bit(&d->ci->ci_evtmask[0], i); devevent[i] = NULL; op.cmd = EVTCHNOP_close; op.u.close.port = i; if ((error = HYPERVISOR_event_channel_op(&op))) { printf("xenevt_fclose: error %d from " "hypervisor\n", -error); } } } mutex_exit(&d->lock); seldestroy(&d->sel); cv_destroy(&d->cv); mutex_destroy(&d->lock); free(d, M_DEVBUF); }
static void unbind_from_irq(unsigned int irq) { struct evtchn_close close; int evtchn = evtchn_from_irq(irq); spin_lock(&irq_mapping_update_lock); if ((--irq_bindcount[irq] == 0) && VALID_EVTCHN(evtchn)) { close.port = evtchn; if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0) BUG(); switch (type_from_irq(irq)) { case IRQT_VIRQ: per_cpu(virq_to_irq, cpu_from_evtchn(evtchn)) [index_from_irq(irq)] = -1; break; case IRQT_IPI: per_cpu(ipi_to_irq, cpu_from_evtchn(evtchn)) [index_from_irq(irq)] = -1; break; default: break; } /* Closed ports are implicitly re-bound to VCPU0. */ bind_evtchn_to_cpu(evtchn, 0); evtchn_to_irq[evtchn] = -1; irq_info[irq] = IRQ_UNBOUND; } spin_unlock(&irq_mapping_update_lock); }
static int evtchn_release(struct inode *inode, struct file *filp) { int i; struct per_user_data *u = filp->private_data; struct evtchn_close close; spin_lock_irq(&port_user_lock); free_page((unsigned long)u->ring); for (i = 0; i < NR_EVENT_CHANNELS; i++) { int ret; if (port_user[i] != u) continue; port_user[i] = NULL; mask_evtchn(i); rebind_evtchn_to_cpu(i, 0); close.port = i; ret = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close); BUG_ON(ret); } spin_unlock_irq(&port_user_lock); kfree(u); return 0; }
void rebind_evtchn_to_cpu(int port, unsigned int cpu) { struct evtchn_bind_vcpu ebv = { .port = port, .vcpu = cpu }; int masked; masked = test_and_set_evtchn_mask(port); if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &ebv) == 0) bind_evtchn_to_cpu(port, cpu); if (!masked) unmask_evtchn(port); }
static int bind_listening_port_to_irq(unsigned int remote_domain) { struct evtchn_alloc_unbound alloc_unbound; int err; alloc_unbound.dom = DOMID_SELF; alloc_unbound.remote_dom = remote_domain; err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &alloc_unbound); return err ? : bind_local_port_to_irq(alloc_unbound.port); }
void unbind_evtchn(evtchn_port_t port) { struct evtchn_close close; int rc; mask_evtchn(port); clear_evtchn(port); close.port = port; rc = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close); if ( rc ) printk("WARN: close_port %s failed rc=%d. ignored\n", port, rc); }
/** * Free an existing event channel. Returns 0 on success or -errno on error. */ int xenbus_free_evtchn(struct xenbus_device *dev, int port) { struct evtchn_close close; int err; close.port = port; err = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close); if (err) xenbus_dev_error(dev, err, "freeing event channel %d", port); return err; }
int gnt_init(void) { int mfn; int err; struct as_sring *sring; struct evtchn_alloc_unbound alloc_unbound; printk(KERN_INFO "gnt_init\n"); page = __get_free_pages(GFP_KERNEL, 0); if (page == 0) { printk(KERN_DEBUG "\nxen:DomU:could not get free page"); return 0; } sring = (struct as_sring *)page; SHARED_RING_INIT(sring); FRONT_RING_INIT(&(info.ring), sring, PAGE_SIZE); mfn = virt_to_mfn(page); printk(KERN_INFO "grant foreign access\n"); info.gref = gnttab_grant_foreign_access(DOM0_ID, mfn, 0); if (info.gref < 0) { printk(KERN_DEBUG "\nxen:could not grant foreign access"); free_page((unsigned long)page); info.ring.sring = NULL; return 0; } printk(KERN_DEBUG "\n gref = %d", info.gref); alloc_unbound.dom = DOMID_SELF; alloc_unbound.remote_dom = DOM0_ID; err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &alloc_unbound); if (err) { printk(KERN_DEBUG "\nalloc unbound port failure"); return err; } err = bind_evtchn_to_irqhandler(alloc_unbound.port, as_int, 0, "xen-eg", &info); if (err < 0) { printk(KERN_DEBUG "\nbind evtchn to irqhandler failure"); return err; } info.irq = err; info.port = alloc_unbound.port; printk(KERN_DEBUG " interrupt = %d, local_port = %d", info.irq, info.port); printk("...\n..."); create_procfs_entry(); return 0; }
static int bind_interdomain_evtchn_to_irq(unsigned int remote_domain, unsigned int remote_port) { struct evtchn_bind_interdomain bind_interdomain; int err; bind_interdomain.remote_dom = remote_domain; bind_interdomain.remote_port = remote_port; err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain, &bind_interdomain); return err ? : bind_local_port_to_irq(bind_interdomain.local_port); }
int evtchn_alloc_unbound(uint32_t pal, void *handler, void *data, evtchn_port_t *port) { int rc; evtchn_alloc_unbound_t op; op.dom = DOMID_SELF; op.remote_dom = pal; rc = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &op); if (rc) { printk("ERROR: alloc_unbound failed with rc=%d", rc); return rc; } *port = bind_evtchn((uint32_t) op.port, handler, data); return rc; }
int xenbus_free_evtchn(device_t dev, evtchn_port_t port) { struct evtchn_close close; int err; close.port = port; err = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close); if (err) { xenbus_dev_error(dev, -err, "freeing event channel %d", port); return (-err); } return (0); }
int xenbus_conn(domid_t remote_dom, unsigned long *grant_ref, evtchn_port_t *local_port) { struct evtchn_alloc_unbound alloc_unbound; int rc, rc2; BUG_ON(atomic_read(&xenbus_xsd_state) != XENBUS_XSD_FOREIGN_INIT); BUG_ON(!is_initial_xendomain()); #if defined(CONFIG_PROC_FS) && defined(CONFIG_XEN_PRIVILEGED_GUEST) remove_xen_proc_entry("xsd_kva"); remove_xen_proc_entry("xsd_port"); #endif rc = xb_free_port(xen_store_evtchn); if (rc != 0) goto fail0; alloc_unbound.dom = DOMID_SELF; alloc_unbound.remote_dom = remote_dom; rc = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &alloc_unbound); if (rc != 0) goto fail0; *local_port = xen_store_evtchn = alloc_unbound.port; /* keep the old page (xen_store_mfn, xen_store_interface) */ rc = gnttab_grant_foreign_access(remote_dom, xen_store_mfn, GTF_permit_access); if (rc < 0) goto fail1; *grant_ref = rc; rc = xb_init_comms(); if (rc != 0) goto fail1; return 0; fail1: rc2 = xb_free_port(xen_store_evtchn); if (rc2 != 0) printk(KERN_WARNING "XENBUS: Error freeing xenstore event channel: %d\n", rc2); fail0: xen_store_evtchn = -1; return rc; }
int evtchn_alloc_unbound(domid_t pal, evtchn_port_t *port) { int rc; evtchn_alloc_unbound_t op; op.dom = DOMID_SELF; op.remote_dom = pal; rc = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &op); if ( rc ) { printk("ERROR: alloc_unbound failed with rc=%d", rc); return rc; } *port = op.port; return rc; }
int evtchn_bind_interdomain(domid_t pal, evtchn_port_t remote_port, evtchn_port_t *local_port) { int rc; evtchn_bind_interdomain_t op; op.remote_dom = pal; op.remote_port = remote_port; rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain, &op); if ( rc ) { printk("ERROR: bind_interdomain failed with rc=%d", rc); return rc; } *local_port = op.local_port; return rc; }
evtchn_port_t bind_virq(uint32_t virq, evtchn_handler_t handler, void *data) { evtchn_bind_virq_t op; int rc; /* Try to bind the virq to a port */ op.virq = virq; op.vcpu = smp_processor_id(); if ( (rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, &op)) != 0 ) { printk("Failed to bind virtual IRQ %d with rc=%d\n", virq, rc); return -1; } bind_evtchn(op.port, handler, data); return op.port; }
/** * Allocate an event channel for the given xenbus_device, assigning the newly * created local port to *port. Return 0 on success, or -errno on error. On * error, the device will switch to XenbusStateClosing, and the error will be * saved in the store. */ int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port) { struct evtchn_alloc_unbound alloc_unbound; int err; alloc_unbound.dom = DOMID_SELF; alloc_unbound.remote_dom = dev->otherend_id; err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &alloc_unbound); if (err) xenbus_dev_fatal(dev, err, "allocating event channel"); else *port = alloc_unbound.port; return err; }
void unmask_evtchn(int port) { unsigned int cpu; shared_info_t *s = shared_info_area; vcpu_info_t *vcpu_info; cpu = get_cpu(); vcpu_info = &s->vcpu_info[cpu]; /* Slow path (hypercall) if this is a non-local port. We only ever bind event channels to vcpu 0 in HVM guests. */ if (unlikely(cpu != 0)) { evtchn_unmask_t op = { .port = port }; (void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &op); put_cpu(); return; }
evtchn_port_t bind_pirq(uint32_t pirq, int will_share, evtchn_handler_t handler, void *data) { evtchn_bind_pirq_t op; int rc; /* Try to bind the pirq to a port */ op.pirq = pirq; op.flags = will_share ? BIND_PIRQ__WILL_SHARE : 0; if ( (rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_pirq, &op)) != 0 ) { printk("Failed to bind physical IRQ %d with rc=%d\n", pirq, rc); return -1; } bind_evtchn(op.port, handler, data); return op.port; }