header[0] = 0x02;
header[1] = len;
- qemu_chr_fe_write(s->chr, header, sizeof(header));
+ /* XXX this blocks entire thread. Rewrite to use
+ * qemu_chr_fe_write and background I/O callbacks */
+ qemu_chr_fe_write_all(s->chr, header, sizeof(header));
size -= len;
}
}
}
#else
- qemu_chr_fe_write(s->chr, buf, len);
+ /* XXX this blocks entire thread. Rewrite to use
+ * qemu_chr_fe_write and background I/O callbacks */
+ qemu_chr_fe_write_all(s->chr, buf, len);
#endif
}
if (ch == STI_TRACE_CONTROL_CHANNEL) {
/* Flush channel <i>value</i>. */
- qemu_chr_fe_write(s->chr, (const uint8_t *) "\r", 1);
+ /* XXX this blocks entire thread. Rewrite to use
+ * qemu_chr_fe_write and background I/O callbacks */
+ qemu_chr_fe_write_all(s->chr, (const uint8_t *) "\r", 1);
} else if (ch == STI_TRACE_CONSOLE_CHANNEL || 1) {
if (value == 0xc0 || value == 0xc3) {
/* Open channel <i>ch</i>. */
} else if (value == 0x00)
- qemu_chr_fe_write(s->chr, (const uint8_t *) "\n", 1);
+ qemu_chr_fe_write_all(s->chr, (const uint8_t *) "\n", 1);
else
- qemu_chr_fe_write(s->chr, &byte, 1);
+ qemu_chr_fe_write_all(s->chr, &byte, 1);
}
}
else
ch = ~value;
if (s->chr && s->enable && (s->control[0] & (1 << 3))) /* TXE */
- qemu_chr_fe_write(s->chr, &ch, 1);
+ /* 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);
break;
case ICSR0:
s->status[0] &= ~(value & 0x66);
if (s->utcr3 & UTCR3_LBM) /* loopback */ {
strongarm_uart_receive(s, &s->tx_fifo[s->tx_start], 1);
} else if (s->chr) {
- qemu_chr_fe_write(s->chr, &s->tx_fifo[s->tx_start], 1);
+ /* XXX this blocks entire thread. Rewrite to use
+ * qemu_chr_fe_write and background I/O callbacks */
+ qemu_chr_fe_write_all(s->chr, &s->tx_fifo[s->tx_start], 1);
}
s->tx_start = (s->tx_start + 1) % 8;
/* "DLAB bit set means access baudrate register" is NYI */
ch = value;
if (s->chr) {
- qemu_chr_fe_write(s->chr, &ch, 1);
+ /* 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);
}
break;
printf(" [debugcon: write addr=0x%04" HWADDR_PRIx " val=0x%02" PRIx64 "]\n", addr, val);
#endif
- qemu_chr_fe_write(s->chr, &ch, 1);
+ /* 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);
}
switch (addr) {
case R_TX:
if (s->chr) {
+ /* 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);
}
break;
s->tx = val;
if (s->wregs[W_TXCTRL2] & TXCTRL2_TXEN) { // tx enabled
if (s->chr)
- qemu_chr_fe_write(s->chr, &s->tx, 1);
+ /* XXX this blocks entire thread. Rewrite to use
+ * qemu_chr_fe_write and background I/O callbacks */
+ qemu_chr_fe_write_all(s->chr, &s->tx, 1);
else if (s->type == kbd && !s->disabled) {
handle_kbd_command(s, val);
}
switch (addr)
{
case RW_DOUT:
- qemu_chr_fe_write(s->chr, &ch, 1);
+ /* 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->regs[R_INTR] |= 3;
s->pending_tx = 1;
s->regs[addr] = value;
s->reg[I_(UTRSTAT)] &= ~(UTRSTAT_TRANSMITTER_EMPTY |
UTRSTAT_Tx_BUFFER_EMPTY);
ch = (uint8_t)val;
- qemu_chr_fe_write(s->chr, &ch, 1);
+ /* 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);
#if DEBUG_Tx_DATA
fprintf(stderr, "%c", ch);
#endif
/* Transmit when character device available and transmitter enabled */
if ((uart->chr) && (uart->control & UART_TRANSMIT_ENABLE)) {
c = value & 0xFF;
- qemu_chr_fe_write(uart->chr, &c, 1);
+ /* XXX this blocks entire thread. Rewrite to use
+ * qemu_chr_fe_write and background I/O callbacks */
+ qemu_chr_fe_write_all(uart->chr, &c, 1);
/* Generate interrupt */
if (uart->control & UART_TRANSMIT_INTERRUPT) {
qemu_irq_pulse(uart->irq);
ch = value;
if (s->ucr2 & UCR2_TXEN) {
if (s->chr) {
- qemu_chr_fe_write(s->chr, &ch, 1);
+ /* 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->usr1 &= ~USR1_TRDY;
imx_update(s);
DPRINTF("Write THR%c (0x%x)\n", channel + 'a', reg);
if (ch->dev) {
uint8_t thr = reg;
- qemu_chr_fe_write(ch->dev, &thr, 1);
+ /* XXX this blocks entire thread. Rewrite to use
+ * qemu_chr_fe_write and background I/O callbacks */
+ qemu_chr_fe_write_all(ch->dev, &thr, 1);
}
} else {
DPRINTF("Write THR%c (0x%x), Tx disabled\n", channel + 'a', reg);
s->jtx = jtx;
if (s->chr) {
+ /* 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);
}
}
switch (addr) {
case R_RXTX:
if (s->chr) {
+ /* 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);
}
break;
{
if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) {
if (s->chr)
- qemu_chr_fe_write(s->chr, (unsigned char *)&s->tb, 1);
+ /* XXX this blocks entire thread. Rewrite to use
+ * qemu_chr_fe_write and background I/O callbacks */
+ qemu_chr_fe_write_all(s->chr, (unsigned char *)&s->tb, 1);
s->sr |= MCF_UART_TxEMP;
}
if (s->tx_enabled) {
if (val & PARA_CTR_STROBE) {
s->status &= ~PARA_STS_BUSY;
if ((s->control & PARA_CTR_STROBE) == 0)
- qemu_chr_fe_write(s->chr, &s->dataw, 1);
+ /* XXX this blocks entire thread. Rewrite to use
+ * qemu_chr_fe_write and background I/O callbacks */
+ qemu_chr_fe_write_all(s->chr, &s->dataw, 1);
} else {
if (s->control & PARA_CTR_INTEN) {
s->irq_pending = 1;
/* ??? Check if transmitter is enabled. */
ch = value;
if (s->chr)
- qemu_chr_fe_write(s->chr, &ch, 1);
+ /* 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->int_level |= PL011_INT_TX;
pl011_update(s);
break;
scon->buf[scon->length] = *buf;
scon->length += 1;
if (scon->echo) {
- qemu_chr_fe_write(scon->chr, buf, size);
+ /* XXX this blocks entire thread. Rewrite to use
+ * qemu_chr_fe_write and background I/O callbacks */
+ qemu_chr_fe_write_all(scon->chr, buf, size);
}
}
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);
}
case 0x0c: /* FTDR / TDR */
if (s->chr) {
ch = val;
- qemu_chr_fe_write(s->chr, &ch, 1);
+ /* 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;
{
VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(sdev);
- /* FIXME: should check the qemu_chr_fe_write() return value */
- qemu_chr_fe_write(dev->chardev, buf, len);
+ /* XXX this blocks entire thread. Rewrite to use
+ * qemu_chr_fe_write and background I/O callbacks */
+ qemu_chr_fe_write_all(dev->chardev, buf, len);
}
static void spapr_vty_realize(VIOsPAPRDevice *sdev, Error **errp)
if (value < 0xF000) {
ch = value;
if (s->chr) {
+ /* 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->usart_sr |= USART_SR_TC;
*/
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) {
case R_TX:
if (s->chr)
- qemu_chr_fe_write(s->chr, &ch, 1);
+ /* 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->regs[addr] = value;
scr_msg_header.type = htonl(type);
scr_msg_header.reader_id = htonl(reader_id);
scr_msg_header.length = htonl(length);
- qemu_chr_fe_write(s->cs, (uint8_t *)&scr_msg_header, sizeof(VSCMsgHeader));
- qemu_chr_fe_write(s->cs, payload, length);
+ /* XXX this blocks entire thread. Rewrite to use
+ * qemu_chr_fe_write and background I/O callbacks */
+ qemu_chr_fe_write_all(s->cs, (uint8_t *)&scr_msg_header,
+ sizeof(VSCMsgHeader));
+ qemu_chr_fe_write_all(s->cs, payload, length);
}
static void ccid_card_vscard_send_apdu(PassthruState *s,
goto fail;
for (i = 0; i < p->iov.niov; i++) {
iov = p->iov.iov + i;
- qemu_chr_fe_write(s->cs, iov->iov_base, iov->iov_len);
+ /* XXX this blocks entire thread. Rewrite to use
+ * qemu_chr_fe_write and background I/O callbacks */
+ qemu_chr_fe_write_all(s->cs, iov->iov_base, iov->iov_len);
}
p->actual_length = p->iov.size;
break;
ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
{
if (so->s == -1 && so->extra) {
- qemu_chr_fe_write(so->extra, buf, len);
+ /* XXX this blocks entire thread. Rewrite to use
+ * qemu_chr_fe_write and background I/O callbacks */
+ qemu_chr_fe_write_all(so->extra, buf, len);
return len;
}