diff options
Diffstat (limited to 'hw')
34 files changed, 351 insertions, 152 deletions
diff --git a/hw/arm/omap2.c b/hw/arm/omap2.c index 3a0d77714a..7e11c65cba 100644 --- a/hw/arm/omap2.c +++ b/hw/arm/omap2.c @@ -769,14 +769,16 @@ static void omap_sti_fifo_write(void *opaque, hwaddr addr, 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); } } diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index cb55704687..0241e07d84 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -1903,7 +1903,9 @@ static void pxa2xx_fir_write(void *opaque, hwaddr addr, 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); diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c index f1b2c6c966..021cbf9a0f 100644 --- a/hw/arm/strongarm.c +++ b/hw/arm/strongarm.c @@ -1108,7 +1108,9 @@ static void strongarm_uart_tx(void *opaque) 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; diff --git a/hw/char/bcm2835_aux.c b/hw/char/bcm2835_aux.c index 319f1652f6..f7a845d3e2 100644 --- a/hw/char/bcm2835_aux.c +++ b/hw/char/bcm2835_aux.c @@ -169,7 +169,9 @@ static void bcm2835_aux_write(void *opaque, hwaddr offset, uint64_t value, /* "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; diff --git a/hw/char/debugcon.c b/hw/char/debugcon.c index e7f025ec67..4402033861 100644 --- a/hw/char/debugcon.c +++ b/hw/char/debugcon.c @@ -60,7 +60,9 @@ static void debugcon_ioport_write(void *opaque, hwaddr addr, uint64_t val, 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); } diff --git a/hw/char/digic-uart.c b/hw/char/digic-uart.c index c7604e6766..e96a9b2d8d 100644 --- a/hw/char/digic-uart.c +++ b/hw/char/digic-uart.c @@ -77,6 +77,8 @@ static void digic_uart_write(void *opaque, hwaddr addr, uint64_t value, 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; diff --git a/hw/char/escc.c b/hw/char/escc.c index 31a5f902f9..aa1739762b 100644 --- a/hw/char/escc.c +++ b/hw/char/escc.c @@ -557,7 +557,9 @@ static void escc_mem_write(void *opaque, hwaddr addr, 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); } diff --git a/hw/char/etraxfs_ser.c b/hw/char/etraxfs_ser.c index 04ca04fe2c..c99cc5d130 100644 --- a/hw/char/etraxfs_ser.c +++ b/hw/char/etraxfs_ser.c @@ -126,7 +126,9 @@ ser_write(void *opaque, hwaddr addr, 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; diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c index 885ecc027b..1107578138 100644 --- a/hw/char/exynos4210_uart.c +++ b/hw/char/exynos4210_uart.c @@ -387,7 +387,9 @@ static void exynos4210_uart_write(void *opaque, hwaddr offset, 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 diff --git a/hw/char/grlib_apbuart.c b/hw/char/grlib_apbuart.c index 871524c82f..778148a15e 100644 --- a/hw/char/grlib_apbuart.c +++ b/hw/char/grlib_apbuart.c @@ -203,7 +203,9 @@ static void grlib_apbuart_write(void *opaque, hwaddr addr, /* 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); diff --git a/hw/char/imx_serial.c b/hw/char/imx_serial.c index 44856d671e..5c3fa61e4c 100644 --- a/hw/char/imx_serial.c +++ b/hw/char/imx_serial.c @@ -182,7 +182,9 @@ static void imx_serial_write(void *opaque, hwaddr offset, 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); diff --git a/hw/char/ipoctal232.c b/hw/char/ipoctal232.c index 9ead32af60..2859fdd7fb 100644 --- a/hw/char/ipoctal232.c +++ b/hw/char/ipoctal232.c @@ -360,7 +360,9 @@ static void io_write(IPackDevice *ip, uint8_t addr, uint16_t val) 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); diff --git a/hw/char/lm32_juart.c b/hw/char/lm32_juart.c index 28c2cf702d..cb1ac76731 100644 --- a/hw/char/lm32_juart.c +++ b/hw/char/lm32_juart.c @@ -76,6 +76,8 @@ void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx) 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); } } diff --git a/hw/char/lm32_uart.c b/hw/char/lm32_uart.c index b5c760dda3..be93697a39 100644 --- a/hw/char/lm32_uart.c +++ b/hw/char/lm32_uart.c @@ -178,6 +178,8 @@ static void uart_write(void *opaque, hwaddr addr, 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; diff --git a/hw/char/mcf_uart.c b/hw/char/mcf_uart.c index 3c0438fd79..c184859c83 100644 --- a/hw/char/mcf_uart.c +++ b/hw/char/mcf_uart.c @@ -114,7 +114,9 @@ static void mcf_uart_do_tx(mcf_uart_state *s) { 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) { diff --git a/hw/char/parallel.c b/hw/char/parallel.c index fa085667ff..da22e36356 100644 --- a/hw/char/parallel.c +++ b/hw/char/parallel.c @@ -129,7 +129,9 @@ parallel_ioport_write_sw(void *opaque, uint32_t addr, uint32_t val) 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; diff --git a/hw/char/pl011.c b/hw/char/pl011.c index c0fbf8a874..786e605fdd 100644 --- a/hw/char/pl011.c +++ b/hw/char/pl011.c @@ -146,7 +146,9 @@ static void pl011_write(void *opaque, hwaddr offset, /* ??? 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; diff --git a/hw/char/sclpconsole-lm.c b/hw/char/sclpconsole-lm.c index a22ad8d016..9a563269e6 100644 --- a/hw/char/sclpconsole-lm.c +++ b/hw/char/sclpconsole-lm.c @@ -89,7 +89,9 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) 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); } } @@ -191,9 +193,6 @@ static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr, */ static int write_console_data(SCLPEvent *event, const uint8_t *buf, int len) { - int ret = 0; - const uint8_t *buf_offset; - SCLPConsoleLM *scon = SCLPLM_CONSOLE(event); if (!scon->chr) { @@ -201,21 +200,9 @@ static int write_console_data(SCLPEvent *event, const uint8_t *buf, int len) return len; } - buf_offset = buf; - while (len > 0) { - ret = qemu_chr_fe_write(scon->chr, buf, len); - if (ret == 0) { - /* a pty doesn't seem to be connected - no error */ - len = 0; - } else if (ret == -EAGAIN || (ret > 0 && ret < len)) { - len -= ret; - buf_offset += ret; - } else { - len = 0; - } - } - - return ret; + /* 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 int process_mdb(SCLPEvent *event, MDBO *mdbo) diff --git a/hw/char/sclpconsole.c b/hw/char/sclpconsole.c index d22464826b..a75ad4f60a 100644 --- a/hw/char/sclpconsole.c +++ b/hw/char/sclpconsole.c @@ -168,6 +168,8 @@ static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf, 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); } diff --git a/hw/char/sh_serial.c b/hw/char/sh_serial.c index 4c55dcb7dc..97ce5629a4 100644 --- a/hw/char/sh_serial.c +++ b/hw/char/sh_serial.c @@ -111,7 +111,9 @@ static void sh_serial_write(void *opaque, hwaddr offs, 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; diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c index 3498d7b052..9aeafc0c42 100644 --- a/hw/char/spapr_vty.c +++ b/hw/char/spapr_vty.c @@ -60,8 +60,9 @@ void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len) { 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) diff --git a/hw/char/stm32f2xx_usart.c b/hw/char/stm32f2xx_usart.c index 15657abda9..4c6640dbe9 100644 --- a/hw/char/stm32f2xx_usart.c +++ b/hw/char/stm32f2xx_usart.c @@ -153,6 +153,8 @@ static void stm32f2xx_usart_write(void *opaque, hwaddr addr, 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; diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c index 4f0e03d3b7..d44c18c128 100644 --- a/hw/char/virtio-console.c +++ b/hw/char/virtio-console.c @@ -68,6 +68,27 @@ static ssize_t flush_buf(VirtIOSerialPort *port, */ 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) { diff --git a/hw/char/xilinx_uartlite.c b/hw/char/xilinx_uartlite.c index 4847efb29f..3766dc2c5b 100644 --- a/hw/char/xilinx_uartlite.c +++ b/hw/char/xilinx_uartlite.c @@ -144,7 +144,9 @@ uart_write(void *opaque, hwaddr addr, 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; diff --git a/hw/dma/i8257.c b/hw/dma/i8257.c index bffbdea0ca..8bd82e8bc8 100644 --- a/hw/dma/i8257.c +++ b/hw/dma/i8257.c @@ -600,6 +600,8 @@ static void i8257_class_init(ObjectClass *klass, void *data) idc->release_DREQ = i8257_dma_release_DREQ; idc->schedule = i8257_dma_schedule; idc->register_channel = i8257_dma_register_channel; + /* Reason: needs to be wired up by isa_bus_dma() to work */ + dc->cannot_instantiate_with_device_add_yet = true; } static const TypeInfo i8257_info = { diff --git a/hw/i386/kvm/apic.c b/hw/i386/kvm/apic.c index 2bd0de82b4..5d140b9341 100644 --- a/hw/i386/kvm/apic.c +++ b/hw/i386/kvm/apic.c @@ -28,9 +28,8 @@ static inline uint32_t kvm_apic_get_reg(struct kvm_lapic_state *kapic, return *((uint32_t *)(kapic->regs + (reg_id << 4))); } -void kvm_put_apic_state(DeviceState *dev, struct kvm_lapic_state *kapic) +static void kvm_put_apic_state(APICCommonState *s, struct kvm_lapic_state *kapic) { - APICCommonState *s = APIC_COMMON(dev); int i; memset(kapic, 0, sizeof(*kapic)); @@ -125,6 +124,27 @@ static void kvm_apic_vapic_base_update(APICCommonState *s) } } +static void kvm_apic_put(void *data) +{ + APICCommonState *s = data; + struct kvm_lapic_state kapic; + int ret; + + kvm_put_apic_state(s, &kapic); + + ret = kvm_vcpu_ioctl(CPU(s->cpu), KVM_SET_LAPIC, &kapic); + if (ret < 0) { + fprintf(stderr, "KVM_SET_LAPIC failed: %s\n", strerror(ret)); + abort(); + } +} + +static void kvm_apic_post_load(APICCommonState *s) +{ + fprintf(stderr, "%s: Yeh\n", __func__); + run_on_cpu(CPU(s->cpu), kvm_apic_put, s); +} + static void do_inject_external_nmi(void *data) { APICCommonState *s = data; @@ -178,6 +198,8 @@ static void kvm_apic_reset(APICCommonState *s) { /* Not used by KVM, which uses the CPU mp_state instead. */ s->wait_for_sipi = 0; + + run_on_cpu(CPU(s->cpu), kvm_apic_put, s); } static void kvm_apic_realize(DeviceState *dev, Error **errp) @@ -206,6 +228,7 @@ static void kvm_apic_class_init(ObjectClass *klass, void *data) k->set_base = kvm_apic_set_base; k->set_tpr = kvm_apic_set_tpr; k->get_tpr = kvm_apic_get_tpr; + k->post_load = kvm_apic_post_load; k->enable_tpr_reporting = kvm_apic_enable_tpr_reporting; k->vapic_base_update = kvm_apic_vapic_base_update; k->external_nmi = kvm_apic_external_nmi; diff --git a/hw/ipmi/ipmi_bmc_extern.c b/hw/ipmi/ipmi_bmc_extern.c index 5b73983e7d..d93e3f3426 100644 --- a/hw/ipmi/ipmi_bmc_extern.c +++ b/hw/ipmi/ipmi_bmc_extern.c @@ -100,12 +100,16 @@ ipmb_checksum(const unsigned char *data, int size, unsigned char start) static void continue_send(IPMIBmcExtern *ibe) { + int ret; if (ibe->outlen == 0) { goto check_reset; } send: - ibe->outpos += qemu_chr_fe_write(ibe->chr, ibe->outbuf + ibe->outpos, - ibe->outlen - ibe->outpos); + ret = qemu_chr_fe_write(ibe->chr, ibe->outbuf + ibe->outpos, + ibe->outlen - ibe->outpos); + if (ret > 0) { + ibe->outpos += ret; + } if (ibe->outpos < ibe->outlen) { /* Not fully transmitted, try again in a 10ms */ timer_mod_ns(ibe->extern_timer, diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c index df205cdafe..feb1191315 100644 --- a/hw/scsi/lsi53c895a.c +++ b/hw/scsi/lsi53c895a.c @@ -19,6 +19,7 @@ #include "hw/pci/pci.h" #include "hw/scsi/scsi.h" #include "sysemu/dma.h" +#include "qemu/log.h" //#define DEBUG_LSI //#define DEBUG_LSI_REG @@ -34,6 +35,21 @@ do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__); exit(1);} while do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0) #endif +static const char *names[] = { + "SCNTL0", "SCNTL1", "SCNTL2", "SCNTL3", "SCID", "SXFER", "SDID", "GPREG", + "SFBR", "SOCL", "SSID", "SBCL", "DSTAT", "SSTAT0", "SSTAT1", "SSTAT2", + "DSA0", "DSA1", "DSA2", "DSA3", "ISTAT", "0x15", "0x16", "0x17", + "CTEST0", "CTEST1", "CTEST2", "CTEST3", "TEMP0", "TEMP1", "TEMP2", "TEMP3", + "DFIFO", "CTEST4", "CTEST5", "CTEST6", "DBC0", "DBC1", "DBC2", "DCMD", + "DNAD0", "DNAD1", "DNAD2", "DNAD3", "DSP0", "DSP1", "DSP2", "DSP3", + "DSPS0", "DSPS1", "DSPS2", "DSPS3", "SCRATCHA0", "SCRATCHA1", "SCRATCHA2", "SCRATCHA3", + "DMODE", "DIEN", "SBR", "DCNTL", "ADDER0", "ADDER1", "ADDER2", "ADDER3", + "SIEN0", "SIEN1", "SIST0", "SIST1", "SLPAR", "0x45", "MACNTL", "GPCNTL", + "STIME0", "STIME1", "RESPID", "0x4b", "STEST0", "STEST1", "STEST2", "STEST3", + "SIDL", "0x51", "0x52", "0x53", "SODL", "0x55", "0x56", "0x57", + "SBDL", "0x59", "0x5a", "0x5b", "SCRATCHB0", "SCRATCHB1", "SCRATCHB2", "SCRATCHB3", +}; + #define LSI_MAX_DEVS 7 #define LSI_SCNTL0_TRG 0x01 @@ -194,6 +210,7 @@ typedef struct { MemoryRegion mmio_io; MemoryRegion ram_io; MemoryRegion io_io; + AddressSpace pci_io_as; int carry; /* ??? Should this be an a visible register somewhere? */ int status; @@ -309,7 +326,7 @@ static void lsi_soft_reset(LSIState *s) s->istat0 = 0; s->istat1 = 0; s->dcmd = 0x40; - s->dstat = LSI_DSTAT_DFE; + s->dstat = 0; s->dien = 0; s->sist0 = 0; s->sist1 = 0; @@ -391,6 +408,30 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val); static void lsi_execute_script(LSIState *s); static void lsi_reselect(LSIState *s, lsi_request *p); +static inline int lsi_mem_read(LSIState *s, dma_addr_t addr, + void *buf, dma_addr_t len) +{ + if (s->dmode & LSI_DMODE_SIOM) { + address_space_read(&s->pci_io_as, addr, MEMTXATTRS_UNSPECIFIED, + buf, len); + return 0; + } else { + return pci_dma_read(PCI_DEVICE(s), addr, buf, len); + } +} + +static inline int lsi_mem_write(LSIState *s, dma_addr_t addr, + const void *buf, dma_addr_t len) +{ + if (s->dmode & LSI_DMODE_DIOM) { + address_space_write(&s->pci_io_as, addr, MEMTXATTRS_UNSPECIFIED, + buf, len); + return 0; + } else { + return pci_dma_write(PCI_DEVICE(s), addr, buf, len); + } +} + static inline uint32_t read_dword(LSIState *s, uint32_t addr) { uint32_t buf; @@ -534,7 +575,6 @@ static void lsi_bad_selection(LSIState *s, uint32_t id) /* Initiate a SCSI layer data transfer. */ static void lsi_do_dma(LSIState *s, int out) { - PCIDevice *pci_dev; uint32_t count; dma_addr_t addr; SCSIDevice *dev; @@ -546,7 +586,6 @@ static void lsi_do_dma(LSIState *s, int out) return; } - pci_dev = PCI_DEVICE(s); dev = s->current->req->dev; assert(dev); @@ -572,9 +611,9 @@ static void lsi_do_dma(LSIState *s, int out) } /* ??? Set SFBR to first data byte. */ if (out) { - pci_dma_read(pci_dev, addr, s->current->dma_buf, count); + lsi_mem_read(s, addr, s->current->dma_buf, count); } else { - pci_dma_write(pci_dev, addr, s->current->dma_buf, count); + lsi_mem_write(s, addr, s->current->dma_buf, count); } s->current->dma_len -= count; if (s->current->dma_len == 0) { @@ -1006,15 +1045,14 @@ bad: #define LSI_BUF_SIZE 4096 static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count) { - PCIDevice *d = PCI_DEVICE(s); int n; uint8_t buf[LSI_BUF_SIZE]; DPRINTF("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count); while (count) { n = (count > LSI_BUF_SIZE) ? LSI_BUF_SIZE : count; - pci_dma_read(d, src, buf, n); - pci_dma_write(d, dest, buf, n); + lsi_mem_read(s, src, buf, n); + lsi_mem_write(s, dest, buf, n); src += n; dest += n; count -= n; @@ -1480,155 +1518,200 @@ again: static uint8_t lsi_reg_readb(LSIState *s, int offset) { - uint8_t tmp; + uint8_t ret; + #define CASE_GET_REG24(name, addr) \ - case addr: return s->name & 0xff; \ - case addr + 1: return (s->name >> 8) & 0xff; \ - case addr + 2: return (s->name >> 16) & 0xff; + case addr: ret = s->name & 0xff; break; \ + case addr + 1: ret = (s->name >> 8) & 0xff; break; \ + case addr + 2: ret = (s->name >> 16) & 0xff; break; #define CASE_GET_REG32(name, addr) \ - case addr: return s->name & 0xff; \ - case addr + 1: return (s->name >> 8) & 0xff; \ - case addr + 2: return (s->name >> 16) & 0xff; \ - case addr + 3: return (s->name >> 24) & 0xff; + case addr: ret = s->name & 0xff; break; \ + case addr + 1: ret = (s->name >> 8) & 0xff; break; \ + case addr + 2: ret = (s->name >> 16) & 0xff; break; \ + case addr + 3: ret = (s->name >> 24) & 0xff; break; -#ifdef DEBUG_LSI_REG - DPRINTF("Read reg %x\n", offset); -#endif switch (offset) { case 0x00: /* SCNTL0 */ - return s->scntl0; + ret = s->scntl0; + break; case 0x01: /* SCNTL1 */ - return s->scntl1; + ret = s->scntl1; + break; case 0x02: /* SCNTL2 */ - return s->scntl2; + ret = s->scntl2; + break; case 0x03: /* SCNTL3 */ - return s->scntl3; + ret = s->scntl3; + break; case 0x04: /* SCID */ - return s->scid; + ret = s->scid; + break; case 0x05: /* SXFER */ - return s->sxfer; + ret = s->sxfer; + break; case 0x06: /* SDID */ - return s->sdid; + ret = s->sdid; + break; case 0x07: /* GPREG0 */ - return 0x7f; + ret = 0x7f; + break; case 0x08: /* Revision ID */ - return 0x00; + ret = 0x00; + break; case 0x09: /* SOCL */ - return s->socl; + ret = s->socl; + break; case 0xa: /* SSID */ - return s->ssid; + ret = s->ssid; + break; case 0xb: /* SBCL */ /* ??? This is not correct. However it's (hopefully) only used for diagnostics, so should be ok. */ - return 0; + ret = 0; + break; case 0xc: /* DSTAT */ - tmp = s->dstat | LSI_DSTAT_DFE; + ret = s->dstat | LSI_DSTAT_DFE; if ((s->istat0 & LSI_ISTAT0_INTF) == 0) s->dstat = 0; lsi_update_irq(s); - return tmp; + break; case 0x0d: /* SSTAT0 */ - return s->sstat0; + ret = s->sstat0; + break; case 0x0e: /* SSTAT1 */ - return s->sstat1; + ret = s->sstat1; + break; case 0x0f: /* SSTAT2 */ - return s->scntl1 & LSI_SCNTL1_CON ? 0 : 2; + ret = s->scntl1 & LSI_SCNTL1_CON ? 0 : 2; + break; CASE_GET_REG32(dsa, 0x10) case 0x14: /* ISTAT0 */ - return s->istat0; + ret = s->istat0; + break; case 0x15: /* ISTAT1 */ - return s->istat1; + ret = s->istat1; + break; case 0x16: /* MBOX0 */ - return s->mbox0; + ret = s->mbox0; + break; case 0x17: /* MBOX1 */ - return s->mbox1; + ret = s->mbox1; + break; case 0x18: /* CTEST0 */ - return 0xff; + ret = 0xff; + break; case 0x19: /* CTEST1 */ - return 0; + ret = 0; + break; case 0x1a: /* CTEST2 */ - tmp = s->ctest2 | LSI_CTEST2_DACK | LSI_CTEST2_CM; + ret = s->ctest2 | LSI_CTEST2_DACK | LSI_CTEST2_CM; if (s->istat0 & LSI_ISTAT0_SIGP) { s->istat0 &= ~LSI_ISTAT0_SIGP; - tmp |= LSI_CTEST2_SIGP; + ret |= LSI_CTEST2_SIGP; } - return tmp; + break; case 0x1b: /* CTEST3 */ - return s->ctest3; + ret = s->ctest3; + break; CASE_GET_REG32(temp, 0x1c) case 0x20: /* DFIFO */ - return 0; + ret = 0; + break; case 0x21: /* CTEST4 */ - return s->ctest4; + ret = s->ctest4; + break; case 0x22: /* CTEST5 */ - return s->ctest5; + ret = s->ctest5; + break; case 0x23: /* CTEST6 */ - return 0; + ret = 0; + break; CASE_GET_REG24(dbc, 0x24) case 0x27: /* DCMD */ - return s->dcmd; + ret = s->dcmd; + break; CASE_GET_REG32(dnad, 0x28) CASE_GET_REG32(dsp, 0x2c) CASE_GET_REG32(dsps, 0x30) CASE_GET_REG32(scratch[0], 0x34) case 0x38: /* DMODE */ - return s->dmode; + ret = s->dmode; + break; case 0x39: /* DIEN */ - return s->dien; + ret = s->dien; + break; case 0x3a: /* SBR */ - return s->sbr; + ret = s->sbr; + break; case 0x3b: /* DCNTL */ - return s->dcntl; + ret = s->dcntl; + break; /* ADDER Output (Debug of relative jump address) */ CASE_GET_REG32(adder, 0x3c) case 0x40: /* SIEN0 */ - return s->sien0; + ret = s->sien0; + break; case 0x41: /* SIEN1 */ - return s->sien1; + ret = s->sien1; + break; case 0x42: /* SIST0 */ - tmp = s->sist0; + ret = s->sist0; s->sist0 = 0; lsi_update_irq(s); - return tmp; + break; case 0x43: /* SIST1 */ - tmp = s->sist1; + ret = s->sist1; s->sist1 = 0; lsi_update_irq(s); - return tmp; + break; case 0x46: /* MACNTL */ - return 0x0f; + ret = 0x0f; + break; case 0x47: /* GPCNTL0 */ - return 0x0f; + ret = 0x0f; + break; case 0x48: /* STIME0 */ - return s->stime0; + ret = s->stime0; + break; case 0x4a: /* RESPID0 */ - return s->respid0; + ret = s->respid0; + break; case 0x4b: /* RESPID1 */ - return s->respid1; + ret = s->respid1; + break; case 0x4d: /* STEST1 */ - return s->stest1; + ret = s->stest1; + break; case 0x4e: /* STEST2 */ - return s->stest2; + ret = s->stest2; + break; case 0x4f: /* STEST3 */ - return s->stest3; + ret = s->stest3; + break; case 0x50: /* SIDL */ /* This is needed by the linux drivers. We currently only update it during the MSG IN phase. */ - return s->sidl; + ret = s->sidl; + break; case 0x52: /* STEST4 */ - return 0xe0; + ret = 0xe0; + break; case 0x56: /* CCNTL0 */ - return s->ccntl0; + ret = s->ccntl0; + break; case 0x57: /* CCNTL1 */ - return s->ccntl1; + ret = s->ccntl1; + break; case 0x58: /* SBDL */ /* Some drivers peek at the data bus during the MSG IN phase. */ if ((s->sstat1 & PHASE_MASK) == PHASE_MI) return s->msg[0]; - return 0; + ret = 0; + break; case 0x59: /* SBDL high */ - return 0; + ret = 0; + break; CASE_GET_REG32(mmrs, 0xa0) CASE_GET_REG32(mmws, 0xa4) CASE_GET_REG32(sfs, 0xa8) @@ -1643,18 +1726,34 @@ static uint8_t lsi_reg_readb(LSIState *s, int offset) CASE_GET_REG32(ia, 0xd4) CASE_GET_REG32(sbc, 0xd8) CASE_GET_REG32(csbc, 0xdc) - } - if (offset >= 0x5c && offset < 0xa0) { + case 0x5c ... 0x9f: + { int n; int shift; n = (offset - 0x58) >> 2; shift = (offset & 3) * 8; - return (s->scratch[n] >> shift) & 0xff; + ret = (s->scratch[n] >> shift) & 0xff; + break; + } + default: + { + qemu_log_mask(LOG_GUEST_ERROR, + "lsi_scsi: invalid read from reg %s %x\n", + offset < ARRAY_SIZE(names) ? names[offset] : "???", + offset); + ret = 0xff; + break; + } } - BADF("readb 0x%x\n", offset); - exit(1); #undef CASE_GET_REG24 #undef CASE_GET_REG32 + +#ifdef DEBUG_LSI_REG + DPRINTF("Read reg %s %x = %02x\n", + offset < ARRAY_SIZE(names) ? names[offset] : "???", offset, ret); +#endif + + return ret; } static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) @@ -1671,7 +1770,8 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) case addr + 3: s->name &= 0x00ffffff; s->name |= val << 24; break; #ifdef DEBUG_LSI_REG - DPRINTF("Write reg %x = %02x\n", offset, val); + DPRINTF("Write reg %s %x = %02x\n", + offset < ARRAY_SIZE(names) ? names[offset] : "???", offset, val); #endif switch (offset) { case 0x00: /* SCNTL0 */ @@ -1799,9 +1899,6 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) CASE_SET_REG32(dsps, 0x30) CASE_SET_REG32(scratch[0], 0x34) case 0x38: /* DMODE */ - if (val & (LSI_DMODE_SIOM | LSI_DMODE_DIOM)) { - BADF("IO mappings not implemented\n"); - } s->dmode = val; break; case 0x39: /* DIEN */ @@ -1886,7 +1983,10 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) shift = (offset & 3) * 8; s->scratch[n] = deposit32(s->scratch[n], shift, 8, val); } else { - BADF("Unhandled writeb 0x%x = 0x%x\n", offset, val); + qemu_log_mask(LOG_GUEST_ERROR, + "lsi_scsi: invalid write to reg %s %x (0x%02x)\n", + offset < ARRAY_SIZE(names) ? names[offset] : "???", + offset, val); } } #undef CASE_SET_REG24 @@ -2108,6 +2208,8 @@ static void lsi_scsi_realize(PCIDevice *dev, Error **errp) memory_region_init_io(&s->io_io, OBJECT(s), &lsi_io_ops, s, "lsi-io", 256); + address_space_init(&s->pci_io_as, pci_address_space_io(dev), "lsi-pci-io"); + pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_io); pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio_io); pci_register_bar(dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ram_io); @@ -2119,6 +2221,13 @@ static void lsi_scsi_realize(PCIDevice *dev, Error **errp) } } +static void lsi_scsi_unrealize(DeviceState *dev, Error **errp) +{ + LSIState *s = LSI53C895A(dev); + + address_space_destroy(&s->pci_io_as); +} + static void lsi_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -2129,6 +2238,7 @@ static void lsi_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_LSI_53C895A; k->class_id = PCI_CLASS_STORAGE_SCSI; k->subsystem_id = 0x1000; + dc->unrealize = lsi_scsi_unrealize; dc->reset = lsi_scsi_reset; dc->vmsd = &vmstate_lsi_scsi; set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index e968302fdc..52a41239cf 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -1981,7 +1981,11 @@ static void megasas_handle_frame(MegasasState *s, uint64_t frame_addr, break; } if (frame_status != MFI_STAT_INVALID_STATUS) { - cmd->frame->header.cmd_status = frame_status; + if (cmd->frame) { + cmd->frame->header.cmd_status = frame_status; + } else { + megasas_frame_set_cmd_status(s, frame_addr, frame_status); + } megasas_unmap_frame(s, cmd); megasas_complete_frame(s, cmd->context); } diff --git a/hw/scsi/mptconfig.c b/hw/scsi/mptconfig.c index 707185469e..87a416a5cb 100644 --- a/hw/scsi/mptconfig.c +++ b/hw/scsi/mptconfig.c @@ -158,7 +158,7 @@ static size_t mptsas_config_pack(uint8_t **data, const char *fmt, ...) va_end(ap); if (data) { - assert(ret < 256 && (ret % 4) == 0); + assert(ret / 4 < 256 && (ret % 4) == 0); stb_p(*data + 1, ret / 4); } return ret; @@ -203,7 +203,7 @@ size_t mptsas_config_manufacturing_1(MPTSASState *s, uint8_t **data, int address { /* VPD - all zeros */ return MPTSAS_CONFIG_PACK(1, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00, - "s256"); + "*s256"); } static @@ -328,7 +328,7 @@ size_t mptsas_config_ioc_0(MPTSASState *s, uint8_t **data, int address) return MPTSAS_CONFIG_PACK(0, MPI_CONFIG_PAGETYPE_IOC, 0x01, "*l*lwwb*b*b*blww", pcic->vendor_id, pcic->device_id, pcic->revision, - pcic->subsystem_vendor_id, + pcic->class_id, pcic->subsystem_vendor_id, pcic->subsystem_id); } diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 99c9d618da..77cba31e30 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -599,8 +599,8 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) } l = strlen(s->serial); - if (l > 20) { - l = 20; + if (l > 36) { + l = 36; } DPRINTF("Inquiry EVPD[Serial number] " diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index 5116f4ad68..babac5a68a 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -40,6 +40,8 @@ #define PVSCSI_MAX_DEVS (64) #define PVSCSI_MSIX_NUM_VECTORS (1) +#define PVSCSI_MAX_SG_ELEM 2048 + #define PVSCSI_MAX_CMD_DATA_WORDS \ (sizeof(PVSCSICmdDescSetupRings)/sizeof(uint32_t)) @@ -152,7 +154,7 @@ pvscsi_log2(uint32_t input) return log; } -static int +static void pvscsi_ring_init_data(PVSCSIRingInfo *m, PVSCSICmdDescSetupRings *ri) { int i; @@ -160,10 +162,6 @@ pvscsi_ring_init_data(PVSCSIRingInfo *m, PVSCSICmdDescSetupRings *ri) uint32_t req_ring_size, cmp_ring_size; m->rs_pa = ri->ringsStatePPN << VMW_PAGE_SHIFT; - if ((ri->reqRingNumPages > PVSCSI_SETUP_RINGS_MAX_NUM_PAGES) - || (ri->cmpRingNumPages > PVSCSI_SETUP_RINGS_MAX_NUM_PAGES)) { - return -1; - } req_ring_size = ri->reqRingNumPages * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE; cmp_ring_size = ri->cmpRingNumPages * PVSCSI_MAX_NUM_CMP_ENTRIES_PER_PAGE; txr_len_log2 = pvscsi_log2(req_ring_size - 1); @@ -195,8 +193,6 @@ pvscsi_ring_init_data(PVSCSIRingInfo *m, PVSCSICmdDescSetupRings *ri) /* Flush ring state page changes */ smp_wmb(); - - return 0; } static int @@ -634,17 +630,16 @@ pvscsi_queue_pending_descriptor(PVSCSIState *s, SCSIDevice **d, static void pvscsi_convert_sglist(PVSCSIRequest *r) { - int chunk_size; + uint32_t chunk_size, elmcnt = 0; uint64_t data_length = r->req.dataLen; PVSCSISGState sg = r->sg; - while (data_length) { - while (!sg.resid) { + while (data_length && elmcnt < PVSCSI_MAX_SG_ELEM) { + while (!sg.resid && elmcnt++ < PVSCSI_MAX_SG_ELEM) { pvscsi_get_next_sg_elem(&sg); trace_pvscsi_convert_sglist(r->req.context, r->sg.dataAddr, r->sg.resid); } - assert(data_length > 0); - chunk_size = MIN((unsigned) data_length, sg.resid); + chunk_size = MIN(data_length, sg.resid); if (chunk_size) { qemu_sglist_add(&r->sgl, sg.dataAddr, chunk_size); } @@ -746,7 +741,7 @@ pvscsi_dbg_dump_tx_rings_config(PVSCSICmdDescSetupRings *rc) trace_pvscsi_tx_rings_num_pages("Confirm Ring", rc->cmpRingNumPages); for (i = 0; i < rc->cmpRingNumPages; i++) { - trace_pvscsi_tx_rings_ppn("Confirm Ring", rc->reqRingPPNs[i]); + trace_pvscsi_tx_rings_ppn("Confirm Ring", rc->cmpRingPPNs[i]); } } @@ -779,11 +774,16 @@ pvscsi_on_cmd_setup_rings(PVSCSIState *s) trace_pvscsi_on_cmd_arrived("PVSCSI_CMD_SETUP_RINGS"); - pvscsi_dbg_dump_tx_rings_config(rc); - if (pvscsi_ring_init_data(&s->rings, rc) < 0) { + if (!rc->reqRingNumPages + || rc->reqRingNumPages > PVSCSI_SETUP_RINGS_MAX_NUM_PAGES + || !rc->cmpRingNumPages + || rc->cmpRingNumPages > PVSCSI_SETUP_RINGS_MAX_NUM_PAGES) { return PVSCSI_COMMAND_PROCESSING_FAILED; } + pvscsi_dbg_dump_tx_rings_config(rc); + pvscsi_ring_init_data(&s->rings, rc); + s->rings_info_valid = TRUE; return PVSCSI_COMMAND_PROCESSING_SUCCEEDED; } diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c index c0e90e501c..2eacea72f3 100644 --- a/hw/usb/ccid-card-passthru.c +++ b/hw/usb/ccid-card-passthru.c @@ -75,8 +75,11 @@ static void ccid_card_vscard_send_msg(PassthruState *s, 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, diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c index ba8538e60e..966ad84b90 100644 --- a/hw/usb/dev-serial.c +++ b/hw/usb/dev-serial.c @@ -366,7 +366,9 @@ static void usb_serial_handle_data(USBDevice *dev, USBPacket *p) 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; |