void xenconscn_putc(dev_t dev, int c) { int s = spltty(); XENCONS_RING_IDX cons, prod; if (xendomain_is_dom0()) { u_char buf[1]; buf[0] = c; (void)HYPERVISOR_console_io(CONSOLEIO_write, 1, buf); } else { XENPRINTK(("xenconscn_putc(%c)\n", c)); cons = xencons_interface->out_cons; prod = xencons_interface->out_prod; xen_rmb(); while (prod == cons + sizeof(xencons_interface->out)) { cons = xencons_interface->out_cons; prod = xencons_interface->out_prod; xen_rmb(); } xencons_interface->out[MASK_XENCONS_IDX(xencons_interface->out_prod, xencons_interface->out)] = c; xen_rmb(); xencons_interface->out_prod++; xen_rmb(); hypervisor_notify_via_evtchn(xen_start_info.console.domU.evtchn); splx(s); } }
int xb_read(void *data, unsigned len) { struct xenstore_domain_interface *intf = xenstore_domain_interface(); XENSTORE_RING_IDX cons, prod; int s = spltty(); while (len != 0) { unsigned int avail; const char *src; while (intf->rsp_cons == intf->rsp_prod) tsleep(&xenstore_interface, PRIBIO, "rdst", 0); /* Read indexes, then verify. */ cons = intf->rsp_cons; prod = intf->rsp_prod; xen_rmb(); if (!check_indexes(cons, prod)) { XENPRINTF(("xb_read EIO\n")); splx(s); return EIO; } src = get_input_chunk(cons, prod, intf->rsp, &avail); if (avail == 0) continue; if (avail > len) avail = len; /* We must read header before we read data. */ xen_rmb(); memcpy(data, src, avail); data = (char *)data + avail; len -= avail; /* Other side must not see free space until we've copied out */ xen_rmb(); intf->rsp_cons += avail; xen_rmb(); XENPRINTF(("Finished read of %i bytes (%i to go)\n", avail, len)); hypervisor_notify_via_evtchn(xen_start_info.store_evtchn); } splx(s); return 0; }
int xb_write(const void *data, unsigned len) { struct xenstore_domain_interface *intf = xenstore_domain_interface(); XENSTORE_RING_IDX cons, prod; int s = spltty(); while (len != 0) { void *dst; unsigned int avail; while ((intf->req_prod - intf->req_cons) == XENSTORE_RING_SIZE) { XENPRINTF(("xb_write tsleep\n")); tsleep(&xenstore_interface, PRIBIO, "wrst", 0); XENPRINTF(("xb_write tsleep done\n")); } /* Read indexes, then verify. */ cons = intf->req_cons; prod = intf->req_prod; xen_rmb(); if (!check_indexes(cons, prod)) { splx(s); return EIO; } dst = get_output_chunk(cons, prod, intf->req, &avail); if (avail == 0) continue; if (avail > len) avail = len; memcpy(dst, data, avail); data = (const char *)data + avail; len -= avail; /* Other side must not see new header until data is there. */ xen_rmb(); intf->req_prod += avail; xen_rmb(); hypervisor_notify_via_evtchn(xen_start_info.store_evtchn); } splx(s); return 0; }
/* Non-privileged console interrupt routine */ static int xencons_handler(void *arg) { struct xencons_softc *sc = arg; XENCONS_RING_IDX cons, prod, len; int s = spltty(); if (sc->polling) { splx(s); return 1; } #define XNC_IN (xencons_interface->in) cons = xencons_interface->in_cons; prod = xencons_interface->in_prod; xen_rmb(); while (cons != prod) { if (MASK_XENCONS_IDX(cons, XNC_IN) < MASK_XENCONS_IDX(prod, XNC_IN)) len = MASK_XENCONS_IDX(prod, XNC_IN) - MASK_XENCONS_IDX(cons, XNC_IN); else len = sizeof(XNC_IN) - MASK_XENCONS_IDX(cons, XNC_IN); xencons_tty_input(sc, __UNVOLATILE( &XNC_IN[MASK_XENCONS_IDX(cons, XNC_IN)]), len); if (__predict_false(xencons_interface->in_cons != cons)) { /* catch up with xenconscn_getc() */ cons = xencons_interface->in_cons; prod = xencons_interface->in_prod; xen_rmb(); } else { cons += len; xen_wmb(); xencons_interface->in_cons = cons; xen_wmb(); } } hypervisor_notify_via_evtchn(xen_start_info.console.domU.evtchn); splx(s); return 1; #undef XNC_IN }
static int xenevt_fioctl(struct file *fp, u_long cmd, void *addr) { struct xenevt_d *d = fp->f_data; evtchn_op_t op = { .cmd = 0 }; int error; switch(cmd) { case EVTCHN_RESET: case IOCTL_EVTCHN_RESET: mutex_enter(&d->lock); d->ring_read = d->ring_write = 0; d->flags = 0; mutex_exit(&d->lock); break; case IOCTL_EVTCHN_BIND_VIRQ: { struct ioctl_evtchn_bind_virq *bind_virq = addr; op.cmd = EVTCHNOP_bind_virq; op.u.bind_virq.virq = bind_virq->virq; op.u.bind_virq.vcpu = 0; if ((error = HYPERVISOR_event_channel_op(&op))) { printf("IOCTL_EVTCHN_BIND_VIRQ failed: virq %d error %d\n", bind_virq->virq, error); return -error; } bind_virq->port = op.u.bind_virq.port; mutex_enter(&devevent_lock); KASSERT(devevent[bind_virq->port] == NULL); devevent[bind_virq->port] = d; mutex_exit(&devevent_lock); xen_atomic_set_bit(&d->ci->ci_evtmask[0], bind_virq->port); hypervisor_unmask_event(bind_virq->port); break; } case IOCTL_EVTCHN_BIND_INTERDOMAIN: { struct ioctl_evtchn_bind_interdomain *bind_intd = addr; op.cmd = EVTCHNOP_bind_interdomain; op.u.bind_interdomain.remote_dom = bind_intd->remote_domain; op.u.bind_interdomain.remote_port = bind_intd->remote_port; if ((error = HYPERVISOR_event_channel_op(&op))) return -error; bind_intd->port = op.u.bind_interdomain.local_port; mutex_enter(&devevent_lock); KASSERT(devevent[bind_intd->port] == NULL); devevent[bind_intd->port] = d; mutex_exit(&devevent_lock); xen_atomic_set_bit(&d->ci->ci_evtmask[0], bind_intd->port); hypervisor_unmask_event(bind_intd->port); break; } case IOCTL_EVTCHN_BIND_UNBOUND_PORT: { struct ioctl_evtchn_bind_unbound_port *bind_unbound = addr; op.cmd = EVTCHNOP_alloc_unbound; op.u.alloc_unbound.dom = DOMID_SELF; op.u.alloc_unbound.remote_dom = bind_unbound->remote_domain; if ((error = HYPERVISOR_event_channel_op(&op))) return -error; bind_unbound->port = op.u.alloc_unbound.port; mutex_enter(&devevent_lock); KASSERT(devevent[bind_unbound->port] == NULL); devevent[bind_unbound->port] = d; mutex_exit(&devevent_lock); xen_atomic_set_bit(&d->ci->ci_evtmask[0], bind_unbound->port); hypervisor_unmask_event(bind_unbound->port); break; } case IOCTL_EVTCHN_UNBIND: { struct ioctl_evtchn_unbind *unbind = addr; if (unbind->port > NR_EVENT_CHANNELS) return EINVAL; mutex_enter(&devevent_lock); if (devevent[unbind->port] != d) { mutex_exit(&devevent_lock); return ENOTCONN; } devevent[unbind->port] = NULL; mutex_exit(&devevent_lock); hypervisor_mask_event(unbind->port); xen_atomic_clear_bit(&d->ci->ci_evtmask[0], unbind->port); op.cmd = EVTCHNOP_close; op.u.close.port = unbind->port; if ((error = HYPERVISOR_event_channel_op(&op))) return -error; break; } case IOCTL_EVTCHN_NOTIFY: { struct ioctl_evtchn_notify *notify = addr; if (notify->port > NR_EVENT_CHANNELS) return EINVAL; mutex_enter(&devevent_lock); if (devevent[notify->port] != d) { mutex_exit(&devevent_lock); return ENOTCONN; } hypervisor_notify_via_evtchn(notify->port); mutex_exit(&devevent_lock); break; } case FIONBIO: break; default: return EINVAL; } return 0; } /* * Support for poll() system call * * Return true if the specific operation will not block indefinitely. */ static int xenevt_fpoll(struct file *fp, int events) { struct xenevt_d *d = fp->f_data; int revents = events & (POLLOUT | POLLWRNORM); /* we can always write */ mutex_enter(&d->lock); if (events & (POLLIN | POLLRDNORM)) { if (d->ring_read != d->ring_write) { revents |= events & (POLLIN | POLLRDNORM); } else { /* Record that someone is waiting */ selrecord(curlwp, &d->sel); } } mutex_exit(&d->lock); return (revents); }
void xencons_start(struct tty *tp) { struct clist *cl; int s; s = spltty(); if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) goto out; tp->t_state |= TS_BUSY; splx(s); /* * We need to do this outside spl since it could be fairly * expensive and we don't want our serial ports to overflow. */ cl = &tp->t_outq; if (xendomain_is_dom0()) { int len, r; u_char buf[XENCONS_BURST+1]; len = q_to_b(cl, buf, XENCONS_BURST); while (len > 0) { r = HYPERVISOR_console_io(CONSOLEIO_write, len, buf); if (r <= 0) break; len -= r; } } else { XENCONS_RING_IDX cons, prod, len; #define XNC_OUT (xencons_interface->out) cons = xencons_interface->out_cons; prod = xencons_interface->out_prod; xen_rmb(); while (prod != cons + sizeof(xencons_interface->out)) { if (MASK_XENCONS_IDX(prod, XNC_OUT) < MASK_XENCONS_IDX(cons, XNC_OUT)) { len = MASK_XENCONS_IDX(cons, XNC_OUT) - MASK_XENCONS_IDX(prod, XNC_OUT); } else { len = sizeof(XNC_OUT) - MASK_XENCONS_IDX(prod, XNC_OUT); } len = q_to_b(cl, __UNVOLATILE( &XNC_OUT[MASK_XENCONS_IDX(prod, XNC_OUT)]), len); if (len == 0) break; prod = prod + len; } xen_wmb(); xencons_interface->out_prod = prod; xen_wmb(); hypervisor_notify_via_evtchn(xen_start_info.console.domU.evtchn); #undef XNC_OUT } s = spltty(); tp->t_state &= ~TS_BUSY; if (ttypull(tp)) { tp->t_state |= TS_TIMEOUT; callout_schedule(&tp->t_rstrt_ch, 1); } out: splx(s); }