static void xencons_send(struct XenConsole *con) { ssize_t len, size; size = con->buffer.size - con->buffer.consumed; if (qemu_chr_fe_backend_connected(&con->chr)) { len = qemu_chr_fe_write(&con->chr, con->buffer.data + con->buffer.consumed, size); } else { len = size; } if (len < 1) { if (!con->backlog) { con->backlog = 1; xen_pv_printf(&con->xendev, 1, "backlog piling up, nobody listening?\n"); } } else { buffer_advance(&con->buffer, len); if (con->backlog && len == size) { con->backlog = 0; xen_pv_printf(&con->xendev, 1, "backlog is gone\n"); } } }
static void virtconsole_realize(DeviceState *dev, Error **errp) { VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev); VirtConsole *vcon = VIRTIO_CONSOLE(dev); VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(dev); if (port->id == 0 && !k->is_console) { error_setg(errp, "Port number 0 on virtio-serial devices reserved " "for virtconsole devices for backward compatibility."); return; } if (qemu_chr_fe_backend_connected(&vcon->chr)) { /* * For consoles we don't block guest data transfer just * because nothing is connected - we'll just let it go * whetherever the chardev wants - /dev/null probably. * * For serial ports we need 100% reliable data transfer * so we use the opened/closed signals from chardev to * trigger open/close of the device */ if (k->is_console) { qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read, NULL, chr_be_change, vcon, NULL, true); virtio_serial_open(port); } else { qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read, chr_event, chr_be_change, vcon, NULL, false); } } }
/* Callback function that's called when the guest sends us data */ static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, ssize_t len) { VirtConsole *vcon = VIRTIO_CONSOLE(port); ssize_t ret; if (!qemu_chr_fe_backend_connected(&vcon->chr)) { /* If there's no backend, we can just say we consumed all data. */ return len; } ret = qemu_chr_fe_write(&vcon->chr, buf, len); trace_virtio_console_flush_buf(port->id, len, ret); if (ret < len) { VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port); /* * Ideally we'd get a better error code than just -1, but * that's what the chardev interface gives us right now. If * we had a finer-grained message, like -EPIPE, we could close * this connection. */ if (ret < 0) ret = 0; /* XXX we should be queuing data to send later for the * console devices too rather than silently dropping * console data on EAGAIN. The Linux virtio-console * hvc driver though does sends with spinlocks held, * so if we enable throttling that'll stall the entire * guest kernel, not merely the process writing to the * console. * * While we could queue data for later write without * enabling throttling, this would result in the guest * being able to trigger arbitrary memory usage in QEMU * buffering data for later writes. * * So fixing this problem likely requires fixing the * Linux virtio-console hvc driver to not hold spinlocks * while writing, and instead merely block the process * that's writing. QEMU would then need some way to detect * if the guest had the fixed driver too, before we can * use throttling on host side. */ if (!k->is_console) { virtio_serial_throttle_port(port, true); if (!vcon->watch) { vcon->watch = qemu_chr_fe_add_watch(&vcon->chr, G_IO_OUT|G_IO_HUP, chr_write_unblocked, vcon); } } } return ret; }
static void ipmi_bmc_extern_realize(DeviceState *dev, Error **errp) { IPMIBmcExtern *ibe = IPMI_BMC_EXTERN(dev); if (!qemu_chr_fe_backend_connected(&ibe->chr)) { error_setg(errp, "IPMI external bmc requires chardev attribute"); return; } qemu_chr_fe_set_handlers(&ibe->chr, can_receive, receive, chr_event, NULL, ibe, NULL, true); }
/* * Triggered by SCLP's write_event_data * - write console data to character layer * returns < 0 if an error occurred */ static int write_console_data(SCLPEvent *event, const uint8_t *buf, int len) { SCLPConsoleLM *scon = SCLPLM_CONSOLE(event); if (!qemu_chr_fe_backend_connected(&scon->chr)) { /* If there's no backend, we can just say we consumed all data. */ return len; } /* XXX this blocks entire thread. Rewrite to use * qemu_chr_fe_write and background I/O callbacks */ return qemu_chr_fe_write_all(&scon->chr, buf, len); }
static void virtconsole_enable_backend(VirtIOSerialPort *port, bool enable) { VirtConsole *vcon = VIRTIO_CONSOLE(port); if (!qemu_chr_fe_backend_connected(&vcon->chr)) { return; } if (enable) { VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port); qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read, k->is_console ? NULL : chr_event, chr_be_change, vcon, NULL, false); } else { qemu_chr_fe_set_handlers(&vcon->chr, NULL, NULL, NULL, NULL, NULL, NULL, false); } }
static int mad_init(RdmaBackendDev *backend_dev, CharBackend *mad_chr_be) { int ret; backend_dev->rdmacm_mux.chr_be = mad_chr_be; ret = qemu_chr_fe_backend_connected(backend_dev->rdmacm_mux.chr_be); if (!ret) { rdma_error_report("Missing chardev for MAD multiplexer"); return -EIO; } rdma_protected_qlist_init(&backend_dev->recv_mads_list); enable_rdmacm_mux_async(backend_dev); qemu_chr_fe_set_handlers(backend_dev->rdmacm_mux.chr_be, rdmacm_mux_can_receive, rdmacm_mux_read, NULL, NULL, backend_dev, NULL, true); return 0; }
static void sh_serial_write(void *opaque, hwaddr offs, uint64_t val, unsigned size) { sh_serial_state *s = opaque; unsigned char ch; #ifdef DEBUG_SERIAL printf("sh_serial: write offs=0x%02x val=0x%02x\n", offs, val); #endif switch(offs) { case 0x00: /* SMR */ s->smr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0x7b : 0xff); return; case 0x04: /* BRR */ s->brr = val; return; case 0x08: /* SCR */ /* TODO : For SH7751, SCIF mask should be 0xfb. */ s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff); if (!(val & (1 << 5))) s->flags |= SH_SERIAL_FLAG_TEND; if ((s->feat & SH_SERIAL_FEAT_SCIF) && s->txi) { qemu_set_irq(s->txi, val & (1 << 7)); } if (!(val & (1 << 6))) { qemu_set_irq(s->rxi, 0); } return; case 0x0c: /* FTDR / TDR */ if (qemu_chr_fe_backend_connected(&s->chr)) { ch = val; /* XXX this blocks entire thread. Rewrite to use * qemu_chr_fe_write and background I/O callbacks */ qemu_chr_fe_write_all(&s->chr, &ch, 1); } s->dr = val; s->flags &= ~SH_SERIAL_FLAG_TDE; return; #if 0 case 0x14: /* FRDR / RDR */ ret = 0; break; #endif } if (s->feat & SH_SERIAL_FEAT_SCIF) { switch(offs) { case 0x10: /* FSR */ if (!(val & (1 << 6))) s->flags &= ~SH_SERIAL_FLAG_TEND; if (!(val & (1 << 5))) s->flags &= ~SH_SERIAL_FLAG_TDE; if (!(val & (1 << 4))) s->flags &= ~SH_SERIAL_FLAG_BRK; if (!(val & (1 << 1))) s->flags &= ~SH_SERIAL_FLAG_RDF; if (!(val & (1 << 0))) s->flags &= ~SH_SERIAL_FLAG_DR; if (!(val & (1 << 1)) || !(val & (1 << 0))) { if (s->rxi) { qemu_set_irq(s->rxi, 0); } } return; case 0x18: /* FCR */ s->fcr = val; switch ((val >> 6) & 3) { case 0: s->rtrg = 1; break; case 1: s->rtrg = 4; break; case 2: s->rtrg = 8; break; case 3: s->rtrg = 14; break; } if (val & (1 << 1)) { sh_serial_clear_fifo(s); s->sr &= ~(1 << 1); } return; case 0x20: /* SPTR */ s->sptr = val & 0xf3; return; case 0x24: /* LSR */ return; } } else { switch(offs) {