diff options
Diffstat (limited to 'hw')
38 files changed, 924 insertions, 313 deletions
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index dad38870a..a48187fa7 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -73,6 +73,7 @@ typedef struct PIIX4PMState { qemu_irq smi_irq; int kvm_enabled; Notifier machine_ready; + Notifier powerdown_notifier; /* for pci hotplug */ struct gpe_regs gpe_cpu; @@ -368,9 +369,9 @@ static void piix4_reset(void *opaque) piix4_update_hotplug(s); } -static void piix4_powerdown(void *opaque, int irq, int power_failing) +static void piix4_pm_powerdown_req(Notifier *n, void *opaque) { - PIIX4PMState *s = opaque; + PIIX4PMState *s = container_of(n, PIIX4PMState, powerdown_notifier); assert(s != NULL); acpi_pm1_evt_power_down(&s->ar); @@ -427,7 +428,8 @@ static int piix4_pm_initfn(PCIDevice *dev) acpi_pm_tmr_init(&s->ar, pm_tmr_timer); acpi_gpe_init(&s->ar, GPE_LEN); - qemu_system_powerdown = *qemu_allocate_irqs(piix4_powerdown, s, 1); + s->powerdown_notifier.notify = piix4_pm_powerdown_req; + qemu_register_powerdown_notifier(&s->powerdown_notifier); pm_smbus_init(&s->dev.qdev, &s->smb); s->machine_ready.notify = piix4_pm_machine_ready; diff --git a/hw/cadence_uart.c b/hw/cadence_uart.c index d98e53137..f8afc4ed2 100644 --- a/hw/cadence_uart.c +++ b/hw/cadence_uart.c @@ -404,7 +404,7 @@ static uint64_t uart_read(void *opaque, target_phys_addr_t offset, uint32_t c = 0; offset >>= 2; - if (offset > R_MAX) { + if (offset >= R_MAX) { return 0; } else if (offset == R_TX_RX) { uart_read_rx_fifo(s, &c); diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 035cc346b..4284c1e2a 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -2441,6 +2441,8 @@ static uint32_t cirrus_vga_ioport_read(void *opaque, uint32_t addr) VGACommonState *s = &c->vga; int val, index; + qemu_flush_coalesced_mmio_buffer(); + if (vga_ioport_invalid(s, addr)) { val = 0xff; } else { @@ -2534,6 +2536,8 @@ static void cirrus_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) VGACommonState *s = &c->vga; int index; + qemu_flush_coalesced_mmio_buffer(); + /* check port range access depending on color/monochrome mode */ if (vga_ioport_invalid(s, addr)) { return; @@ -2854,6 +2858,7 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci, /* I/O handler for LFB */ memory_region_init_io(&s->cirrus_linear_io, &cirrus_linear_io_ops, s, "cirrus-linear-io", VGA_RAM_SIZE); + memory_region_set_flush_coalesced(&s->cirrus_linear_io); /* I/O handler for LFB */ memory_region_init_io(&s->cirrus_linear_bitblt_io, @@ -2861,10 +2866,12 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci, s, "cirrus-bitblt-mmio", 0x400000); + memory_region_set_flush_coalesced(&s->cirrus_linear_bitblt_io); /* I/O handler for memory-mapped I/O */ memory_region_init_io(&s->cirrus_mmio_io, &cirrus_mmio_io_ops, s, "cirrus-mmio", CIRRUS_PNPMMIO_SIZE); + memory_region_set_flush_coalesced(&s->cirrus_mmio_io); s->real_vram_size = (s->device_id == CIRRUS_ID_CLGD5446) ? 4096 * 1024 : 2048 * 1024; diff --git a/hw/e1000.c b/hw/e1000.c index ae8a6c552..ec3a7c4ec 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -295,6 +295,7 @@ set_rx_control(E1000State *s, int index, uint32_t val) s->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1; DBGOUT(RX, "RCTL: %d, mac_reg[RCTL] = 0x%x\n", s->mac_reg[RDT], s->mac_reg[RCTL]); + qemu_flush_queued_packets(&s->nic->nc); } static void @@ -926,6 +927,9 @@ set_rdt(E1000State *s, int index, uint32_t val) { s->check_rxov = 0; s->mac_reg[index] = val & 0xffff; + if (e1000_has_rxbufs(s, 1)) { + qemu_flush_queued_packets(&s->nic->nc); + } } static void diff --git a/hw/eepro100.c b/hw/eepro100.c index 50d117e35..5b231163d 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -1036,6 +1036,7 @@ static void eepro100_ru_command(EEPRO100State * s, uint8_t val) } set_ru_state(s, ru_ready); s->ru_offset = e100_read_reg4(s, SCBPointer); + qemu_flush_queued_packets(&s->nic->nc); TRACE(OTHER, logout("val=0x%02x (rx start)\n", val)); break; case RX_RESUME: @@ -1770,7 +1771,8 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) if (rfd_command & COMMAND_EL) { /* EL bit is set, so this was the last frame. */ logout("receive: Running out of frames\n"); - set_ru_state(s, ru_suspended); + set_ru_state(s, ru_no_resources); + eepro100_rnr_interrupt(s); } if (rfd_command & COMMAND_S) { /* S bit is set. */ diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 5ea3cadb0..68671bc4d 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -1175,7 +1175,6 @@ void ahci_init(AHCIState *s, DeviceState *qdev, DMAContext *dma, int ports) ad->port_no = i; ad->port.dma = &ad->dma; ad->port.dma->ops = &ahci_dma_ops; - ad->port_regs.cmd = PORT_CMD_SPIN_UP | PORT_CMD_POWER_ON; } } @@ -1199,6 +1198,7 @@ void ahci_reset(AHCIState *s) pr->irq_stat = 0; pr->irq_mask = 0; pr->scr_ctl = 0; + pr->cmd = PORT_CMD_SPIN_UP | PORT_CMD_POWER_ON; ahci_reset_port(s, i); } } diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c index f7f714c72..685cbaa88 100644 --- a/hw/ide/atapi.c +++ b/hw/ide/atapi.c @@ -875,6 +875,12 @@ static void cmd_start_stop_unit(IDEState *s, uint8_t* buf) int sense; bool start = buf[4] & 1; bool loej = buf[4] & 2; /* load on start, eject on !start */ + int pwrcnd = buf[4] & 0xf0; + + if (pwrcnd) { + /* eject/load only happens for power condition == 0 */ + return; + } if (loej) { if (!start && !s->tray_open && s->tray_locked) { diff --git a/hw/ide/core.c b/hw/ide/core.c index d65ef3d58..d6fb69c63 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -53,8 +53,6 @@ static const int smart_attributes[][12] = { { 0x0c, 0x03, 0x00, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* airflow-temperature-celsius */ { 190, 0x03, 0x00, 0x45, 0x45, 0x1f, 0x00, 0x1f, 0x1f, 0x00, 0x00, 0x32}, - /* end of list */ - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }; static int ide_handle_rw_error(IDEState *s, int error, int op); @@ -1468,9 +1466,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) case SMART_READ_THRESH: memset(s->io_buffer, 0, 0x200); s->io_buffer[0] = 0x01; /* smart struct version */ - for (n=0; n<30; n++) { - if (smart_attributes[n][0] == 0) - break; + for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) { s->io_buffer[2+0+(n*12)] = smart_attributes[n][0]; s->io_buffer[2+1+(n*12)] = smart_attributes[n][11]; } @@ -1484,10 +1480,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) case SMART_READ_DATA: memset(s->io_buffer, 0, 0x200); s->io_buffer[0] = 0x01; /* smart struct version */ - for (n=0; n<30; n++) { - if (smart_attributes[n][0] == 0) { - break; - } + for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) { int i; for(i = 0; i < 11; i++) { s->io_buffer[2+i+(n*12)] = smart_attributes[n][i]; diff --git a/hw/imx_avic.c b/hw/imx_avic.c index 4f010e8ee..b1a8fe6d4 100644 --- a/hw/imx_avic.c +++ b/hw/imx_avic.c @@ -6,9 +6,9 @@ * * Copyright (c) 2008 OKL * Copyright (c) 2011 NICTA Pty Ltd - * Originally Written by Hans Jiang + * Originally written by Hans Jiang * - * This code is licenced under the GPL version 2 or later. See + * This code is licensed under the GPL version 2 or later. See * the COPYING file in the top-level directory. * * TODO: implement vectors. diff --git a/hw/imx_timer.c b/hw/imx_timer.c index 16215ccf0..c28c53725 100644 --- a/hw/imx_timer.c +++ b/hw/imx_timer.c @@ -3,10 +3,10 @@ * * Copyright (c) 2008 OK Labs * Copyright (c) 2011 NICTA Pty Ltd - * Originally Written by Hans Jiang + * Originally written by Hans Jiang * Updated by Peter Chubb * - * This code is licenced under GPL version 2 or later. See + * This code is licensed under GPL version 2 or later. See * the COPYING file in the top-level directory. * */ diff --git a/hw/ioh3420.c b/hw/ioh3420.c index 94a537c9b..4d314733b 100644 --- a/hw/ioh3420.c +++ b/hw/ioh3420.c @@ -125,7 +125,6 @@ static int ioh3420_initfn(PCIDevice *d) rc = pcie_chassis_add_slot(s); if (rc < 0) { goto err_pcie_cap; - return rc; } pcie_cap_root_init(d); rc = pcie_aer_init(d, IOH_EP_AER_OFFSET); @@ -5,7 +5,7 @@ * Written by Hans at OK-Labs * Updated by Peter Chubb. * - * This code is licenced under the GPL, version 2 or later. + * This code is licensed under the GPL, version 2 or later. * See the file `COPYING' in the top level directory. * * It (partially) emulates a Kyoto Microcomputer diff --git a/hw/lm4549.c b/hw/lm4549.c index 80b3ec4a5..e0137d54b 100644 --- a/hw/lm4549.c +++ b/hw/lm4549.c @@ -224,7 +224,7 @@ uint32_t lm4549_write_samples(lm4549_state *s, uint32_t left, uint32_t right) This model supports 16-bit playback. */ - if (s->buffer_level >= LM4549_BUFFER_SIZE) { + if (s->buffer_level > LM4549_BUFFER_SIZE - 2) { DPRINTF("write_sample Buffer full\n"); return 0; } diff --git a/hw/nseries.c b/hw/nseries.c index 4df267032..6df71ebb4 100644 --- a/hw/nseries.c +++ b/hw/nseries.c @@ -189,6 +189,17 @@ static void n8x0_nand_setup(struct n800_s *s) /* XXX: in theory should also update the OOB for both pages */ } +static qemu_irq n8x0_system_powerdown; + +static void n8x0_powerdown_req(Notifier *n, void *opaque) +{ + qemu_irq_raise(n8x0_system_powerdown); +} + +static Notifier n8x0_system_powerdown_notifier = { + .notify = n8x0_powerdown_req +}; + static void n8x0_i2c_setup(struct n800_s *s) { DeviceState *dev; @@ -201,7 +212,8 @@ static void n8x0_i2c_setup(struct n800_s *s) qdev_get_gpio_in(s->mpu->ih[0], OMAP_INT_24XX_SYS_NIRQ)); - qemu_system_powerdown = qdev_get_gpio_in(dev, 3); + n8x0_system_powerdown = qdev_get_gpio_in(dev, 3); + qemu_register_powerdown_notifier(&n8x0_system_powerdown_notifier); /* Attach a TMP105 PM chip (A0 wired to ground) */ dev = i2c_create_slave(i2c, "tmp105", N8X0_TMP105_ADDR); diff --git a/hw/pc_piix.c b/hw/pc_piix.c index a771d7982..7229d2f16 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -359,8 +359,8 @@ static void pc_xen_hvm_init(ram_addr_t ram_size, #define KVM_MACHINE_OPTIONS "" #endif -static QEMUMachine pc_machine_v1_2 = { - .name = "pc-1.2", +static QEMUMachine pc_machine_v1_3 = { + .name = "pc-1.3", .alias = "pc", .desc = "Standard PC", .init = pc_init_pci, @@ -369,6 +369,13 @@ static QEMUMachine pc_machine_v1_2 = { .default_machine_opts = KVM_MACHINE_OPTIONS, }; +static QEMUMachine pc_machine_v1_2 = { + .name = "pc-1.2", + .desc = "Standard PC", + .init = pc_init_pci, + .max_cpus = 255, +}; + #define PC_COMPAT_1_1 \ {\ .driver = "virtio-scsi-pci",\ @@ -675,6 +682,7 @@ static QEMUMachine xenfv_machine = { static void pc_machine_init(void) { + qemu_register_machine(&pc_machine_v1_3); qemu_register_machine(&pc_machine_v1_2); qemu_register_machine(&pc_machine_v1_1); qemu_register_machine(&pc_machine_v1_0); diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c index d1c742379..855890d1f 100644 --- a/hw/pflash_cfi01.c +++ b/hw/pflash_cfi01.c @@ -41,6 +41,7 @@ #include "block.h" #include "qemu-timer.h" #include "exec-memory.h" +#include "host-utils.h" #define PFLASH_BUG(fmt, ...) \ do { \ @@ -320,7 +321,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset, } pfl->wcycle++; pfl->cmd = cmd; - return; + break; case 1: switch (pfl->cmd) { case 0x10: /* Single Byte Program */ @@ -375,7 +376,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset, default: goto error_flash; } - return; + break; case 2: switch (pfl->cmd) { case 0xe8: /* Block write */ @@ -406,7 +407,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset, default: goto error_flash; } - return; + break; case 3: /* Confirm mode */ switch (pfl->cmd) { case 0xe8: /* Block write */ @@ -422,7 +423,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset, default: goto error_flash; } - return; + break; default: /* Should never happen */ DPRINTF("%s: invalid write state\n", __func__); @@ -543,42 +544,6 @@ static const MemoryRegionOps pflash_cfi01_ops_le = { .endianness = DEVICE_NATIVE_ENDIAN, }; -/* Count trailing zeroes of a 32 bits quantity */ -static int ctz32 (uint32_t n) -{ - int ret; - - ret = 0; - if (!(n & 0xFFFF)) { - ret += 16; - n = n >> 16; - } - if (!(n & 0xFF)) { - ret += 8; - n = n >> 8; - } - if (!(n & 0xF)) { - ret += 4; - n = n >> 4; - } - if (!(n & 0x3)) { - ret += 2; - n = n >> 2; - } - if (!(n & 0x1)) { - ret++; -#if 0 /* This is not necessary as n is never 0 */ - n = n >> 1; -#endif - } -#if 0 /* This is not necessary as n is never 0 */ - if (!n) - ret++; -#endif - - return ret; -} - pflash_t *pflash_cfi01_register(target_phys_addr_t base, DeviceState *qdev, const char *name, target_phys_addr_t size, @@ -711,7 +676,7 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base, pfl->cfi_table[0x33] = 'I'; pfl->cfi_table[0x34] = '1'; - pfl->cfi_table[0x35] = '1'; + pfl->cfi_table[0x35] = '0'; pfl->cfi_table[0x36] = 0x00; pfl->cfi_table[0x37] = 0x00; @@ -723,6 +688,8 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base, pfl->cfi_table[0x3b] = 0x00; pfl->cfi_table[0x3c] = 0x00; + pfl->cfi_table[0x3f] = 0x01; /* Number of protection fields */ + return pfl; } diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c index 3e2002e4b..8cb154958 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -40,6 +40,7 @@ #include "qemu-timer.h" #include "block.h" #include "exec-memory.h" +#include "host-utils.h" //#define PFLASH_DEBUG #ifdef PFLASH_DEBUG @@ -575,42 +576,6 @@ static const MemoryRegionOps pflash_cfi02_ops_le = { .endianness = DEVICE_NATIVE_ENDIAN, }; -/* Count trailing zeroes of a 32 bits quantity */ -static int ctz32 (uint32_t n) -{ - int ret; - - ret = 0; - if (!(n & 0xFFFF)) { - ret += 16; - n = n >> 16; - } - if (!(n & 0xFF)) { - ret += 8; - n = n >> 8; - } - if (!(n & 0xF)) { - ret += 4; - n = n >> 4; - } - if (!(n & 0x3)) { - ret += 2; - n = n >> 2; - } - if (!(n & 0x1)) { - ret++; -#if 0 /* This is not necessary as n is never 0 */ - n = n >> 1; -#endif - } -#if 0 /* This is not necessary as n is never 0 */ - if (!n) - ret++; -#endif - - return ret; -} - pflash_t *pflash_cfi02_register(target_phys_addr_t base, DeviceState *qdev, const char *name, target_phys_addr_t size, @@ -18,6 +18,8 @@ * along with this program; if not, see <http://www.gnu.org/licenses/>. */ +#include <zlib.h> + #include "qemu-common.h" #include "qemu-timer.h" #include "qemu-queue.h" @@ -141,6 +143,7 @@ static void qxl_ring_set_dirty(PCIQXLDevice *qxl); void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...) { + trace_qxl_set_guest_bug(qxl->id); qxl_send_events(qxl, QXL_INTERRUPT_ERROR); qxl->guest_bug = 1; if (qxl->guestdebug) { @@ -201,6 +204,7 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, (uintptr_t)cookie); } else { qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id); + qxl_spice_destroy_surface_wait_complete(qxl, id); } } @@ -597,9 +601,9 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) case QXL_MODE_VGA: ret = false; qemu_mutex_lock(&qxl->ssd.lock); - if (qxl->ssd.update != NULL) { - update = qxl->ssd.update; - qxl->ssd.update = NULL; + update = QTAILQ_FIRST(&qxl->ssd.updates); + if (update != NULL) { + QTAILQ_REMOVE(&qxl->ssd.updates, update, next); *ext = update->ext; ret = true; } @@ -953,6 +957,11 @@ static void interface_set_client_capabilities(QXLInstance *sin, { PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + if (runstate_check(RUN_STATE_INMIGRATE) || + runstate_check(RUN_STATE_POSTMIGRATE)) { + return; + } + qxl->shadow_rom.client_present = client_present; memcpy(qxl->shadow_rom.client_capabilities, caps, sizeof(caps)); qxl->rom->client_present = client_present; @@ -964,6 +973,79 @@ static void interface_set_client_capabilities(QXLInstance *sin, #endif +#if defined(CONFIG_QXL_CLIENT_MONITORS_CONFIG) \ + && SPICE_SERVER_VERSION >= 0x000b05 + +static uint32_t qxl_crc32(const uint8_t *p, unsigned len) +{ + /* + * zlib xors the seed with 0xffffffff, and xors the result + * again with 0xffffffff; Both are not done with linux's crc32, + * which we want to be compatible with, so undo that. + */ + return crc32(0xffffffff, p, len) ^ 0xffffffff; +} + +/* called from main context only */ +static int interface_client_monitors_config(QXLInstance *sin, + VDAgentMonitorsConfig *monitors_config) +{ + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + QXLRom *rom = memory_region_get_ram_ptr(&qxl->rom_bar); + int i; + + /* + * Older windows drivers set int_mask to 0 when their ISR is called, + * then later set it to ~0. So it doesn't relate to the actual interrupts + * handled. However, they are old, so clearly they don't support this + * interrupt + */ + if (qxl->ram->int_mask == 0 || qxl->ram->int_mask == ~0 || + !(qxl->ram->int_mask & QXL_INTERRUPT_CLIENT_MONITORS_CONFIG)) { + trace_qxl_client_monitors_config_unsupported_by_guest(qxl->id, + qxl->ram->int_mask, + monitors_config); + return 0; + } + if (!monitors_config) { + return 1; + } + memset(&rom->client_monitors_config, 0, + sizeof(rom->client_monitors_config)); + rom->client_monitors_config.count = monitors_config->num_of_monitors; + /* monitors_config->flags ignored */ + if (rom->client_monitors_config.count >= + ARRAY_SIZE(rom->client_monitors_config.heads)) { + trace_qxl_client_monitors_config_capped(qxl->id, + monitors_config->num_of_monitors, + ARRAY_SIZE(rom->client_monitors_config.heads)); + rom->client_monitors_config.count = + ARRAY_SIZE(rom->client_monitors_config.heads); + } + for (i = 0 ; i < rom->client_monitors_config.count ; ++i) { + VDAgentMonConfig *monitor = &monitors_config->monitors[i]; + QXLURect *rect = &rom->client_monitors_config.heads[i]; + /* monitor->depth ignored */ + rect->left = monitor->x; + rect->top = monitor->y; + rect->right = monitor->x + monitor->width; + rect->bottom = monitor->y + monitor->height; + } + rom->client_monitors_config_crc = qxl_crc32( + (const uint8_t *)&rom->client_monitors_config, + sizeof(rom->client_monitors_config)); + trace_qxl_client_monitors_config_crc(qxl->id, + sizeof(rom->client_monitors_config), + rom->client_monitors_config_crc); + + trace_qxl_interrupt_client_monitors_config(qxl->id, + rom->client_monitors_config.count, + rom->client_monitors_config.heads); + qxl_send_events(qxl, QXL_INTERRUPT_CLIENT_MONITORS_CONFIG); + return 1; +} +#endif + static const QXLInterface qxl_interface = { .base.type = SPICE_INTERFACE_QXL, .base.description = "qxl gpu", @@ -988,6 +1070,10 @@ static const QXLInterface qxl_interface = { #if SPICE_SERVER_VERSION >= 0x000b04 .set_client_capabilities = interface_set_client_capabilities, #endif +#if SPICE_SERVER_VERSION >= 0x000b05 && \ + defined(CONFIG_QXL_CLIENT_MONITORS_CONFIG) + .client_monitors_config = interface_client_monitors_config, +#endif }; static void qxl_enter_vga_mode(PCIQXLDevice *d) @@ -1402,7 +1488,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, break; } trace_qxl_io_unexpected_vga_mode(d->id, - io_port, io_port_to_string(io_port)); + addr, val, io_port_to_string(io_port)); /* be nice to buggy guest drivers */ if (io_port >= QXL_IO_UPDATE_AREA_ASYNC && io_port < QXL_IO_RANGE_SIZE) { @@ -1470,6 +1556,13 @@ async_common: return; } + if (update.left < 0 || update.top < 0 || update.left >= update.right || + update.top >= update.bottom) { + qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: " + "invalid area(%d,%d,%d,%d)\n", update.left, + update.right, update.top, update.bottom); + break; + } if (async == QXL_ASYNC) { cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO, QXL_IO_UPDATE_AREA_ASYNC); @@ -1501,6 +1594,7 @@ async_common: qxl_set_mode(d, val, 0); break; case QXL_IO_LOG: + trace_qxl_io_log(d->id, d->ram->log_buf); if (d->guestdebug) { fprintf(stderr, "qxl/guest-%d: %" PRId64 ": %s", d->id, qemu_get_clock_ns(vm_clock), d->ram->log_buf); @@ -1594,9 +1688,9 @@ cancel_async: static uint64_t ioport_read(void *opaque, target_phys_addr_t addr, unsigned size) { - PCIQXLDevice *d = opaque; + PCIQXLDevice *qxl = opaque; - trace_qxl_io_read_unexpected(d->id); + trace_qxl_io_read_unexpected(qxl->id); return 0xff; } @@ -1626,6 +1720,7 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events) uint32_t old_pending; uint32_t le_events = cpu_to_le32(events); + trace_qxl_send_events(d->id, events); assert(qemu_spice_display_is_running(&d->ssd)); old_pending = __sync_fetch_and_or(&d->ram->int_pending, le_events); if ((old_pending & le_events) == le_events) { @@ -1910,6 +2005,7 @@ static int qxl_init_common(PCIQXLDevice *qxl) if (qxl->id == 0) { vga_dirty_log_start(&qxl->vga); } + memory_region_set_flush_coalesced(&qxl->io_bar); pci_register_bar(&qxl->pci, QXL_IO_RANGE_INDEX, diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 4981a0243..058d3b237 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -801,26 +801,39 @@ static int ata_passthrough_16_xfer_size(SCSIDevice *dev, uint8_t *buf) return xfer * unit; } -static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) +uint32_t scsi_data_cdb_length(uint8_t *buf) +{ + if ((buf[0] >> 5) == 0 && buf[4] == 0) { + return 256; + } else { + return scsi_cdb_length(buf); + } +} + +uint32_t scsi_cdb_length(uint8_t *buf) { switch (buf[0] >> 5) { case 0: - cmd->xfer = buf[4]; + return buf[4]; break; case 1: case 2: - cmd->xfer = lduw_be_p(&buf[7]); + return lduw_be_p(&buf[7]); break; case 4: - cmd->xfer = ldl_be_p(&buf[10]) & 0xffffffffULL; + return ldl_be_p(&buf[10]) & 0xffffffffULL; break; case 5: - cmd->xfer = ldl_be_p(&buf[6]) & 0xffffffffULL; + return ldl_be_p(&buf[6]) & 0xffffffffULL; break; default: return -1; } +} +static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) +{ + cmd->xfer = scsi_cdb_length(buf); switch (buf[0]) { case TEST_UNIT_READY: case REWIND: diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 1585683bc..95e91585e 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -678,7 +678,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) * is actually implemented, but we're good enough. */ outbuf[2] = 5; - outbuf[3] = 2; /* Format 2 */ + outbuf[3] = 2 | 0x10; /* Format 2, HiSup */ if (buflen > 36) { outbuf[4] = buflen - 5; /* Additional Length = (Len - 1) - 4 */ @@ -1449,6 +1449,22 @@ invalid_field: return; } +static inline bool check_lba_range(SCSIDiskState *s, + uint64_t sector_num, uint32_t nb_sectors) +{ + /* + * The first line tests that no overflow happens when computing the last + * sector. The second line tests that the last accessed sector is in + * range. + * + * Careful, the computations should not underflow for nb_sectors == 0, + * and a 0-block read to the first LBA beyond the end of device is + * valid. + */ + return (sector_num <= sector_num + nb_sectors && + sector_num + nb_sectors <= s->qdev.max_lba + 1); +} + typedef struct UnmapCBData { SCSIDiskReq *r; uint8_t *inbuf; @@ -1473,8 +1489,7 @@ static void scsi_unmap_complete(void *opaque, int ret) if (data->count > 0 && !r->req.io_canceled) { sector_num = ldq_be_p(&data->inbuf[0]); nb_sectors = ldl_be_p(&data->inbuf[8]) & 0xffffffffULL; - if (sector_num > sector_num + nb_sectors || - sector_num + nb_sectors - 1 > s->qdev.max_lba) { + if (!check_lba_range(s, sector_num, nb_sectors)) { scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE)); goto done; } @@ -1793,17 +1808,13 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) DPRINTF("Unmap (len %lu)\n", (long)r->req.cmd.xfer); break; case WRITE_SAME_10: - nb_sectors = lduw_be_p(&req->cmd.buf[7]); - goto write_same; case WRITE_SAME_16: - nb_sectors = ldl_be_p(&req->cmd.buf[10]) & 0xffffffffULL; - write_same: + nb_sectors = scsi_data_cdb_length(r->req.cmd.buf); if (bdrv_is_read_only(s->qdev.conf.bs)) { scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED)); return 0; } - if (r->req.cmd.lba > r->req.cmd.lba + nb_sectors || - r->req.cmd.lba + nb_sectors - 1 > s->qdev.max_lba) { + if (!check_lba_range(s, r->req.cmd.lba, nb_sectors)) { goto illegal_lba; } @@ -1858,7 +1869,7 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf) { SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); - int32_t len; + uint32_t len; uint8_t command; command = buf[0]; @@ -1868,18 +1879,17 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf) return 0; } + len = scsi_data_cdb_length(r->req.cmd.buf); switch (command) { case READ_6: case READ_10: case READ_12: case READ_16: - len = r->req.cmd.xfer / s->qdev.blocksize; - DPRINTF("Read (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len); + DPRINTF("Read (sector %" PRId64 ", count %u)\n", r->req.cmd.lba, len); if (r->req.cmd.buf[1] & 0xe0) { goto illegal_request; } - if (r->req.cmd.lba > r->req.cmd.lba + len || - r->req.cmd.lba + len - 1 > s->qdev.max_lba) { + if (!check_lba_range(s, r->req.cmd.lba, len)) { goto illegal_lba; } r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512); @@ -1900,15 +1910,13 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf) case VERIFY_10: case VERIFY_12: case VERIFY_16: - len = r->req.cmd.xfer / s->qdev.blocksize; - DPRINTF("Write %s(sector %" PRId64 ", count %d)\n", + DPRINTF("Write %s(sector %" PRId64 ", count %u)\n", (command & 0xe) == 0xe ? "And Verify " : "", r->req.cmd.lba, len); if (r->req.cmd.buf[1] & 0xe0) { goto illegal_request; } - if (r->req.cmd.lba > r->req.cmd.lba + len || - r->req.cmd.lba + len - 1 > s->qdev.max_lba) { + if (!check_lba_range(s, r->req.cmd.lba, len)) { goto illegal_lba; } r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512); @@ -218,6 +218,8 @@ extern const struct SCSISense sense_code_WRITE_PROTECTED; #define SENSE_CODE(x) sense_code_ ## x +uint32_t scsi_data_cdb_length(uint8_t *buf); +uint32_t scsi_cdb_length(uint8_t *buf); int scsi_sense_valid(SCSISense sense); int scsi_build_sense(uint8_t *in_buf, int in_len, uint8_t *buf, int len, bool fixed); @@ -177,13 +177,13 @@ struct srp_tsk_mgmt { uint8_t reserved1[6]; uint64_t tag; uint8_t reserved2[4]; - uint64_t lun QEMU_PACKED; + uint64_t lun; uint8_t reserved3[2]; uint8_t tsk_mgmt_func; uint8_t reserved4; uint64_t task_tag; uint8_t reserved5[8]; -}; +} QEMU_PACKED; /* * We need the packed attribute because the SRP spec only aligns the @@ -198,14 +198,14 @@ struct srp_cmd { uint8_t data_in_desc_cnt; uint64_t tag; uint8_t reserved2[4]; - uint64_t lun QEMU_PACKED; + uint64_t lun; uint8_t reserved3; uint8_t task_attr; uint8_t reserved4; uint8_t add_cdb_len; uint8_t cdb[16]; uint8_t add_data[0]; -}; +} QEMU_PACKED; enum { SRP_RSP_FLAG_RSPVALID = 1 << 0, diff --git a/hw/sun4m.c b/hw/sun4m.c index 0f909b5f8..c98cd5ec3 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -472,6 +472,17 @@ static void slavio_timer_init_all(target_phys_addr_t addr, qemu_irq master_irq, } } +static qemu_irq slavio_system_powerdown; + +static void slavio_powerdown_req(Notifier *n, void *opaque) +{ + qemu_irq_raise(slavio_system_powerdown); +} + +static Notifier slavio_system_powerdown_notifier = { + .notify = slavio_powerdown_req +}; + #define MISC_LEDS 0x01600000 #define MISC_CFG 0x01800000 #define MISC_DIAG 0x01a00000 @@ -514,7 +525,8 @@ static void slavio_misc_init(target_phys_addr_t base, } sysbus_connect_irq(s, 0, irq); sysbus_connect_irq(s, 1, fdc_tc); - qemu_system_powerdown = qdev_get_gpio_in(dev, 0); + slavio_system_powerdown = qdev_get_gpio_in(dev, 0); + qemu_register_powerdown_notifier(&slavio_system_powerdown_notifier); } static void ecc_init(target_phys_addr_t base, qemu_irq irq, uint32_t version) diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index c84892c98..e4a43599b 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -1001,6 +1001,13 @@ static int rndis_keepalive_response(USBNetState *s, return 0; } +/* Prepare to receive the next packet */ +static void usb_net_reset_in_buf(USBNetState *s) +{ + s->in_ptr = s->in_len = 0; + qemu_flush_queued_packets(&s->nic->nc); +} + static int rndis_parse(USBNetState *s, uint8_t *data, int length) { uint32_t msg_type; @@ -1025,7 +1032,8 @@ static int rndis_parse(USBNetState *s, uint8_t *data, int length) case RNDIS_RESET_MSG: rndis_clear_responsequeue(s); - s->out_ptr = s->in_ptr = s->in_len = 0; + s->out_ptr = 0; + usb_net_reset_in_buf(s); return rndis_reset_response(s, (rndis_reset_msg_type *) data); case RNDIS_KEEPALIVE_MSG: @@ -1135,7 +1143,7 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p) int ret = USB_RET_NAK; if (s->in_ptr > s->in_len) { - s->in_ptr = s->in_len = 0; + usb_net_reset_in_buf(s); ret = USB_RET_NAK; return ret; } @@ -1152,7 +1160,7 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p) if (s->in_ptr >= s->in_len && (is_rndis(s) || (s->in_len & (64 - 1)) || !ret)) { /* no short packet necessary */ - s->in_ptr = s->in_len = 0; + usb_net_reset_in_buf(s); } #ifdef TRAFFIC_DEBUG @@ -1250,20 +1258,32 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p) static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t size) { USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque; - struct rndis_packet_msg_type *msg; + uint8_t *in_buf = s->in_buf; + size_t total_size = size; if (is_rndis(s)) { - msg = (struct rndis_packet_msg_type *) s->in_buf; if (s->rndis_state != RNDIS_DATA_INITIALIZED) { return -1; } - if (size + sizeof(struct rndis_packet_msg_type) > sizeof(s->in_buf)) - return -1; + total_size += sizeof(struct rndis_packet_msg_type); + } + if (total_size > sizeof(s->in_buf)) { + return -1; + } + /* Only accept packet if input buffer is empty */ + if (s->in_len > 0) { + return 0; + } + + if (is_rndis(s)) { + struct rndis_packet_msg_type *msg; + + msg = (struct rndis_packet_msg_type *)in_buf; memset(msg, 0, sizeof(struct rndis_packet_msg_type)); msg->MessageType = cpu_to_le32(RNDIS_PACKET_MSG); - msg->MessageLength = cpu_to_le32(size + sizeof(struct rndis_packet_msg_type)); - msg->DataOffset = cpu_to_le32(sizeof(struct rndis_packet_msg_type) - 8); + msg->MessageLength = cpu_to_le32(size + sizeof(*msg)); + msg->DataOffset = cpu_to_le32(sizeof(*msg) - 8); msg->DataLength = cpu_to_le32(size); /* msg->OOBDataOffset; * msg->OOBDataLength; @@ -1273,14 +1293,11 @@ static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t siz * msg->VcHandle; * msg->Reserved; */ - memcpy(msg + 1, buf, size); - s->in_len = size + sizeof(struct rndis_packet_msg_type); - } else { - if (size > sizeof(s->in_buf)) - return -1; - memcpy(s->in_buf, buf, size); - s->in_len = size; + in_buf += sizeof(*msg); } + + memcpy(in_buf, buf, size); + s->in_len = total_size; s->in_ptr = 0; return size; } diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 2f3e9c03a..6a5da8413 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -34,6 +34,7 @@ #include "monitor.h" #include "trace.h" #include "dma.h" +#include "sysemu.h" #define EHCI_DEBUG 0 @@ -139,6 +140,7 @@ #define NB_PORTS 6 // Number of downstream ports #define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction #define MAX_QH 100 // Max allowable queue heads in a chain +#define MIN_FR_PER_TICK 3 // Min frames to process when catching up /* Internal periodic / asynchronous schedule state machine states */ @@ -389,6 +391,9 @@ struct EHCIState { USBBus bus; qemu_irq irq; MemoryRegion mem; + MemoryRegion mem_caps; + MemoryRegion mem_opreg; + MemoryRegion mem_ports; int companion_count; /* properties */ @@ -398,10 +403,10 @@ struct EHCIState { * EHCI spec version 1.0 Section 2.3 * Host Controller Operational Registers */ + uint8_t caps[OPREGBASE]; union { - uint8_t mmio[MMIO_SIZE]; + uint32_t opreg[(PORTSC_BEGIN-OPREGBASE)/sizeof(uint32_t)]; struct { - uint8_t cap[OPREGBASE]; uint32_t usbcmd; uint32_t usbsts; uint32_t usbintr; @@ -411,9 +416,9 @@ struct EHCIState { uint32_t asynclistaddr; uint32_t notused[9]; uint32_t configflag; - uint32_t portsc[NB_PORTS]; }; }; + uint32_t portsc[NB_PORTS]; /* * Internal states, shadow registers, etc @@ -471,22 +476,12 @@ static const char *ehci_state_names[] = { }; static const char *ehci_mmio_names[] = { - [CAPLENGTH] = "CAPLENGTH", - [HCIVERSION] = "HCIVERSION", - [HCSPARAMS] = "HCSPARAMS", - [HCCPARAMS] = "HCCPARAMS", [USBCMD] = "USBCMD", [USBSTS] = "USBSTS", [USBINTR] = "USBINTR", [FRINDEX] = "FRINDEX", [PERIODICLISTBASE] = "P-LIST BASE", [ASYNCLISTADDR] = "A-LIST ADDR", - [PORTSC_BEGIN] = "PORTSC #0", - [PORTSC_BEGIN + 4] = "PORTSC #1", - [PORTSC_BEGIN + 8] = "PORTSC #2", - [PORTSC_BEGIN + 12] = "PORTSC #3", - [PORTSC_BEGIN + 16] = "PORTSC #4", - [PORTSC_BEGIN + 20] = "PORTSC #5", [CONFIGFLAG] = "CONFIGFLAG", }; @@ -509,7 +504,8 @@ static const char *state2str(uint32_t state) static const char *addr2str(target_phys_addr_t addr) { - return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), addr); + return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), + addr + OPREGBASE); } static void ehci_trace_usbsts(uint32_t mask, int state) @@ -853,10 +849,10 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr, return NULL; } -static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush) +static void ehci_queues_rip_unused(EHCIState *ehci, int async) { EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; - const char *warn = (async && !flush) ? "guest unlinked busy QH" : NULL; + const char *warn = async ? "guest unlinked busy QH" : NULL; uint64_t maxage = FRAME_TIMER_NS * ehci->maxframes * 4; EHCIQueue *q, *tmp; @@ -866,13 +862,25 @@ static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush) q->ts = ehci->last_run_ns; continue; } - if (!flush && ehci->last_run_ns < q->ts + maxage) { + if (ehci->last_run_ns < q->ts + maxage) { continue; } ehci_free_queue(q, warn); } } +static void ehci_queues_rip_unseen(EHCIState *ehci, int async) +{ + EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; + EHCIQueue *q, *tmp; + + QTAILQ_FOREACH_SAFE(q, head, next, tmp) { + if (!q->seen) { + ehci_free_queue(q, NULL); + } + } +} + static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev, int async) { EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; @@ -1018,7 +1026,7 @@ static int ehci_register_companion(USBBus *bus, USBPort *ports[], } s->companion_count++; - s->mmio[0x05] = (s->companion_count << 4) | portcount; + s->caps[0x05] = (s->companion_count << 4) | portcount; return 0; } @@ -1063,7 +1071,8 @@ static void ehci_reset(void *opaque) } } - memset(&s->mmio[OPREGBASE], 0x00, MMIO_SIZE - OPREGBASE); + memset(&s->opreg, 0x00, sizeof(s->opreg)); + memset(&s->portsc, 0x00, sizeof(s->portsc)); s->usbcmd = NB_MAXINTRATE << USBCMD_ITC_SH; s->usbsts = USBSTS_HALT; @@ -1090,50 +1099,35 @@ static void ehci_reset(void *opaque) qemu_bh_cancel(s->async_bh); } -static uint32_t ehci_mem_readb(void *ptr, target_phys_addr_t addr) +static uint64_t ehci_caps_read(void *ptr, target_phys_addr_t addr, + unsigned size) { EHCIState *s = ptr; - uint32_t val; - - val = s->mmio[addr]; - - return val; + return s->caps[addr]; } -static uint32_t ehci_mem_readw(void *ptr, target_phys_addr_t addr) +static uint64_t ehci_opreg_read(void *ptr, target_phys_addr_t addr, + unsigned size) { EHCIState *s = ptr; uint32_t val; - val = s->mmio[addr] | (s->mmio[addr+1] << 8); - + val = s->opreg[addr >> 2]; + trace_usb_ehci_opreg_read(addr + OPREGBASE, addr2str(addr), val); return val; } -static uint32_t ehci_mem_readl(void *ptr, target_phys_addr_t addr) +static uint64_t ehci_port_read(void *ptr, target_phys_addr_t addr, + unsigned size) { EHCIState *s = ptr; uint32_t val; - val = s->mmio[addr] | (s->mmio[addr+1] << 8) | - (s->mmio[addr+2] << 16) | (s->mmio[addr+3] << 24); - - trace_usb_ehci_mmio_readl(addr, addr2str(addr), val); + val = s->portsc[addr >> 2]; + trace_usb_ehci_portsc_read(addr + PORTSC_BEGIN, addr >> 2, val); return val; } -static void ehci_mem_writeb(void *ptr, target_phys_addr_t addr, uint32_t val) -{ - fprintf(stderr, "EHCI doesn't handle byte writes to MMIO\n"); - exit(1); -} - -static void ehci_mem_writew(void *ptr, target_phys_addr_t addr, uint32_t val) -{ - fprintf(stderr, "EHCI doesn't handle 16-bit writes to MMIO\n"); - exit(1); -} - static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner) { USBDevice *dev = s->ports[port].dev; @@ -1162,11 +1156,17 @@ static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner) } } -static void handle_port_status_write(EHCIState *s, int port, uint32_t val) +static void ehci_port_write(void *ptr, target_phys_addr_t addr, + uint64_t val, unsigned size) { + EHCIState *s = ptr; + int port = addr >> 2; uint32_t *portsc = &s->portsc[port]; + uint32_t old = *portsc; USBDevice *dev = s->ports[port].dev; + trace_usb_ehci_portsc_write(addr + PORTSC_BEGIN, addr >> 2, val); + /* Clear rwc bits */ *portsc &= ~(val & PORTSC_RWC_MASK); /* The guest may clear, but not set the PED bit */ @@ -1198,39 +1198,20 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val) *portsc &= ~PORTSC_RO_MASK; *portsc |= val; + trace_usb_ehci_portsc_change(addr + PORTSC_BEGIN, addr >> 2, *portsc, old); } -static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) +static void ehci_opreg_write(void *ptr, target_phys_addr_t addr, + uint64_t val, unsigned size) { EHCIState *s = ptr; - uint32_t *mmio = (uint32_t *)(&s->mmio[addr]); + uint32_t *mmio = s->opreg + (addr >> 2); uint32_t old = *mmio; int i; - trace_usb_ehci_mmio_writel(addr, addr2str(addr), val); - - /* Only aligned reads are allowed on OHCI */ - if (addr & 3) { - fprintf(stderr, "usb-ehci: Mis-aligned write to addr 0x" - TARGET_FMT_plx "\n", addr); - return; - } - - if (addr >= PORTSC && addr < PORTSC + 4 * NB_PORTS) { - handle_port_status_write(s, (addr-PORTSC)/4, val); - trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old); - return; - } - - if (addr < OPREGBASE) { - fprintf(stderr, "usb-ehci: write attempt to read-only register" - TARGET_FMT_plx "\n", addr); - return; - } + trace_usb_ehci_opreg_write(addr + OPREGBASE, addr2str(addr), val); - - /* Do any register specific pre-write processing here. */ - switch(addr) { + switch (addr + OPREGBASE) { case USBCMD: if (val & USBCMD_HCRESET) { ehci_reset(s); @@ -1241,7 +1222,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) /* not supporting dynamic frame list size at the moment */ if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) { fprintf(stderr, "attempt to set frame list size -- value %d\n", - val & USBCMD_FLS); + (int)val & USBCMD_FLS); val &= ~USBCMD_FLS; } @@ -1308,7 +1289,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) } *mmio = val; - trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old); + trace_usb_ehci_opreg_change(addr + OPREGBASE, addr2str(addr), *mmio, old); } @@ -1732,7 +1713,7 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async) ehci_set_usbsts(ehci, USBSTS_REC); } - ehci_queues_rip_unused(ehci, async, 0); + ehci_queues_rip_unused(ehci, async); /* Find the head of the list (4.9.1.1) */ for(i = 0; i < MAX_QH; i++) { @@ -2364,7 +2345,7 @@ static void ehci_advance_async_state(EHCIState *ehci) */ if (ehci->usbcmd & USBCMD_IAAD) { /* Remove all unseen qhs from the async qhs queue */ - ehci_queues_rip_unused(ehci, async, 1); + ehci_queues_rip_unseen(ehci, async); trace_usb_ehci_doorbell_ack(); ehci->usbcmd &= ~USBCMD_IAAD; ehci_raise_irq(ehci, USBSTS_IAA); @@ -2417,7 +2398,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci) ehci_set_fetch_addr(ehci, async,entry); ehci_set_state(ehci, async, EST_FETCHENTRY); ehci_advance_state(ehci, async); - ehci_queues_rip_unused(ehci, async, 0); + ehci_queues_rip_unused(ehci, async); break; default: @@ -2446,7 +2427,7 @@ static void ehci_update_frindex(EHCIState *ehci, int frames) if (ehci->frindex == 0x00004000) { ehci_raise_irq(ehci, USBSTS_FLR); ehci->frindex = 0; - if (ehci->usbsts_frindex > 0x00004000) { + if (ehci->usbsts_frindex >= 0x00004000) { ehci->usbsts_frindex -= 0x00004000; } else { ehci->usbsts_frindex = 0; @@ -2481,6 +2462,19 @@ static void ehci_frame_timer(void *opaque) } for (i = 0; i < frames; i++) { + /* + * If we're running behind schedule, we should not catch up + * too fast, as that will make some guests unhappy: + * 1) We must process a minimum of MIN_FR_PER_TICK frames, + * otherwise we will never catch up + * 2) Process frames until the guest has requested an irq (IOC) + */ + if (i >= MIN_FR_PER_TICK) { + ehci_commit_irq(ehci); + if ((ehci->usbsts & USBINTR_MASK) & ehci->usbintr) { + break; + } + } ehci_update_frindex(ehci, 1); ehci_advance_periodic_state(ehci); ehci->last_run_ns += FRAME_TIMER_NS; @@ -2520,11 +2514,28 @@ static void ehci_async_bh(void *opaque) ehci_advance_async_state(ehci); } -static const MemoryRegionOps ehci_mem_ops = { - .old_mmio = { - .read = { ehci_mem_readb, ehci_mem_readw, ehci_mem_readl }, - .write = { ehci_mem_writeb, ehci_mem_writew, ehci_mem_writel }, - }, +static const MemoryRegionOps ehci_mmio_caps_ops = { + .read = ehci_caps_read, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .impl.min_access_size = 1, + .impl.max_access_size = 1, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static const MemoryRegionOps ehci_mmio_opreg_ops = { + .read = ehci_opreg_read, + .write = ehci_opreg_write, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static const MemoryRegionOps ehci_mmio_port_ops = { + .read = ehci_port_read, + .write = ehci_port_write, + .valid.min_access_size = 4, + .valid.max_access_size = 4, .endianness = DEVICE_LITTLE_ENDIAN, }; @@ -2562,6 +2573,32 @@ static int usb_ehci_post_load(void *opaque, int version_id) return 0; } +static void usb_ehci_vm_state_change(void *opaque, int running, RunState state) +{ + EHCIState *ehci = opaque; + + /* + * We don't migrate the EHCIQueue-s, instead we rebuild them for the + * schedule in guest memory. We must do the rebuilt ASAP, so that + * USB-devices which have async handled packages have a packet in the + * ep queue to match the completion with. + */ + if (state == RUN_STATE_RUNNING) { + ehci_advance_async_state(ehci); + } + + /* + * The schedule rebuilt from guest memory could cause the migration dest + * to miss a QH unlink, and fail to cancel packets, since the unlinked QH + * will never have existed on the destination. Therefor we must flush the + * async schedule on savevm to catch any not yet noticed unlinks. + */ + if (state == RUN_STATE_SAVE_VM) { + ehci_advance_async_state(ehci); + ehci_queues_rip_unseen(ehci, 1); + } +} + static const VMStateDescription vmstate_ehci = { .name = "ehci", .version_id = 2, @@ -2681,19 +2718,19 @@ static int usb_ehci_initfn(PCIDevice *dev) pci_conf[0x6e] = 0x00; pci_conf[0x6f] = 0xc0; // USBLEFCTLSTS - // 2.2 host controller interface version - s->mmio[0x00] = (uint8_t) OPREGBASE; - s->mmio[0x01] = 0x00; - s->mmio[0x02] = 0x00; - s->mmio[0x03] = 0x01; // HC version - s->mmio[0x04] = NB_PORTS; // Number of downstream ports - s->mmio[0x05] = 0x00; // No companion ports at present - s->mmio[0x06] = 0x00; - s->mmio[0x07] = 0x00; - s->mmio[0x08] = 0x80; // We can cache whole frame, not 64-bit capable - s->mmio[0x09] = 0x68; // EECP - s->mmio[0x0a] = 0x00; - s->mmio[0x0b] = 0x00; + /* 2.2 host controller interface version */ + s->caps[0x00] = (uint8_t) OPREGBASE; + s->caps[0x01] = 0x00; + s->caps[0x02] = 0x00; + s->caps[0x03] = 0x01; /* HC version */ + s->caps[0x04] = NB_PORTS; /* Number of downstream ports */ + s->caps[0x05] = 0x00; /* No companion ports at present */ + s->caps[0x06] = 0x00; + s->caps[0x07] = 0x00; + s->caps[0x08] = 0x80; /* We can cache whole frame, no 64-bit */ + s->caps[0x09] = 0x68; /* EECP */ + s->caps[0x0a] = 0x00; + s->caps[0x0b] = 0x00; s->irq = s->dev.irq[3]; @@ -2711,8 +2748,20 @@ static int usb_ehci_initfn(PCIDevice *dev) usb_packet_init(&s->ipacket); qemu_register_reset(ehci_reset, s); + qemu_add_vm_change_state_handler(usb_ehci_vm_state_change, s); + + memory_region_init(&s->mem, "ehci", MMIO_SIZE); + memory_region_init_io(&s->mem_caps, &ehci_mmio_caps_ops, s, + "capabilities", OPREGBASE); + memory_region_init_io(&s->mem_opreg, &ehci_mmio_opreg_ops, s, + "operational", PORTSC_BEGIN - OPREGBASE); + memory_region_init_io(&s->mem_ports, &ehci_mmio_port_ops, s, + "ports", PORTSC_END - PORTSC_BEGIN); + + memory_region_add_subregion(&s->mem, 0, &s->mem_caps); + memory_region_add_subregion(&s->mem, OPREGBASE, &s->mem_opreg); + memory_region_add_subregion(&s->mem, PORTSC_BEGIN, &s->mem_ports); - memory_region_init_io(&s->mem, &ehci_mem_ops, s, "ehci", MMIO_SIZE); pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem); return 0; diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index c7c878635..cdc8bc3fb 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -1000,6 +1000,9 @@ static void uhci_fill_queue(UHCIState *s, UHCI_TD *td) } assert(ret == TD_RESULT_ASYNC_START); assert(int_mask == 0); + if (ptd.ctrl & TD_CTRL_SPD) { + break; + } plink = ptd.link; } } @@ -1097,7 +1100,7 @@ static void uhci_process_frame(UHCIState *s) case TD_RESULT_ASYNC_START: trace_usb_uhci_td_async(curr_qh & ~0xf, link & ~0xf); - if (is_valid(td.link)) { + if (is_valid(td.link) && !(td.ctrl & TD_CTRL_SPD)) { uhci_fill_queue(s, &td); } link = curr_qh ? qh.link : td.link; diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index 8df92074d..44f1a64b3 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -1045,7 +1045,6 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p, /* Note request is (bRequestType << 8) | bRequest */ trace_usb_host_req_control(s->bus_num, s->addr, p, request, value, index); - assert(p->result == 0); switch (request) { case DeviceOutRequest | USB_REQ_SET_ADDRESS: @@ -1074,6 +1073,7 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p, } /* The rest are asynchronous */ + assert(p && p->result == 0); if (length > sizeof(dev->data_buf)) { fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n", diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 5301a69c4..b10241a13 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -43,7 +43,6 @@ #define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f)) #define I2EP(i) (((i & 0x10) << 3) | (i & 0x0f)) -typedef struct Cancelled Cancelled; typedef struct USBRedirDevice USBRedirDevice; /* Struct to hold buffered packets (iso or int input packets) */ @@ -58,6 +57,7 @@ struct endp_data { uint8_t type; uint8_t interval; uint8_t interface; /* bInterfaceNumber this ep belongs to */ + uint16_t max_packet_size; /* In bytes, not wMaxPacketSize format !! */ uint8_t iso_started; uint8_t iso_error; /* For reporting iso errors to the HC */ uint8_t interrupt_started; @@ -65,8 +65,20 @@ struct endp_data { uint8_t bufpq_prefilled; uint8_t bufpq_dropping_packets; QTAILQ_HEAD(, buf_packet) bufpq; - int bufpq_size; - int bufpq_target_size; + int32_t bufpq_size; + int32_t bufpq_target_size; +}; + +struct PacketIdQueueEntry { + uint64_t id; + QTAILQ_ENTRY(PacketIdQueueEntry)next; +}; + +struct PacketIdQueue { + USBRedirDevice *dev; + const char *name; + QTAILQ_HEAD(, PacketIdQueueEntry) head; + int size; }; struct USBRedirDevice { @@ -86,7 +98,8 @@ struct USBRedirDevice { int64_t next_attach_time; struct usbredirparser *parser; struct endp_data endpoint[MAX_ENDPOINTS]; - QTAILQ_HEAD(, Cancelled) cancelled; + struct PacketIdQueue cancelled; + struct PacketIdQueue already_in_flight; /* Data for device filtering */ struct usb_redir_device_connect_header device_info; struct usb_redir_interface_info_header interface_info; @@ -94,11 +107,6 @@ struct USBRedirDevice { int filter_rules_count; }; -struct Cancelled { - uint64_t id; - QTAILQ_ENTRY(Cancelled)next; -}; - static void usbredir_hello(void *priv, struct usb_redir_hello_header *h); static void usbredir_device_connect(void *priv, struct usb_redir_device_connect_header *device_connect); @@ -134,6 +142,8 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id, static int usbredir_handle_status(USBRedirDevice *dev, int status, int actual_len); +#define VERSION "qemu usb-redir guest " QEMU_VERSION + /* * Logging stuff */ @@ -232,6 +242,11 @@ static int usbredir_write(void *priv, uint8_t *data, int count) return 0; } + /* Don't send new data to the chardev until our state is fully synced */ + if (!runstate_check(RUN_STATE_RUNNING)) { + return 0; + } + return qemu_chr_fe_write(dev->cs, data, count); } @@ -239,37 +254,103 @@ static int usbredir_write(void *priv, uint8_t *data, int count) * Cancelled and buffered packets helpers */ -static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p) +static void packet_id_queue_init(struct PacketIdQueue *q, + USBRedirDevice *dev, const char *name) { - USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); - Cancelled *c; + q->dev = dev; + q->name = name; + QTAILQ_INIT(&q->head); + q->size = 0; +} + +static void packet_id_queue_add(struct PacketIdQueue *q, uint64_t id) +{ + USBRedirDevice *dev = q->dev; + struct PacketIdQueueEntry *e; + + DPRINTF("adding packet id %"PRIu64" to %s queue\n", id, q->name); - DPRINTF("cancel packet id %"PRIu64"\n", p->id); + e = g_malloc0(sizeof(struct PacketIdQueueEntry)); + e->id = id; + QTAILQ_INSERT_TAIL(&q->head, e, next); + q->size++; +} - c = g_malloc0(sizeof(Cancelled)); - c->id = p->id; - QTAILQ_INSERT_TAIL(&dev->cancelled, c, next); +static int packet_id_queue_remove(struct PacketIdQueue *q, uint64_t id) +{ + USBRedirDevice *dev = q->dev; + struct PacketIdQueueEntry *e; + + QTAILQ_FOREACH(e, &q->head, next) { + if (e->id == id) { + DPRINTF("removing packet id %"PRIu64" from %s queue\n", + id, q->name); + QTAILQ_REMOVE(&q->head, e, next); + q->size--; + g_free(e); + return 1; + } + } + return 0; +} +static void packet_id_queue_empty(struct PacketIdQueue *q) +{ + USBRedirDevice *dev = q->dev; + struct PacketIdQueueEntry *e, *next_e; + + DPRINTF("removing %d packet-ids from %s queue\n", q->size, q->name); + + QTAILQ_FOREACH_SAFE(e, &q->head, next, next_e) { + QTAILQ_REMOVE(&q->head, e, next); + g_free(e); + } + q->size = 0; +} + +static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p) +{ + USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); + + packet_id_queue_add(&dev->cancelled, p->id); usbredirparser_send_cancel_data_packet(dev->parser, p->id); usbredirparser_do_write(dev->parser); } static int usbredir_is_cancelled(USBRedirDevice *dev, uint64_t id) { - Cancelled *c; - if (!dev->dev.attached) { return 1; /* Treat everything as cancelled after a disconnect */ } + return packet_id_queue_remove(&dev->cancelled, id); +} + +static void usbredir_fill_already_in_flight_from_ep(USBRedirDevice *dev, + struct USBEndpoint *ep) +{ + static USBPacket *p; + + QTAILQ_FOREACH(p, &ep->queue, queue) { + packet_id_queue_add(&dev->already_in_flight, p->id); + } +} - QTAILQ_FOREACH(c, &dev->cancelled, next) { - if (c->id == id) { - QTAILQ_REMOVE(&dev->cancelled, c, next); - g_free(c); - return 1; - } +static void usbredir_fill_already_in_flight(USBRedirDevice *dev) +{ + int ep; + struct USBDevice *udev = &dev->dev; + + usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_ctl); + + for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) { + usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_in[ep]); + usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_out[ep]); } - return 0; +} + +static int usbredir_already_in_flight(USBRedirDevice *dev, uint64_t id) +{ + return packet_id_queue_remove(&dev->already_in_flight, id); } static USBPacket *usbredir_find_packet_by_id(USBRedirDevice *dev, @@ -487,6 +568,10 @@ static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p, DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, p->iov.size, p->id); + if (usbredir_already_in_flight(dev, p->id)) { + return USB_RET_ASYNC; + } + bulk_packet.endpoint = ep; bulk_packet.length = p->iov.size; bulk_packet.stream_id = 0; @@ -567,6 +652,10 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev, DPRINTF("interrupt-out ep %02X len %zd id %"PRIu64"\n", ep, p->iov.size, p->id); + if (usbredir_already_in_flight(dev, p->id)) { + return USB_RET_ASYNC; + } + interrupt_packet.endpoint = ep; interrupt_packet.length = p->iov.size; @@ -709,6 +798,10 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p, USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); struct usb_redir_control_packet_header control_packet; + if (usbredir_already_in_flight(dev, p->id)) { + return USB_RET_ASYNC; + } + /* Special cases for certain standard device requests */ switch (request) { case DeviceOutRequest | USB_REQ_SET_ADDRESS: @@ -763,6 +856,7 @@ static void usbredir_chardev_close_bh(void *opaque) usbredir_device_disconnect(dev); if (dev->parser) { + DPRINTF("destroying usbredirparser\n"); usbredirparser_destroy(dev->parser); dev->parser = NULL; } @@ -771,14 +865,13 @@ static void usbredir_chardev_close_bh(void *opaque) static void usbredir_chardev_open(USBRedirDevice *dev) { uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, }; - char version[32]; + int flags = 0; /* Make sure any pending closes are handled (no-op if none pending) */ usbredir_chardev_close_bh(dev); qemu_bh_cancel(dev->chardev_close_bh); - strcpy(version, "qemu usb-redir guest "); - pstrcat(version, sizeof(version), qemu_get_version()); + DPRINTF("creating usbredirparser\n"); dev->parser = qemu_oom_check(usbredirparser_create()); dev->parser->priv = dev; @@ -807,7 +900,12 @@ static void usbredir_chardev_open(USBRedirDevice *dev) usbredirparser_caps_set_cap(caps, usb_redir_cap_filter); usbredirparser_caps_set_cap(caps, usb_redir_cap_ep_info_max_packet_size); usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids); - usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, 0); + + if (runstate_check(RUN_STATE_INMIGRATE)) { + flags |= usbredirparser_fl_no_hello; + } + usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE, + flags); usbredirparser_do_write(dev->parser); } @@ -853,6 +951,11 @@ static int usbredir_chardev_can_read(void *opaque) return 0; } + /* Don't read new data from the chardev until our state is fully synced */ + if (!runstate_check(RUN_STATE_RUNNING)) { + return 0; + } + /* usbredir_parser_do_read will consume *all* data we give it */ return 1024 * 1024; } @@ -878,9 +981,11 @@ static void usbredir_chardev_event(void *opaque, int event) switch (event) { case CHR_EVENT_OPENED: + DPRINTF("chardev open\n"); usbredir_chardev_open(dev); break; case CHR_EVENT_CLOSED: + DPRINTF("chardev close\n"); qemu_bh_schedule(dev->chardev_close_bh); break; } @@ -890,6 +995,15 @@ static void usbredir_chardev_event(void *opaque, int event) * init + destroy */ +static void usbredir_vm_state_change(void *priv, int running, RunState state) +{ + USBRedirDevice *dev = priv; + + if (state == RUN_STATE_RUNNING && dev->parser != NULL) { + usbredirparser_do_write(dev->parser); /* Flush any pending writes */ + } +} + static int usbredir_initfn(USBDevice *udev) { USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); @@ -914,7 +1028,8 @@ static int usbredir_initfn(USBDevice *udev) dev->chardev_close_bh = qemu_bh_new(usbredir_chardev_close_bh, dev); dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev); - QTAILQ_INIT(&dev->cancelled); + packet_id_queue_init(&dev->cancelled, dev, "cancelled"); + packet_id_queue_init(&dev->already_in_flight, dev, "already-in-flight"); for (i = 0; i < MAX_ENDPOINTS; i++) { QTAILQ_INIT(&dev->endpoint[i].bufpq); } @@ -927,19 +1042,17 @@ static int usbredir_initfn(USBDevice *udev) qemu_chr_add_handlers(dev->cs, usbredir_chardev_can_read, usbredir_chardev_read, usbredir_chardev_event, dev); + qemu_add_vm_change_state_handler(usbredir_vm_state_change, dev); add_boot_device_path(dev->bootindex, &udev->qdev, NULL); return 0; } static void usbredir_cleanup_device_queues(USBRedirDevice *dev) { - Cancelled *c, *next_c; int i; - QTAILQ_FOREACH_SAFE(c, &dev->cancelled, next, next_c) { - QTAILQ_REMOVE(&dev->cancelled, c, next); - g_free(c); - } + packet_id_queue_empty(&dev->cancelled); + packet_id_queue_empty(&dev->already_in_flight); for (i = 0; i < MAX_ENDPOINTS; i++) { usbredir_free_bufpq(dev, I2EP(i)); } @@ -1118,6 +1231,7 @@ static void usbredir_device_disconnect(void *priv) qemu_del_timer(dev->attach_timer); if (dev->dev.attached) { + DPRINTF("detaching device\n"); usb_device_detach(&dev->dev); /* * Delay next usb device attach to give the guest a chance to see @@ -1195,7 +1309,8 @@ static void usbredir_ep_info(void *priv, usb_ep->ifnum = dev->endpoint[i].interface; if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_ep_info_max_packet_size)) { - usb_ep->max_packet_size = ep_info->max_packet_size[i]; + dev->endpoint[i].max_packet_size = + usb_ep->max_packet_size = ep_info->max_packet_size[i]; } if (ep_info->type[i] == usb_redir_type_bulk) { usb_ep->pipeline = true; @@ -1418,6 +1533,322 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id, } } +/* + * Migration code + */ + +static void usbredir_pre_save(void *priv) +{ + USBRedirDevice *dev = priv; + + usbredir_fill_already_in_flight(dev); +} + +static int usbredir_post_load(void *priv, int version_id) +{ + USBRedirDevice *dev = priv; + struct USBEndpoint *usb_ep; + int i; + + switch (dev->device_info.speed) { + case usb_redir_speed_low: + dev->dev.speed = USB_SPEED_LOW; + break; + case usb_redir_speed_full: + dev->dev.speed = USB_SPEED_FULL; + break; + case usb_redir_speed_high: + dev->dev.speed = USB_SPEED_HIGH; + break; + case usb_redir_speed_super: + dev->dev.speed = USB_SPEED_SUPER; + break; + default: + dev->dev.speed = USB_SPEED_FULL; + } + dev->dev.speedmask = (1 << dev->dev.speed); + + for (i = 0; i < MAX_ENDPOINTS; i++) { + usb_ep = usb_ep_get(&dev->dev, + (i & 0x10) ? USB_TOKEN_IN : USB_TOKEN_OUT, + i & 0x0f); + usb_ep->type = dev->endpoint[i].type; + usb_ep->ifnum = dev->endpoint[i].interface; + usb_ep->max_packet_size = dev->endpoint[i].max_packet_size; + if (dev->endpoint[i].type == usb_redir_type_bulk) { + usb_ep->pipeline = true; + } + } + return 0; +} + +/* For usbredirparser migration */ +static void usbredir_put_parser(QEMUFile *f, void *priv, size_t unused) +{ + USBRedirDevice *dev = priv; + uint8_t *data; + int len; + + if (dev->parser == NULL) { + qemu_put_be32(f, 0); + return; + } + + usbredirparser_serialize(dev->parser, &data, &len); + qemu_oom_check(data); + + qemu_put_be32(f, len); + qemu_put_buffer(f, data, len); + + free(data); +} + +static int usbredir_get_parser(QEMUFile *f, void *priv, size_t unused) +{ + USBRedirDevice *dev = priv; + uint8_t *data; + int len, ret; + + len = qemu_get_be32(f); + if (len == 0) { + return 0; + } + + /* + * Our chardev should be open already at this point, otherwise + * the usbredir channel will be broken (ie spice without seamless) + */ + if (dev->parser == NULL) { + ERROR("get_parser called with closed chardev, failing migration\n"); + return -1; + } + + data = g_malloc(len); + qemu_get_buffer(f, data, len); + + ret = usbredirparser_unserialize(dev->parser, data, len); + + g_free(data); + + return ret; +} + +static const VMStateInfo usbredir_parser_vmstate_info = { + .name = "usb-redir-parser", + .put = usbredir_put_parser, + .get = usbredir_get_parser, +}; + + +/* For buffered packets (iso/irq) queue migration */ +static void usbredir_put_bufpq(QEMUFile *f, void *priv, size_t unused) +{ + struct endp_data *endp = priv; + struct buf_packet *bufp; + int remain = endp->bufpq_size; + + qemu_put_be32(f, endp->bufpq_size); + QTAILQ_FOREACH(bufp, &endp->bufpq, next) { + qemu_put_be32(f, bufp->len); + qemu_put_be32(f, bufp->status); + qemu_put_buffer(f, bufp->data, bufp->len); + remain--; + } + assert(remain == 0); +} + +static int usbredir_get_bufpq(QEMUFile *f, void *priv, size_t unused) +{ + struct endp_data *endp = priv; + struct buf_packet *bufp; + int i; + + endp->bufpq_size = qemu_get_be32(f); + for (i = 0; i < endp->bufpq_size; i++) { + bufp = g_malloc(sizeof(struct buf_packet)); + bufp->len = qemu_get_be32(f); + bufp->status = qemu_get_be32(f); + bufp->data = qemu_oom_check(malloc(bufp->len)); /* regular malloc! */ + qemu_get_buffer(f, bufp->data, bufp->len); + QTAILQ_INSERT_TAIL(&endp->bufpq, bufp, next); + } + return 0; +} + +static const VMStateInfo usbredir_ep_bufpq_vmstate_info = { + .name = "usb-redir-bufpq", + .put = usbredir_put_bufpq, + .get = usbredir_get_bufpq, +}; + + +/* For endp_data migration */ +static const VMStateDescription usbredir_ep_vmstate = { + .name = "usb-redir-ep", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(type, struct endp_data), + VMSTATE_UINT8(interval, struct endp_data), + VMSTATE_UINT8(interface, struct endp_data), + VMSTATE_UINT16(max_packet_size, struct endp_data), + VMSTATE_UINT8(iso_started, struct endp_data), + VMSTATE_UINT8(iso_error, struct endp_data), + VMSTATE_UINT8(interrupt_started, struct endp_data), + VMSTATE_UINT8(interrupt_error, struct endp_data), + VMSTATE_UINT8(bufpq_prefilled, struct endp_data), + VMSTATE_UINT8(bufpq_dropping_packets, struct endp_data), + { + .name = "bufpq", + .version_id = 0, + .field_exists = NULL, + .size = 0, + .info = &usbredir_ep_bufpq_vmstate_info, + .flags = VMS_SINGLE, + .offset = 0, + }, + VMSTATE_INT32(bufpq_target_size, struct endp_data), + VMSTATE_END_OF_LIST() + } +}; + + +/* For PacketIdQueue migration */ +static void usbredir_put_packet_id_q(QEMUFile *f, void *priv, size_t unused) +{ + struct PacketIdQueue *q = priv; + USBRedirDevice *dev = q->dev; + struct PacketIdQueueEntry *e; + int remain = q->size; + + DPRINTF("put_packet_id_q %s size %d\n", q->name, q->size); + qemu_put_be32(f, q->size); + QTAILQ_FOREACH(e, &q->head, next) { + qemu_put_be64(f, e->id); + remain--; + } + assert(remain == 0); +} + +static int usbredir_get_packet_id_q(QEMUFile *f, void *priv, size_t unused) +{ + struct PacketIdQueue *q = priv; + USBRedirDevice *dev = q->dev; + int i, size; + uint64_t id; + + size = qemu_get_be32(f); + DPRINTF("get_packet_id_q %s size %d\n", q->name, size); + for (i = 0; i < size; i++) { + id = qemu_get_be64(f); + packet_id_queue_add(q, id); + } + assert(q->size == size); + return 0; +} + +static const VMStateInfo usbredir_ep_packet_id_q_vmstate_info = { + .name = "usb-redir-packet-id-q", + .put = usbredir_put_packet_id_q, + .get = usbredir_get_packet_id_q, +}; + +static const VMStateDescription usbredir_ep_packet_id_queue_vmstate = { + .name = "usb-redir-packet-id-queue", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + { + .name = "queue", + .version_id = 0, + .field_exists = NULL, + .size = 0, + .info = &usbredir_ep_packet_id_q_vmstate_info, + .flags = VMS_SINGLE, + .offset = 0, + }, + VMSTATE_END_OF_LIST() + } +}; + + +/* For usb_redir_device_connect_header migration */ +static const VMStateDescription usbredir_device_info_vmstate = { + .name = "usb-redir-device-info", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(speed, struct usb_redir_device_connect_header), + VMSTATE_UINT8(device_class, struct usb_redir_device_connect_header), + VMSTATE_UINT8(device_subclass, struct usb_redir_device_connect_header), + VMSTATE_UINT8(device_protocol, struct usb_redir_device_connect_header), + VMSTATE_UINT16(vendor_id, struct usb_redir_device_connect_header), + VMSTATE_UINT16(product_id, struct usb_redir_device_connect_header), + VMSTATE_UINT16(device_version_bcd, + struct usb_redir_device_connect_header), + VMSTATE_END_OF_LIST() + } +}; + + +/* For usb_redir_interface_info_header migration */ +static const VMStateDescription usbredir_interface_info_vmstate = { + .name = "usb-redir-interface-info", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(interface_count, + struct usb_redir_interface_info_header), + VMSTATE_UINT8_ARRAY(interface, + struct usb_redir_interface_info_header, 32), + VMSTATE_UINT8_ARRAY(interface_class, + struct usb_redir_interface_info_header, 32), + VMSTATE_UINT8_ARRAY(interface_subclass, + struct usb_redir_interface_info_header, 32), + VMSTATE_UINT8_ARRAY(interface_protocol, + struct usb_redir_interface_info_header, 32), + VMSTATE_END_OF_LIST() + } +}; + + +/* And finally the USBRedirDevice vmstate itself */ +static const VMStateDescription usbredir_vmstate = { + .name = "usb-redir", + .version_id = 1, + .minimum_version_id = 1, + .pre_save = usbredir_pre_save, + .post_load = usbredir_post_load, + .fields = (VMStateField[]) { + VMSTATE_USB_DEVICE(dev, USBRedirDevice), + VMSTATE_TIMER(attach_timer, USBRedirDevice), + { + .name = "parser", + .version_id = 0, + .field_exists = NULL, + .size = 0, + .info = &usbredir_parser_vmstate_info, + .flags = VMS_SINGLE, + .offset = 0, + }, + VMSTATE_STRUCT_ARRAY(endpoint, USBRedirDevice, MAX_ENDPOINTS, 1, + usbredir_ep_vmstate, struct endp_data), + VMSTATE_STRUCT(cancelled, USBRedirDevice, 1, + usbredir_ep_packet_id_queue_vmstate, + struct PacketIdQueue), + VMSTATE_STRUCT(already_in_flight, USBRedirDevice, 1, + usbredir_ep_packet_id_queue_vmstate, + struct PacketIdQueue), + VMSTATE_STRUCT(device_info, USBRedirDevice, 1, + usbredir_device_info_vmstate, + struct usb_redir_device_connect_header), + VMSTATE_STRUCT(interface_info, USBRedirDevice, 1, + usbredir_interface_info_vmstate, + struct usb_redir_interface_info_header), + VMSTATE_END_OF_LIST() + } +}; + static Property usbredir_properties[] = { DEFINE_PROP_CHR("chardev", USBRedirDevice, cs), DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0), @@ -1438,6 +1869,7 @@ static void usbredir_class_initfn(ObjectClass *klass, void *data) uc->handle_reset = usbredir_handle_reset; uc->handle_data = usbredir_handle_data; uc->handle_control = usbredir_handle_control; + dc->vmsd = &usbredir_vmstate; dc->props = usbredir_properties; } diff --git a/hw/vga-isa-mm.c b/hw/vga-isa-mm.c index 44ae7d92c..306e6ba44 100644 --- a/hw/vga-isa-mm.c +++ b/hw/vga-isa-mm.c @@ -107,6 +107,7 @@ static void vga_mm_init(ISAVGAMMState *s, target_phys_addr_t vram_base, s_ioport_ctrl = g_malloc(sizeof(*s_ioport_ctrl)); memory_region_init_io(s_ioport_ctrl, &vga_mm_ctrl_ops, s, "vga-mm-ctrl", 0x100000); + memory_region_set_flush_coalesced(s_ioport_ctrl); vga_io_memory = g_malloc(sizeof(*vga_io_memory)); /* XXX: endianness? */ @@ -361,6 +361,8 @@ uint32_t vga_ioport_read(void *opaque, uint32_t addr) VGACommonState *s = opaque; int val, index; + qemu_flush_coalesced_mmio_buffer(); + if (vga_ioport_invalid(s, addr)) { val = 0xff; } else { @@ -453,6 +455,8 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) VGACommonState *s = opaque; int index; + qemu_flush_coalesced_mmio_buffer(); + /* check port range access depending on color/monochrome mode */ if (vga_ioport_invalid(s, addr)) { return; @@ -2338,6 +2342,7 @@ MemoryRegion *vga_init_io(VGACommonState *s, vga_mem = g_malloc(sizeof(*vga_mem)); memory_region_init_io(vga_mem, &vga_mem_ops, s, "vga-lowmem", 0x20000); + memory_region_set_flush_coalesced(vga_mem); return vga_mem; } diff --git a/hw/virtio-net.c b/hw/virtio-net.c index b1998b27d..649074329 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -447,10 +447,6 @@ static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq) VirtIONet *n = to_virtio_net(vdev); qemu_flush_queued_packets(&n->nic->nc); - - /* We now have RX buffers, signal to the IO thread to break out of the - * select to re-poll the tap file descriptor */ - qemu_notify_event(); } static int virtio_net_can_receive(NetClientState *nc) diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index b68e88367..e815a04e9 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -1186,6 +1186,7 @@ static int pci_vmsvga_initfn(PCIDevice *dev) memory_region_init_io(&s->io_bar, &vmsvga_io_ops, &s->chip, "vmsvga-io", 0x10); + memory_region_set_flush_coalesced(&s->io_bar); pci_register_bar(&s->card, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar); vmsvga_init(&s->chip, pci_address_space(dev), diff --git a/hw/xen-host-pci-device.c b/hw/xen-host-pci-device.c index e7ff680ef..743b37b99 100644 --- a/hw/xen-host-pci-device.c +++ b/hw/xen-host-pci-device.c @@ -47,13 +47,13 @@ static int xen_host_pci_sysfs_path(const XenHostPCIDevice *d, } -/* This size should be enough to read the first 7 lines of a ressource file */ -#define XEN_HOST_PCI_RESSOURCE_BUFFER_SIZE 400 +/* This size should be enough to read the first 7 lines of a resource file */ +#define XEN_HOST_PCI_RESOURCE_BUFFER_SIZE 400 static int xen_host_pci_get_resource(XenHostPCIDevice *d) { int i, rc, fd; char path[PATH_MAX]; - char buf[XEN_HOST_PCI_RESSOURCE_BUFFER_SIZE]; + char buf[XEN_HOST_PCI_RESOURCE_BUFFER_SIZE]; unsigned long long start, end, flags, size; char *endptr, *s; uint8_t type; diff --git a/hw/xen_nic.c b/hw/xen_nic.c index 8b79bfb73..cf7d5591b 100644 --- a/hw/xen_nic.c +++ b/hw/xen_nic.c @@ -415,6 +415,7 @@ static void net_event(struct XenDevice *xendev) { struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev); net_tx_packets(netdev); + qemu_flush_queued_packets(&netdev->nic->nc); } static int net_free(struct XenDevice *xendev) diff --git a/hw/xen_pt.h b/hw/xen_pt.h index 41904ece9..112477a88 100644 --- a/hw/xen_pt.h +++ b/hw/xen_pt.h @@ -96,7 +96,7 @@ typedef struct XenPTRegion { * - do NOT use ALL F for init_val, otherwise the tbl will not be registered. */ -/* emulated register infomation */ +/* emulated register information */ struct XenPTRegInfo { uint32_t offset; uint32_t size; @@ -140,7 +140,7 @@ typedef int (*xen_pt_reg_size_init_fn) (XenPCIPassthroughState *, const XenPTRegGroupInfo *, uint32_t base_offset, uint8_t *size); -/* emulated register group infomation */ +/* emulated register group information */ struct XenPTRegGroupInfo { uint8_t grp_id; XenPTRegisterGroupType grp_type; diff --git a/hw/xen_pt_config_init.c b/hw/xen_pt_config_init.c index 00eb3d997..e524a4094 100644 --- a/hw/xen_pt_config_init.c +++ b/hw/xen_pt_config_init.c @@ -562,7 +562,7 @@ static int xen_pt_exp_rom_bar_reg_write(XenPCIPassthroughState *s, return 0; } -/* Header Type0 reg static infomation table */ +/* Header Type0 reg static information table */ static XenPTRegInfo xen_pt_emu_reg_header0[] = { /* Vendor ID reg */ { @@ -753,7 +753,7 @@ static XenPTRegInfo xen_pt_emu_reg_header0[] = { * Vital Product Data Capability */ -/* Vital Product Data Capability Structure reg static infomation table */ +/* Vital Product Data Capability Structure reg static information table */ static XenPTRegInfo xen_pt_emu_reg_vpd[] = { { .offset = PCI_CAP_LIST_NEXT, @@ -775,7 +775,7 @@ static XenPTRegInfo xen_pt_emu_reg_vpd[] = { * Vendor Specific Capability */ -/* Vendor Specific Capability Structure reg static infomation table */ +/* Vendor Specific Capability Structure reg static information table */ static XenPTRegInfo xen_pt_emu_reg_vendor[] = { { .offset = PCI_CAP_LIST_NEXT, @@ -866,7 +866,7 @@ static int xen_pt_linkctrl2_reg_init(XenPCIPassthroughState *s, return 0; } -/* PCI Express Capability Structure reg static infomation table */ +/* PCI Express Capability Structure reg static information table */ static XenPTRegInfo xen_pt_emu_reg_pcie[] = { /* Next Pointer reg */ { @@ -981,7 +981,7 @@ static int xen_pt_pmcsr_reg_write(XenPCIPassthroughState *s, return 0; } -/* Power Management Capability reg static infomation table */ +/* Power Management Capability reg static information table */ static XenPTRegInfo xen_pt_emu_reg_pm[] = { /* Next Pointer reg */ { @@ -1259,7 +1259,7 @@ static int xen_pt_msgdata_reg_write(XenPCIPassthroughState *s, return 0; } -/* MSI Capability Structure reg static infomation table */ +/* MSI Capability Structure reg static information table */ static XenPTRegInfo xen_pt_emu_reg_msi[] = { /* Next Pointer reg */ { @@ -1396,7 +1396,7 @@ static int xen_pt_msixctrl_reg_write(XenPCIPassthroughState *s, return 0; } -/* MSI-X Capability Structure reg static infomation table */ +/* MSI-X Capability Structure reg static information table */ static XenPTRegInfo xen_pt_emu_reg_msix[] = { /* Next Pointer reg */ { diff --git a/hw/xilinx.h b/hw/xilinx.h index 556c5aa9f..98300477a 100644 --- a/hw/xilinx.h +++ b/hw/xilinx.h @@ -21,9 +21,9 @@ xilinx_timer_create(target_phys_addr_t base, qemu_irq irq, int oto, int freq) { DeviceState *dev; - dev = qdev_create(NULL, "xlnx,xps-timer"); + dev = qdev_create(NULL, "xlnx.xps-timer"); qdev_prop_set_uint32(dev, "one-timer-only", oto); - qdev_prop_set_uint32(dev, "frequency", freq); + qdev_prop_set_uint32(dev, "clock-frequency", freq); qdev_init_nofail(dev); sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); @@ -55,13 +55,17 @@ xilinx_axiethernet_create(NICInfo *nd, StreamSlave *peer, int txmem, int rxmem) { DeviceState *dev; + Error *errp = NULL; + qemu_check_nic_model(nd, "xlnx.axi-ethernet"); dev = qdev_create(NULL, "xlnx.axi-ethernet"); qdev_set_nic_properties(dev, nd); qdev_prop_set_uint32(dev, "rxmem", rxmem); qdev_prop_set_uint32(dev, "txmem", txmem); - object_property_set_link(OBJECT(dev), OBJECT(peer), "tx_dev", NULL); + object_property_set_link(OBJECT(dev), OBJECT(peer), "axistream-connected", + &errp); + assert_no_error(errp); qdev_init_nofail(dev); sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); @@ -74,8 +78,12 @@ xilinx_axiethernetdma_init(DeviceState *dev, StreamSlave *peer, target_phys_addr_t base, qemu_irq irq, qemu_irq irq2, int freqhz) { + Error *errp = NULL; + qdev_prop_set_uint32(dev, "freqhz", freqhz); - object_property_set_link(OBJECT(dev), OBJECT(peer), "tx_dev", NULL); + object_property_set_link(OBJECT(dev), OBJECT(peer), "axistream-connected", + &errp); + assert_no_error(errp); qdev_init_nofail(dev); sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c index b562bd065..2e48ca2be 100644 --- a/hw/xilinx_timer.c +++ b/hw/xilinx_timer.c @@ -24,6 +24,7 @@ #include "sysbus.h" #include "ptimer.h" +#include "qemu-log.h" #define D(x) @@ -119,7 +120,7 @@ timer_read(void *opaque, target_phys_addr_t addr, unsigned int size) break; } - D(printf("%s timer=%d %x=%x\n", __func__, timer, addr * 4, r)); + D(fprintf(stderr, "%s timer=%d %x=%x\n", __func__, timer, addr * 4, r)); return r; } @@ -127,7 +128,7 @@ static void timer_enable(struct xlx_timer *xt) { uint64_t count; - D(printf("%s timer=%d down=%d\n", __func__, + D(fprintf(stderr, "%s timer=%d down=%d\n", __func__, xt->nr, xt->regs[R_TCSR] & TCSR_UDT)); ptimer_stop(xt->ptimer); @@ -152,7 +153,7 @@ timer_write(void *opaque, target_phys_addr_t addr, addr >>= 2; timer = timer_from_addr(addr); xt = &t->timers[timer]; - D(printf("%s addr=%x val=%x (timer=%d off=%d)\n", + D(fprintf(stderr, "%s addr=%x val=%x (timer=%d off=%d)\n", __func__, addr * 4, value, timer, addr & 3)); /* Further decoding to address a specific timers reg. */ addr &= 3; @@ -189,7 +190,7 @@ static void timer_hit(void *opaque) { struct xlx_timer *xt = opaque; struct timerblock *t = xt->parent; - D(printf("%s %d\n", __func__, timer)); + D(fprintf(stderr, "%s %d\n", __func__, xt->nr)); xt->regs[R_TCSR] |= TCSR_TINT; if (xt->regs[R_TCSR] & TCSR_ARHT) @@ -217,14 +218,15 @@ static int xilinx_timer_init(SysBusDevice *dev) ptimer_set_freq(xt->ptimer, t->freq_hz); } - memory_region_init_io(&t->mmio, &timer_ops, t, "xlnx,xps-timer", + memory_region_init_io(&t->mmio, &timer_ops, t, "xlnx.xps-timer", R_MAX * 4 * num_timers(t)); sysbus_init_mmio(dev, &t->mmio); return 0; } static Property xilinx_timer_properties[] = { - DEFINE_PROP_UINT32("frequency", struct timerblock, freq_hz, 62 * 1000000), + DEFINE_PROP_UINT32("clock-frequency", struct timerblock, freq_hz, + 62 * 1000000), DEFINE_PROP_UINT8("one-timer-only", struct timerblock, one_timer_only, 0), DEFINE_PROP_END_OF_LIST(), }; @@ -239,7 +241,7 @@ static void xilinx_timer_class_init(ObjectClass *klass, void *data) } static TypeInfo xilinx_timer_info = { - .name = "xlnx,xps-timer", + .name = "xlnx.xps-timer", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct timerblock), .class_init = xilinx_timer_class_init, |