diff options
61 files changed, 1991 insertions, 753 deletions
@@ -2916,7 +2916,8 @@ if test "$softmmu" = yes ; then tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)" else if test "$virtfs" = yes; then - feature_not_found "virtfs" + echo "VirtFS is supported only on Linux and requires libcap-devel and libattr-devel" + exit 1 fi virtfs=no fi @@ -1076,11 +1076,11 @@ TranslationBlock *tb_gen_code(CPUArchState *env, } /* - * invalidate all TBs which intersect with the target physical pages - * starting in range [start;end[. NOTE: start and end may refer to - * different physical pages. 'is_cpu_write_access' should be true if called - * from a real cpu write access: the virtual CPU will exit the current - * TB if code is modified inside this TB. + * Invalidate all TBs which intersect with the target physical address range + * [start;end[. NOTE: start and end may refer to *different* physical pages. + * 'is_cpu_write_access' should be true if called from a real cpu write + * access: the virtual CPU will exit the current TB if code is modified inside + * this TB. */ void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end, int is_cpu_write_access) @@ -1092,11 +1092,13 @@ void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end, } } -/* invalidate all TBs which intersect with the target physical page - starting in range [start;end[. NOTE: start and end must refer to - the same physical page. 'is_cpu_write_access' should be true if called - from a real cpu write access: the virtual CPU will exit the current - TB if code is modified inside this TB. */ +/* + * Invalidate all TBs which intersect with the target physical address range + * [start;end[. NOTE: start and end must refer to the *same* physical page. + * 'is_cpu_write_access' should be true if called from a real cpu write + * access: the virtual CPU will exit the current TB if code is modified inside + * this TB. + */ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, int is_cpu_write_access) { diff --git a/hw/arm-misc.h b/hw/arm-misc.h index 2f46e21..1d51570c 100644 --- a/hw/arm-misc.h +++ b/hw/arm-misc.h @@ -16,7 +16,7 @@ /* The CPU is also modeled as an interrupt controller. */ #define ARM_PIC_CPU_IRQ 0 #define ARM_PIC_CPU_FIQ 1 -qemu_irq *arm_pic_init_cpu(CPUARMState *env); +qemu_irq *arm_pic_init_cpu(ARMCPU *cpu); /* armv7m.c */ qemu_irq *armv7m_init(MemoryRegion *address_space_mem, @@ -50,16 +50,16 @@ struct arm_boot_info { * perform any necessary CPU reset handling and set the PC for thei * secondary CPUs to point at this boot blob. */ - void (*write_secondary_boot)(CPUARMState *env, + void (*write_secondary_boot)(ARMCPU *cpu, const struct arm_boot_info *info); - void (*secondary_cpu_reset_hook)(CPUARMState *env, + void (*secondary_cpu_reset_hook)(ARMCPU *cpu, const struct arm_boot_info *info); /* Used internally by arm_boot.c */ int is_linux; target_phys_addr_t initrd_size; target_phys_addr_t entry; }; -void arm_load_kernel(CPUARMState *env, struct arm_boot_info *info); +void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info); /* Multiplication factor to convert from system clock ticks to qemu timer ticks. */ diff --git a/hw/arm_boot.c b/hw/arm_boot.c index eb2d176..d0e643b 100644 --- a/hw/arm_boot.c +++ b/hw/arm_boot.c @@ -59,7 +59,7 @@ static uint32_t smpboot[] = { 0 /* bootreg: Boot register address is held here */ }; -static void default_write_secondary(CPUARMState *env, +static void default_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info) { int n; @@ -72,9 +72,11 @@ static void default_write_secondary(CPUARMState *env, info->smp_loader_start); } -static void default_reset_secondary(CPUARMState *env, +static void default_reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info) { + CPUARMState *env = &cpu->env; + stl_phys_notdirty(info->smp_bootreg_addr, 0); env->regs[15] = info->smp_loader_start; } @@ -295,15 +297,15 @@ static void do_cpu_reset(void *opaque) } } } else { - info->secondary_cpu_reset_hook(env, info); + info->secondary_cpu_reset_hook(cpu, info); } } } } -void arm_load_kernel(CPUARMState *env, struct arm_boot_info *info) +void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) { - ARMCPU *cpu; + CPUARMState *env = &cpu->env; int kernel_size; int initrd_size; int n; @@ -402,7 +404,7 @@ void arm_load_kernel(CPUARMState *env, struct arm_boot_info *info) rom_add_blob_fixed("bootloader", bootloader, sizeof(bootloader), info->loader_start); if (info->nb_cpus > 1) { - info->write_secondary_boot(env, info); + info->write_secondary_boot(cpu, info); } } info->is_linux = is_linux; diff --git a/hw/arm_pic.c b/hw/arm_pic.c index 1094965..ffb4d41 100644 --- a/hw/arm_pic.c +++ b/hw/arm_pic.c @@ -13,7 +13,9 @@ /* Input 0 is IRQ and input 1 is FIQ. */ static void arm_pic_cpu_handler(void *opaque, int irq, int level) { - CPUARMState *env = (CPUARMState *)opaque; + ARMCPU *cpu = opaque; + CPUARMState *env = &cpu->env; + switch (irq) { case ARM_PIC_CPU_IRQ: if (level) @@ -32,7 +34,7 @@ static void arm_pic_cpu_handler(void *opaque, int irq, int level) } } -qemu_irq *arm_pic_init_cpu(CPUARMState *env) +qemu_irq *arm_pic_init_cpu(ARMCPU *cpu) { - return qemu_allocate_irqs(arm_pic_cpu_handler, env, 2); + return qemu_allocate_irqs(arm_pic_cpu_handler, cpu, 2); } diff --git a/hw/armv7m.c b/hw/armv7m.c index 418139a..8cec78d 100644 --- a/hw/armv7m.c +++ b/hw/armv7m.c @@ -215,7 +215,7 @@ qemu_irq *armv7m_init(MemoryRegion *address_space_mem, nvic = qdev_create(NULL, "armv7m_nvic"); env->nvic = nvic; qdev_init_nofail(nvic); - cpu_pic = arm_pic_init_cpu(env); + cpu_pic = arm_pic_init_cpu(cpu); sysbus_connect_irq(sysbus_from_qdev(nvic), 0, cpu_pic[ARM_PIC_CPU_IRQ]); for (i = 0; i < 64; i++) { pic[i] = qdev_get_gpio_in(nvic, i); diff --git a/hw/collie.c b/hw/collie.c index 42f4310..56f89a9 100644 --- a/hw/collie.c +++ b/hw/collie.c @@ -54,7 +54,7 @@ static void collie_init(ram_addr_t ram_size, collie_binfo.kernel_cmdline = kernel_cmdline; collie_binfo.initrd_filename = initrd_filename; collie_binfo.board_id = 0x208; - arm_load_kernel(s->env, &collie_binfo); + arm_load_kernel(s->cpu, &collie_binfo); } static QEMUMachine collie_machine = { diff --git a/hw/exynos4210.c b/hw/exynos4210.c index afc4bdc..dd14d01 100644 --- a/hw/exynos4210.c +++ b/hw/exynos4210.c @@ -65,7 +65,7 @@ static uint8_t chipid_and_omr[] = { 0x11, 0x02, 0x21, 0x43, 0x09, 0x00, 0x00, 0x00 }; -void exynos4210_write_secondary(CPUARMState *env, +void exynos4210_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info) { int n; @@ -107,13 +107,14 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem, SysBusDevice *busdev; for (n = 0; n < EXYNOS4210_NCPUS; n++) { - s->env[n] = cpu_init("cortex-a9"); - if (!s->env[n]) { + s->cpu[n] = cpu_arm_init("cortex-a9"); + if (!s->cpu[n]) { fprintf(stderr, "Unable to find CPU %d definition\n", n); exit(1); } + /* Create PIC controller for each processor instance */ - irqp = arm_pic_init_cpu(s->env[n]); + irqp = arm_pic_init_cpu(s->cpu[n]); /* * Get GICs gpio_in cpu_irq to connect a combiner to them later. diff --git a/hw/exynos4210.h b/hw/exynos4210.h index f7c7027..b1b4609 100644 --- a/hw/exynos4210.h +++ b/hw/exynos4210.h @@ -83,7 +83,7 @@ typedef struct Exynos4210Irq { } Exynos4210Irq; typedef struct Exynos4210State { - CPUARMState * env[EXYNOS4210_NCPUS]; + ARMCPU *cpu[EXYNOS4210_NCPUS]; Exynos4210Irq irqs; qemu_irq *irq_table; @@ -97,7 +97,7 @@ typedef struct Exynos4210State { MemoryRegion bootreg_mem; } Exynos4210State; -void exynos4210_write_secondary(CPUARMState *env, +void exynos4210_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info); Exynos4210State *exynos4210_init(MemoryRegion *system_mem, diff --git a/hw/exynos4_boards.c b/hw/exynos4_boards.c index ea32c51..e5c2a5f 100644 --- a/hw/exynos4_boards.c +++ b/hw/exynos4_boards.c @@ -138,7 +138,7 @@ static void nuri_init(ram_addr_t ram_size, exynos4_boards_init_common(kernel_filename, kernel_cmdline, initrd_filename, EXYNOS4_BOARD_NURI); - arm_load_kernel(first_cpu, &exynos4_board_binfo); + arm_load_kernel(arm_env_get_cpu(first_cpu), &exynos4_board_binfo); } static void smdkc210_init(ram_addr_t ram_size, @@ -151,7 +151,7 @@ static void smdkc210_init(ram_addr_t ram_size, lan9215_init(SMDK_LAN9118_BASE_ADDR, qemu_irq_invert(s->irq_table[exynos4210_get_irq(37, 1)])); - arm_load_kernel(first_cpu, &exynos4_board_binfo); + arm_load_kernel(arm_env_get_cpu(first_cpu), &exynos4_board_binfo); } static QEMUMachine exynos4_machines[EXYNOS4_NUM_OF_BOARDS] = { diff --git a/hw/highbank.c b/hw/highbank.c index 4d6d728..4bdea5d 100644 --- a/hw/highbank.c +++ b/hw/highbank.c @@ -36,7 +36,7 @@ /* Board init. */ -static void hb_write_secondary(CPUARMState *env, const struct arm_boot_info *info) +static void hb_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info) { int n; uint32_t smpboot[] = { @@ -60,8 +60,10 @@ static void hb_write_secondary(CPUARMState *env, const struct arm_boot_info *inf rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), SMP_BOOT_ADDR); } -static void hb_reset_secondary(CPUARMState *env, const struct arm_boot_info *info) +static void hb_reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info) { + CPUARMState *env = &cpu->env; + switch (info->nb_cpus) { case 4: stl_phys_notdirty(SMP_BOOT_REG + 0x30, 0); @@ -190,7 +192,6 @@ static void highbank_init(ram_addr_t ram_size, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { - CPUARMState *env = NULL; DeviceState *dev; SysBusDevice *busdev; qemu_irq *irqp; @@ -213,10 +214,10 @@ static void highbank_init(ram_addr_t ram_size, fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - env = &cpu->env; + /* This will become a QOM property eventually */ cpu->reset_cbar = GIC_BASE_ADDR; - irqp = arm_pic_init_cpu(env); + irqp = arm_pic_init_cpu(cpu); cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; } @@ -316,7 +317,7 @@ static void highbank_init(ram_addr_t ram_size, highbank_binfo.loader_start = 0; highbank_binfo.write_secondary_boot = hb_write_secondary; highbank_binfo.secondary_cpu_reset_hook = hb_reset_secondary; - arm_load_kernel(first_cpu, &highbank_binfo); + arm_load_kernel(arm_env_get_cpu(first_cpu), &highbank_binfo); } static QEMUMachine highbank_machine = { diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 9bdb9e6..deacbf4 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -443,7 +443,7 @@ static void integratorcp_init(ram_addr_t ram_size, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { - CPUARMState *env; + ARMCPU *cpu; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); MemoryRegion *ram_alias = g_new(MemoryRegion, 1); @@ -452,13 +452,15 @@ static void integratorcp_init(ram_addr_t ram_size, DeviceState *dev; int i; - if (!cpu_model) + if (!cpu_model) { cpu_model = "arm926"; - env = cpu_init(cpu_model); - if (!env) { + } + cpu = cpu_arm_init(cpu_model); + if (!cpu) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } + memory_region_init_ram(ram, "integrator.ram", ram_size); vmstate_register_ram_global(ram); /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */ @@ -474,7 +476,7 @@ static void integratorcp_init(ram_addr_t ram_size, qdev_init_nofail(dev); sysbus_mmio_map((SysBusDevice *)dev, 0, 0x10000000); - cpu_pic = arm_pic_init_cpu(env); + cpu_pic = arm_pic_init_cpu(cpu); dev = sysbus_create_varargs("integrator_pic", 0x14000000, cpu_pic[ARM_PIC_CPU_IRQ], cpu_pic[ARM_PIC_CPU_FIQ], NULL); @@ -500,7 +502,7 @@ static void integratorcp_init(ram_addr_t ram_size, integrator_binfo.kernel_filename = kernel_filename; integrator_binfo.kernel_cmdline = kernel_cmdline; integrator_binfo.initrd_filename = initrd_filename; - arm_load_kernel(env, &integrator_binfo); + arm_load_kernel(cpu, &integrator_binfo); } static QEMUMachine integratorcp_machine = { diff --git a/hw/mainstone.c b/hw/mainstone.c index 00a8adc..97687b6 100644 --- a/hw/mainstone.c +++ b/hw/mainstone.c @@ -102,7 +102,7 @@ static void mainstone_common_init(MemoryRegion *address_space_mem, { uint32_t sector_len = 256 * 1024; target_phys_addr_t mainstone_flash_base[] = { MST_FLASH_0, MST_FLASH_1 }; - PXA2xxState *cpu; + PXA2xxState *mpu; DeviceState *mst_irq; DriveInfo *dinfo; int i; @@ -113,7 +113,7 @@ static void mainstone_common_init(MemoryRegion *address_space_mem, cpu_model = "pxa270-c5"; /* Setup CPU & memory */ - cpu = pxa270_init(address_space_mem, mainstone_binfo.ram_size, cpu_model); + mpu = pxa270_init(address_space_mem, mainstone_binfo.ram_size, cpu_model); memory_region_init_ram(rom, "mainstone.rom", MAINSTONE_ROM); vmstate_register_ram_global(rom); memory_region_set_readonly(rom, true); @@ -145,19 +145,19 @@ static void mainstone_common_init(MemoryRegion *address_space_mem, } mst_irq = sysbus_create_simple("mainstone-fpga", MST_FPGA_PHYS, - qdev_get_gpio_in(cpu->gpio, 0)); + qdev_get_gpio_in(mpu->gpio, 0)); /* setup keypad */ printf("map addr %p\n", &map); - pxa27x_register_keypad(cpu->kp, map, 0xe0); + pxa27x_register_keypad(mpu->kp, map, 0xe0); /* MMC/SD host */ - pxa2xx_mmci_handlers(cpu->mmc, NULL, qdev_get_gpio_in(mst_irq, MMC_IRQ)); + pxa2xx_mmci_handlers(mpu->mmc, NULL, qdev_get_gpio_in(mst_irq, MMC_IRQ)); - pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0], + pxa2xx_pcmcia_set_irq_cb(mpu->pcmcia[0], qdev_get_gpio_in(mst_irq, S0_IRQ), qdev_get_gpio_in(mst_irq, S0_CD_IRQ)); - pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1], + pxa2xx_pcmcia_set_irq_cb(mpu->pcmcia[1], qdev_get_gpio_in(mst_irq, S1_IRQ), qdev_get_gpio_in(mst_irq, S1_CD_IRQ)); @@ -168,7 +168,7 @@ static void mainstone_common_init(MemoryRegion *address_space_mem, mainstone_binfo.kernel_cmdline = kernel_cmdline; mainstone_binfo.initrd_filename = initrd_filename; mainstone_binfo.board_id = arm_id; - arm_load_kernel(&cpu->cpu->env, &mainstone_binfo); + arm_load_kernel(mpu->cpu, &mainstone_binfo); } static void mainstone_init(ram_addr_t ram_size, diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 9c64e0a..3777f85 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -599,13 +599,6 @@ static const MemoryRegionOps cmos_ops = { .old_portio = cmos_portio }; -// FIXME add int32 visitor -static void visit_type_int32(Visitor *v, int *value, const char *name, Error **errp) -{ - int64_t val = *value; - visit_type_int(v, &val, name, errp); -} - static void rtc_get_date(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { diff --git a/hw/musicpal.c b/hw/musicpal.c index c9f845a..f14f20d 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -1513,7 +1513,7 @@ static void musicpal_init(ram_addr_t ram_size, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { - CPUARMState *env; + ARMCPU *cpu; qemu_irq *cpu_pic; qemu_irq pic[32]; DeviceState *dev; @@ -1533,12 +1533,12 @@ static void musicpal_init(ram_addr_t ram_size, if (!cpu_model) { cpu_model = "arm926"; } - env = cpu_init(cpu_model); - if (!env) { + cpu = cpu_arm_init(cpu_model); + if (!cpu) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - cpu_pic = arm_pic_init_cpu(env); + cpu_pic = arm_pic_init_cpu(cpu); /* For now we use a fixed - the original - RAM size */ memory_region_init_ram(ram, "musicpal.ram", MP_RAM_DEFAULT_SIZE); @@ -1651,7 +1651,7 @@ static void musicpal_init(ram_addr_t ram_size, musicpal_binfo.kernel_filename = kernel_filename; musicpal_binfo.kernel_cmdline = kernel_cmdline; musicpal_binfo.initrd_filename = initrd_filename; - arm_load_kernel(env, &musicpal_binfo); + arm_load_kernel(cpu, &musicpal_binfo); } static QEMUMachine musicpal_machine = { diff --git a/hw/nseries.c b/hw/nseries.c index b8c6a29..fcc8546 100644 --- a/hw/nseries.c +++ b/hw/nseries.c @@ -37,7 +37,7 @@ /* Nokia N8x0 support */ struct n800_s { - struct omap_mpu_state_s *cpu; + struct omap_mpu_state_s *mpu; struct rfbi_chip_s blizzard; struct { @@ -135,10 +135,10 @@ static void n800_mmc_cs_cb(void *opaque, int line, int level) static void n8x0_gpio_setup(struct n800_s *s) { - qemu_irq *mmc_cs = qemu_allocate_irqs(n800_mmc_cs_cb, s->cpu->mmc, 1); - qdev_connect_gpio_out(s->cpu->gpio, N8X0_MMC_CS_GPIO, mmc_cs[0]); + qemu_irq *mmc_cs = qemu_allocate_irqs(n800_mmc_cs_cb, s->mpu->mmc, 1); + qdev_connect_gpio_out(s->mpu->gpio, N8X0_MMC_CS_GPIO, mmc_cs[0]); - qemu_irq_lower(qdev_get_gpio_in(s->cpu->gpio, N800_BAT_COVER_GPIO)); + qemu_irq_lower(qdev_get_gpio_in(s->mpu->gpio, N800_BAT_COVER_GPIO)); } #define MAEMO_CAL_HEADER(...) \ @@ -179,8 +179,8 @@ static void n8x0_nand_setup(struct n800_s *s) } qdev_init_nofail(s->nand); sysbus_connect_irq(sysbus_from_qdev(s->nand), 0, - qdev_get_gpio_in(s->cpu->gpio, N8X0_ONENAND_GPIO)); - omap_gpmc_attach(s->cpu->gpmc, N8X0_ONENAND_CS, + qdev_get_gpio_in(s->mpu->gpio, N8X0_ONENAND_GPIO)); + omap_gpmc_attach(s->mpu->gpmc, N8X0_ONENAND_CS, sysbus_mmio_get_region(sysbus_from_qdev(s->nand), 0)); otp_region = onenand_raw_otp(s->nand); @@ -192,13 +192,13 @@ static void n8x0_nand_setup(struct n800_s *s) static void n8x0_i2c_setup(struct n800_s *s) { DeviceState *dev; - qemu_irq tmp_irq = qdev_get_gpio_in(s->cpu->gpio, N8X0_TMP105_GPIO); - i2c_bus *i2c = omap_i2c_bus(s->cpu->i2c[0]); + qemu_irq tmp_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_TMP105_GPIO); + i2c_bus *i2c = omap_i2c_bus(s->mpu->i2c[0]); /* Attach a menelaus PM chip */ dev = i2c_create_slave(i2c, "twl92230", N8X0_MENELAUS_ADDR); qdev_connect_gpio_out(dev, 3, - qdev_get_gpio_in(s->cpu->ih[0], + qdev_get_gpio_in(s->mpu->ih[0], OMAP_INT_24XX_SYS_NIRQ)); qemu_system_powerdown = qdev_get_gpio_in(dev, 3); @@ -263,8 +263,8 @@ static void n800_tsc_kbd_setup(struct n800_s *s) /* XXX: are the three pins inverted inside the chip between the * tsc and the cpu (N4111)? */ qemu_irq penirq = NULL; /* NC */ - qemu_irq kbirq = qdev_get_gpio_in(s->cpu->gpio, N800_TSC_KP_IRQ_GPIO); - qemu_irq dav = qdev_get_gpio_in(s->cpu->gpio, N800_TSC_TS_GPIO); + qemu_irq kbirq = qdev_get_gpio_in(s->mpu->gpio, N800_TSC_KP_IRQ_GPIO); + qemu_irq dav = qdev_get_gpio_in(s->mpu->gpio, N800_TSC_TS_GPIO); s->ts.chip = tsc2301_init(penirq, kbirq, dav); s->ts.opaque = s->ts.chip->opaque; @@ -283,7 +283,7 @@ static void n800_tsc_kbd_setup(struct n800_s *s) static void n810_tsc_setup(struct n800_s *s) { - qemu_irq pintdav = qdev_get_gpio_in(s->cpu->gpio, N810_TSC_TS_GPIO); + qemu_irq pintdav = qdev_get_gpio_in(s->mpu->gpio, N810_TSC_TS_GPIO); s->ts.opaque = tsc2005_init(pintdav); s->ts.txrx = tsc2005_txrx; @@ -375,7 +375,7 @@ static int n810_keys[0x80] = { static void n810_kbd_setup(struct n800_s *s) { - qemu_irq kbd_irq = qdev_get_gpio_in(s->cpu->gpio, N810_KEYBOARD_GPIO); + qemu_irq kbd_irq = qdev_get_gpio_in(s->mpu->gpio, N810_KEYBOARD_GPIO); int i; for (i = 0; i < 0x80; i ++) @@ -388,7 +388,7 @@ static void n810_kbd_setup(struct n800_s *s) /* Attach the LM8322 keyboard to the I2C bus, * should happen in n8x0_i2c_setup and s->kbd be initialised here. */ - s->kbd = i2c_create_slave(omap_i2c_bus(s->cpu->i2c[0]), + s->kbd = i2c_create_slave(omap_i2c_bus(s->mpu->i2c[0]), "lm8323", N810_LM8323_ADDR); qdev_connect_gpio_out(s->kbd, 0, kbd_irq); } @@ -679,8 +679,8 @@ static void n8x0_spi_setup(struct n800_s *s) void *tsc = s->ts.opaque; void *mipid = mipid_init(); - omap_mcspi_attach(s->cpu->mcspi[0], s->ts.txrx, tsc, 0); - omap_mcspi_attach(s->cpu->mcspi[0], mipid_txrx, mipid, 1); + omap_mcspi_attach(s->mpu->mcspi[0], s->ts.txrx, tsc, 0); + omap_mcspi_attach(s->mpu->mcspi[0], mipid_txrx, mipid, 1); } /* This task is normally performed by the bootloader. If we're loading @@ -735,20 +735,20 @@ static void n8x0_dss_setup(struct n800_s *s) s->blizzard.write = s1d13745_write; s->blizzard.read = s1d13745_read; - omap_rfbi_attach(s->cpu->dss, 0, &s->blizzard); + omap_rfbi_attach(s->mpu->dss, 0, &s->blizzard); } static void n8x0_cbus_setup(struct n800_s *s) { - qemu_irq dat_out = qdev_get_gpio_in(s->cpu->gpio, N8X0_CBUS_DAT_GPIO); - qemu_irq retu_irq = qdev_get_gpio_in(s->cpu->gpio, N8X0_RETU_GPIO); - qemu_irq tahvo_irq = qdev_get_gpio_in(s->cpu->gpio, N8X0_TAHVO_GPIO); + qemu_irq dat_out = qdev_get_gpio_in(s->mpu->gpio, N8X0_CBUS_DAT_GPIO); + qemu_irq retu_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_RETU_GPIO); + qemu_irq tahvo_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_TAHVO_GPIO); CBus *cbus = cbus_init(dat_out); - qdev_connect_gpio_out(s->cpu->gpio, N8X0_CBUS_CLK_GPIO, cbus->clk); - qdev_connect_gpio_out(s->cpu->gpio, N8X0_CBUS_DAT_GPIO, cbus->dat); - qdev_connect_gpio_out(s->cpu->gpio, N8X0_CBUS_SEL_GPIO, cbus->sel); + qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_CLK_GPIO, cbus->clk); + qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_DAT_GPIO, cbus->dat); + qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_SEL_GPIO, cbus->sel); cbus_attach(cbus, s->retu = retu_init(retu_irq, 1)); cbus_attach(cbus, s->tahvo = tahvo_init(tahvo_irq, 1)); @@ -757,14 +757,14 @@ static void n8x0_cbus_setup(struct n800_s *s) static void n8x0_uart_setup(struct n800_s *s) { CharDriverState *radio = uart_hci_init( - qdev_get_gpio_in(s->cpu->gpio, N8X0_BT_HOST_WKUP_GPIO)); + qdev_get_gpio_in(s->mpu->gpio, N8X0_BT_HOST_WKUP_GPIO)); - qdev_connect_gpio_out(s->cpu->gpio, N8X0_BT_RESET_GPIO, + qdev_connect_gpio_out(s->mpu->gpio, N8X0_BT_RESET_GPIO, csrhci_pins_get(radio)[csrhci_pin_reset]); - qdev_connect_gpio_out(s->cpu->gpio, N8X0_BT_WKUP_GPIO, + qdev_connect_gpio_out(s->mpu->gpio, N8X0_BT_WKUP_GPIO, csrhci_pins_get(radio)[csrhci_pin_wakeup]); - omap_uart_attach(s->cpu->uart[BT_UART], radio); + omap_uart_attach(s->mpu->uart[BT_UART], radio); } static void n8x0_usb_setup(struct n800_s *s) @@ -774,13 +774,13 @@ static void n8x0_usb_setup(struct n800_s *s) dev = sysbus_from_qdev(s->usb); qdev_init_nofail(s->usb); sysbus_connect_irq(dev, 0, - qdev_get_gpio_in(s->cpu->gpio, N8X0_TUSB_INT_GPIO)); + qdev_get_gpio_in(s->mpu->gpio, N8X0_TUSB_INT_GPIO)); /* Using the NOR interface */ - omap_gpmc_attach(s->cpu->gpmc, N8X0_USB_ASYNC_CS, + omap_gpmc_attach(s->mpu->gpmc, N8X0_USB_ASYNC_CS, sysbus_mmio_get_region(dev, 0)); - omap_gpmc_attach(s->cpu->gpmc, N8X0_USB_SYNC_CS, + omap_gpmc_attach(s->mpu->gpmc, N8X0_USB_SYNC_CS, sysbus_mmio_get_region(dev, 1)); - qdev_connect_gpio_out(s->cpu->gpio, N8X0_TUSB_ENABLE_GPIO, + qdev_connect_gpio_out(s->mpu->gpio, N8X0_TUSB_ENABLE_GPIO, qdev_get_gpio_in(s->usb, 0)); /* tusb_pwr */ } @@ -1023,11 +1023,11 @@ static void n8x0_boot_init(void *opaque) n800_dss_init(&s->blizzard); /* CPU setup */ - s->cpu->cpu->env.GE = 0x5; + s->mpu->cpu->env.GE = 0x5; /* If the machine has a slided keyboard, open it */ if (s->kbd) - qemu_irq_raise(qdev_get_gpio_in(s->cpu->gpio, N810_SLIDE_GPIO)); + qemu_irq_raise(qdev_get_gpio_in(s->mpu->gpio, N810_SLIDE_GPIO)); } #define OMAP_TAG_NOKIA_BT 0x4e01 @@ -1281,7 +1281,7 @@ static void n8x0_init(ram_addr_t ram_size, const char *boot_device, int sdram_size = binfo->ram_size; DisplayState *ds; - s->cpu = omap2420_mpu_init(sysmem, sdram_size, cpu_model); + s->mpu = omap2420_mpu_init(sysmem, sdram_size, cpu_model); /* Setup peripherals * @@ -1329,7 +1329,7 @@ static void n8x0_init(ram_addr_t ram_size, const char *boot_device, binfo->kernel_filename = kernel_filename; binfo->kernel_cmdline = kernel_cmdline; binfo->initrd_filename = initrd_filename; - arm_load_kernel(&s->cpu->cpu->env, binfo); + arm_load_kernel(s->mpu->cpu, binfo); qemu_register_reset(n8x0_boot_init, s); } @@ -1338,7 +1338,7 @@ static void n8x0_init(ram_addr_t ram_size, const char *boot_device, int rom_size; uint8_t nolo_tags[0x10000]; /* No, wait, better start at the ROM. */ - s->cpu->cpu->env.regs[15] = OMAP2_Q2_BASE + 0x400000; + s->mpu->cpu->env.regs[15] = OMAP2_Q2_BASE + 0x400000; /* This is intended for loading the `secondary.bin' program from * Nokia images (the NOLO bootloader). The entry point seems @@ -3854,7 +3854,7 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory, omap_clkm_init(system_memory, 0xfffece00, 0xe1008000, s); - cpu_irq = arm_pic_init_cpu(&s->cpu->env); + cpu_irq = arm_pic_init_cpu(s->cpu); s->ih[0] = qdev_create(NULL, "omap-intc"); qdev_prop_set_uint32(s->ih[0], "size", 0x100); qdev_prop_set_ptr(s->ih[0], "clk", omap_findclk(s, "arminth_ck")); @@ -2277,7 +2277,7 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem, s->l4 = omap_l4_init(sysmem, OMAP2_L4_BASE, 54); /* Actually mapped at any 2K boundary in the ARM11 private-peripheral if */ - cpu_irq = arm_pic_init_cpu(&s->cpu->env); + cpu_irq = arm_pic_init_cpu(s->cpu); s->ih[0] = qdev_create(NULL, "omap2-intc"); qdev_prop_set_uint8(s->ih[0], "revision", 0x21); qdev_prop_set_ptr(s->ih[0], "fclk", omap_findclk(s, "mpu_intc_fclk")); diff --git a/hw/omap_sx1.c b/hw/omap_sx1.c index c7618c6..abca341 100644 --- a/hw/omap_sx1.c +++ b/hw/omap_sx1.c @@ -103,7 +103,7 @@ static void sx1_init(ram_addr_t ram_size, const char *initrd_filename, const char *cpu_model, const int version) { - struct omap_mpu_state_s *cpu; + struct omap_mpu_state_s *mpu; MemoryRegion *address_space = get_system_memory(); MemoryRegion *flash = g_new(MemoryRegion, 1); MemoryRegion *flash_1 = g_new(MemoryRegion, 1); @@ -121,7 +121,7 @@ static void sx1_init(ram_addr_t ram_size, flash_size = flash2_size; } - cpu = omap310_mpu_init(address_space, sx1_binfo.ram_size, cpu_model); + mpu = omap310_mpu_init(address_space, sx1_binfo.ram_size, cpu_model); /* External Flash (EMIFS) */ memory_region_init_ram(flash, "omap_sx1.flash0-0", flash_size); @@ -202,7 +202,7 @@ static void sx1_init(ram_addr_t ram_size, sx1_binfo.kernel_filename = kernel_filename; sx1_binfo.kernel_cmdline = kernel_cmdline; sx1_binfo.initrd_filename = initrd_filename; - arm_load_kernel(&cpu->cpu->env, &sx1_binfo); + arm_load_kernel(mpu->cpu, &sx1_binfo); } /* TODO: fix next line */ @@ -196,7 +196,7 @@ static void palmte_init(ram_addr_t ram_size, const char *initrd_filename, const char *cpu_model) { MemoryRegion *address_space_mem = get_system_memory(); - struct omap_mpu_state_s *cpu; + struct omap_mpu_state_s *mpu; int flash_size = 0x00800000; int sdram_size = palmte_binfo.ram_size; static uint32_t cs0val = 0xffffffff; @@ -208,7 +208,7 @@ static void palmte_init(ram_addr_t ram_size, MemoryRegion *flash = g_new(MemoryRegion, 1); MemoryRegion *cs = g_new(MemoryRegion, 4); - cpu = omap310_mpu_init(address_space_mem, sdram_size, cpu_model); + mpu = omap310_mpu_init(address_space_mem, sdram_size, cpu_model); /* External Flash (EMIFS) */ memory_region_init_ram(flash, "palmte.flash", flash_size); @@ -230,11 +230,11 @@ static void palmte_init(ram_addr_t ram_size, OMAP_CS3_SIZE); memory_region_add_subregion(address_space_mem, OMAP_CS3_BASE, &cs[3]); - palmte_microwire_setup(cpu); + palmte_microwire_setup(mpu); - qemu_add_kbd_event_handler(palmte_button_event, cpu); + qemu_add_kbd_event_handler(palmte_button_event, mpu); - palmte_gpio_setup(cpu); + palmte_gpio_setup(mpu); /* Setup initial (reset) machine state */ if (nb_option_roms) { @@ -265,7 +265,7 @@ static void palmte_init(ram_addr_t ram_size, palmte_binfo.kernel_filename = kernel_filename; palmte_binfo.kernel_cmdline = kernel_cmdline; palmte_binfo.initrd_filename = initrd_filename; - arm_load_kernel(&cpu->cpu->env, &palmte_binfo); + arm_load_kernel(mpu->cpu, &palmte_binfo); } /* FIXME: We shouldn't really be doing this here. The LCD controller @@ -1537,7 +1537,7 @@ PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction, DeviceState *dev; dev = qdev_create(&bus->qbus, name); - qdev_prop_set_uint32(dev, "addr", devfn); + qdev_prop_set_int32(dev, "addr", devfn); qdev_prop_set_bit(dev, "multifunction", multifunction); return PCI_DEVICE(dev); } @@ -197,7 +197,7 @@ struct PCIDevice { /* the following fields are read only */ PCIBus *bus; - uint32_t devfn; + int32_t devfn; char name[64]; PCIIORegion io_regions[PCI_NUM_REGIONS]; @@ -65,7 +65,7 @@ # define PXA2XX_INTERNAL_SIZE 0x40000 /* pxa2xx_pic.c */ -DeviceState *pxa2xx_pic_init(target_phys_addr_t base, CPUARMState *env); +DeviceState *pxa2xx_pic_init(target_phys_addr_t base, ARMCPU *cpu); /* pxa2xx_gpio.c */ DeviceState *pxa2xx_gpio_init(target_phys_addr_t base, diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 5f8f226..7958d14 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -2081,7 +2081,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE, &s->internal); - s->pic = pxa2xx_pic_init(0x40d00000, &s->cpu->env); + s->pic = pxa2xx_pic_init(0x40d00000, s->cpu); s->dma = pxa27x_dma_init(0x40000000, qdev_get_gpio_in(s->pic, PXA2XX_PIC_DMA)); @@ -2213,7 +2213,7 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE, &s->internal); - s->pic = pxa2xx_pic_init(0x40d00000, &s->cpu->env); + s->pic = pxa2xx_pic_init(0x40d00000, s->cpu); s->dma = pxa255_dma_init(0x40000000, qdev_get_gpio_in(s->pic, PXA2XX_PIC_DMA)); diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c index 09a408b..3c90c9c 100644 --- a/hw/pxa2xx_gpio.c +++ b/hw/pxa2xx_gpio.c @@ -20,7 +20,7 @@ struct PXA2xxGPIOInfo { qemu_irq irq0, irq1, irqX; int lines; int ncpu; - CPUARMState *cpu_env; + ARMCPU *cpu; /* XXX: GNU C vectors are more suitable */ uint32_t ilevel[PXA2XX_GPIO_BANKS]; @@ -118,8 +118,9 @@ static void pxa2xx_gpio_set(void *opaque, int line, int level) pxa2xx_gpio_irq_update(s); /* Wake-up GPIOs */ - if (s->cpu_env->halted && (mask & ~s->dir[bank] & pxa2xx_gpio_wake[bank])) - cpu_interrupt(s->cpu_env, CPU_INTERRUPT_EXITTB); + if (s->cpu->env.halted && (mask & ~s->dir[bank] & pxa2xx_gpio_wake[bank])) { + cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_EXITTB); + } } static void pxa2xx_gpio_handler_update(PXA2xxGPIOInfo *s) { @@ -275,7 +276,7 @@ static int pxa2xx_gpio_initfn(SysBusDevice *dev) s = FROM_SYSBUS(PXA2xxGPIOInfo, dev); - s->cpu_env = qemu_get_cpu(s->ncpu); + s->cpu = arm_env_get_cpu(qemu_get_cpu(s->ncpu)); qdev_init_gpio_in(&dev->qdev, pxa2xx_gpio_set, s->lines); qdev_init_gpio_out(&dev->qdev, s->handler, s->lines); diff --git a/hw/pxa2xx_pic.c b/hw/pxa2xx_pic.c index a806b80..c560133 100644 --- a/hw/pxa2xx_pic.c +++ b/hw/pxa2xx_pic.c @@ -34,7 +34,7 @@ typedef struct { SysBusDevice busdev; MemoryRegion iomem; - CPUARMState *cpu_env; + ARMCPU *cpu; uint32_t int_enabled[2]; uint32_t int_pending[2]; uint32_t is_fiq[2]; @@ -47,25 +47,28 @@ static void pxa2xx_pic_update(void *opaque) uint32_t mask[2]; PXA2xxPICState *s = (PXA2xxPICState *) opaque; - if (s->cpu_env->halted) { + if (s->cpu->env.halted) { mask[0] = s->int_pending[0] & (s->int_enabled[0] | s->int_idle); mask[1] = s->int_pending[1] & (s->int_enabled[1] | s->int_idle); - if (mask[0] || mask[1]) - cpu_interrupt(s->cpu_env, CPU_INTERRUPT_EXITTB); + if (mask[0] || mask[1]) { + cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_EXITTB); + } } mask[0] = s->int_pending[0] & s->int_enabled[0]; mask[1] = s->int_pending[1] & s->int_enabled[1]; - if ((mask[0] & s->is_fiq[0]) || (mask[1] & s->is_fiq[1])) - cpu_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ); - else - cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ); + if ((mask[0] & s->is_fiq[0]) || (mask[1] & s->is_fiq[1])) { + cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_FIQ); + } else { + cpu_reset_interrupt(&s->cpu->env, CPU_INTERRUPT_FIQ); + } - if ((mask[0] & ~s->is_fiq[0]) || (mask[1] & ~s->is_fiq[1])) - cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); - else - cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); + if ((mask[0] & ~s->is_fiq[0]) || (mask[1] & ~s->is_fiq[1])) { + cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(&s->cpu->env, CPU_INTERRUPT_HARD); + } } /* Note: Here level means state of the signal on a pin, not @@ -245,12 +248,13 @@ static int pxa2xx_pic_post_load(void *opaque, int version_id) return 0; } -DeviceState *pxa2xx_pic_init(target_phys_addr_t base, CPUARMState *env) +DeviceState *pxa2xx_pic_init(target_phys_addr_t base, ARMCPU *cpu) { + CPUARMState *env = &cpu->env; DeviceState *dev = qdev_create(NULL, "pxa2xx_pic"); PXA2xxPICState *s = FROM_SYSBUS(PXA2xxPICState, sysbus_from_qdev(dev)); - s->cpu_env = env; + s->cpu = cpu; s->int_pending[0] = 0; s->int_pending[1] = 0; diff --git a/hw/qdev-addr.c b/hw/qdev-addr.c index 0bb16c7..b711b6b 100644 --- a/hw/qdev-addr.c +++ b/hw/qdev-addr.c @@ -27,7 +27,7 @@ static void get_taddr(Object *obj, Visitor *v, void *opaque, int64_t value; value = *ptr; - visit_type_int(v, &value, name, errp); + visit_type_int64(v, &value, name, errp); } static void set_taddr(Object *obj, Visitor *v, void *opaque, @@ -44,7 +44,7 @@ static void set_taddr(Object *obj, Visitor *v, void *opaque, return; } - visit_type_int(v, &value, name, &local_err); + visit_type_int64(v, &value, name, &local_err); if (local_err) { error_propagate(errp, local_err); return; diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index b7b5597..9ae3187 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -76,52 +76,35 @@ PropertyInfo qdev_prop_bit = { /* --- 8bit integer --- */ -static void get_int8(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) +static void get_uint8(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { DeviceState *dev = DEVICE(obj); Property *prop = opaque; - int8_t *ptr = qdev_get_prop_ptr(dev, prop); - int64_t value; + uint8_t *ptr = qdev_get_prop_ptr(dev, prop); - value = *ptr; - visit_type_int(v, &value, name, errp); + visit_type_uint8(v, ptr, name, errp); } -static void set_int8(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) +static void set_uint8(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { DeviceState *dev = DEVICE(obj); Property *prop = opaque; - int8_t *ptr = qdev_get_prop_ptr(dev, prop); - Error *local_err = NULL; - int64_t value; + uint8_t *ptr = qdev_get_prop_ptr(dev, prop); if (dev->state != DEV_STATE_CREATED) { error_set(errp, QERR_PERMISSION_DENIED); return; } - visit_type_int(v, &value, name, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - if (value >= prop->info->min && value <= prop->info->max) { - *ptr = value; - } else { - error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, - dev->id?:"", name, value, prop->info->min, - prop->info->max); - } + visit_type_uint8(v, ptr, name, errp); } PropertyInfo qdev_prop_uint8 = { .name = "uint8", - .get = get_int8, - .set = set_int8, - .min = 0, - .max = 255, + .get = get_uint8, + .set = set_uint8, }; /* --- 8bit hex value --- */ @@ -154,74 +137,78 @@ PropertyInfo qdev_prop_hex8 = { .legacy_name = "hex8", .parse = parse_hex8, .print = print_hex8, - .get = get_int8, - .set = set_int8, - .min = 0, - .max = 255, + .get = get_uint8, + .set = set_uint8, }; /* --- 16bit integer --- */ -static void get_int16(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) +static void get_uint16(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { DeviceState *dev = DEVICE(obj); Property *prop = opaque; - int16_t *ptr = qdev_get_prop_ptr(dev, prop); - int64_t value; + uint16_t *ptr = qdev_get_prop_ptr(dev, prop); - value = *ptr; - visit_type_int(v, &value, name, errp); + visit_type_uint16(v, ptr, name, errp); } -static void set_int16(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) +static void set_uint16(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { DeviceState *dev = DEVICE(obj); Property *prop = opaque; - int16_t *ptr = qdev_get_prop_ptr(dev, prop); - Error *local_err = NULL; - int64_t value; + uint16_t *ptr = qdev_get_prop_ptr(dev, prop); if (dev->state != DEV_STATE_CREATED) { error_set(errp, QERR_PERMISSION_DENIED); return; } - visit_type_int(v, &value, name, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - if (value >= prop->info->min && value <= prop->info->max) { - *ptr = value; - } else { - error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, - dev->id?:"", name, value, prop->info->min, - prop->info->max); - } + visit_type_uint16(v, ptr, name, errp); } PropertyInfo qdev_prop_uint16 = { .name = "uint16", - .get = get_int16, - .set = set_int16, - .min = 0, - .max = 65535, + .get = get_uint16, + .set = set_uint16, }; /* --- 32bit integer --- */ +static void get_uint32(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + uint32_t *ptr = qdev_get_prop_ptr(dev, prop); + + visit_type_uint32(v, ptr, name, errp); +} + +static void set_uint32(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + uint32_t *ptr = qdev_get_prop_ptr(dev, prop); + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_uint32(v, ptr, name, errp); +} + static void get_int32(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { DeviceState *dev = DEVICE(obj); Property *prop = opaque; int32_t *ptr = qdev_get_prop_ptr(dev, prop); - int64_t value; - value = *ptr; - visit_type_int(v, &value, name, errp); + visit_type_int32(v, ptr, name, errp); } static void set_int32(Object *obj, Visitor *v, void *opaque, @@ -230,42 +217,25 @@ static void set_int32(Object *obj, Visitor *v, void *opaque, DeviceState *dev = DEVICE(obj); Property *prop = opaque; int32_t *ptr = qdev_get_prop_ptr(dev, prop); - Error *local_err = NULL; - int64_t value; if (dev->state != DEV_STATE_CREATED) { error_set(errp, QERR_PERMISSION_DENIED); return; } - visit_type_int(v, &value, name, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - if (value >= prop->info->min && value <= prop->info->max) { - *ptr = value; - } else { - error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, - dev->id?:"", name, value, prop->info->min, - prop->info->max); - } + visit_type_int32(v, ptr, name, errp); } PropertyInfo qdev_prop_uint32 = { .name = "uint32", - .get = get_int32, - .set = set_int32, - .min = 0, - .max = 0xFFFFFFFFULL, + .get = get_uint32, + .set = set_uint32, }; PropertyInfo qdev_prop_int32 = { .name = "int32", .get = get_int32, .set = set_int32, - .min = -0x80000000LL, - .max = 0x7FFFFFFFLL, }; /* --- 32bit hex value --- */ @@ -298,43 +268,41 @@ PropertyInfo qdev_prop_hex32 = { .legacy_name = "hex32", .parse = parse_hex32, .print = print_hex32, - .get = get_int32, - .set = set_int32, - .min = 0, - .max = 0xFFFFFFFFULL, + .get = get_uint32, + .set = set_uint32, }; /* --- 64bit integer --- */ -static void get_int64(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) +static void get_uint64(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { DeviceState *dev = DEVICE(obj); Property *prop = opaque; - int64_t *ptr = qdev_get_prop_ptr(dev, prop); + uint64_t *ptr = qdev_get_prop_ptr(dev, prop); - visit_type_int(v, ptr, name, errp); + visit_type_uint64(v, ptr, name, errp); } -static void set_int64(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) +static void set_uint64(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { DeviceState *dev = DEVICE(obj); Property *prop = opaque; - int64_t *ptr = qdev_get_prop_ptr(dev, prop); + uint64_t *ptr = qdev_get_prop_ptr(dev, prop); if (dev->state != DEV_STATE_CREATED) { error_set(errp, QERR_PERMISSION_DENIED); return; } - visit_type_int(v, ptr, name, errp); + visit_type_uint64(v, ptr, name, errp); } PropertyInfo qdev_prop_uint64 = { .name = "uint64", - .get = get_int64, - .set = set_int64, + .get = get_uint64, + .set = set_uint64, }; /* --- 64bit hex value --- */ @@ -367,8 +335,8 @@ PropertyInfo qdev_prop_hex64 = { .legacy_name = "hex64", .parse = parse_hex64, .print = print_hex64, - .get = get_int64, - .set = set_int64, + .get = get_uint64, + .set = set_uint64, }; /* --- string --- */ @@ -645,7 +613,7 @@ static void get_vlan(Object *obj, Visitor *v, void *opaque, int64_t id; id = *ptr ? (*ptr)->id : -1; - visit_type_int(v, &id, name, errp); + visit_type_int64(v, &id, name, errp); } static void set_vlan(Object *obj, Visitor *v, void *opaque, @@ -663,7 +631,7 @@ static void set_vlan(Object *obj, Visitor *v, void *opaque, return; } - visit_type_int(v, &id, name, &local_err); + visit_type_int64(v, &id, name, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -824,7 +792,7 @@ static void set_pci_devfn(Object *obj, Visitor *v, void *opaque, { DeviceState *dev = DEVICE(obj); Property *prop = opaque; - uint32_t *ptr = qdev_get_prop_ptr(dev, prop); + int32_t value, *ptr = qdev_get_prop_ptr(dev, prop); unsigned int slot, fn, n; Error *local_err = NULL; char *str; @@ -837,7 +805,17 @@ static void set_pci_devfn(Object *obj, Visitor *v, void *opaque, visit_type_str(v, &str, name, &local_err); if (local_err) { error_free(local_err); - return set_int32(obj, v, opaque, name, errp); + local_err = NULL; + visit_type_int32(v, &value, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); + } else if (value < -1 || value > 255) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", + "pci_devfn"); + } else { + *ptr = value; + } + return; } if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) { @@ -860,7 +838,7 @@ invalid: static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t len) { - uint32_t *ptr = qdev_get_prop_ptr(dev, prop); + int32_t *ptr = qdev_get_prop_ptr(dev, prop); if (*ptr == -1) { return snprintf(dest, len, "<unset>"); @@ -875,11 +853,6 @@ PropertyInfo qdev_prop_pci_devfn = { .print = print_pci_devfn, .get = get_int32, .set = set_pci_devfn, - /* FIXME: this should be -1...255, but the address is stored - * into an uint32_t rather than int32_t. - */ - .min = 0, - .max = 0xFFFFFFFFULL, }; /* --- blocksize --- */ @@ -889,31 +862,31 @@ static void set_blocksize(Object *obj, Visitor *v, void *opaque, { DeviceState *dev = DEVICE(obj); Property *prop = opaque; - int16_t *ptr = qdev_get_prop_ptr(dev, prop); + uint16_t value, *ptr = qdev_get_prop_ptr(dev, prop); Error *local_err = NULL; - int64_t value; + const int64_t min = 512; + const int64_t max = 32768; if (dev->state != DEV_STATE_CREATED) { error_set(errp, QERR_PERMISSION_DENIED); return; } - visit_type_int(v, &value, name, &local_err); + visit_type_uint16(v, &value, name, &local_err); if (local_err) { error_propagate(errp, local_err); return; } - if (value < prop->info->min || value > prop->info->max) { + if (value < min || value > max) { error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, - dev->id?:"", name, value, prop->info->min, - prop->info->max); + dev->id?:"", name, (int64_t)value, min, max); return; } /* We rely on power-of-2 blocksizes for bitmasks */ if ((value & (value - 1)) != 0) { error_set(errp, QERR_PROPERTY_VALUE_NOT_POWER_OF_2, - dev->id?:"", name, value); + dev->id?:"", name, (int64_t)value); return; } @@ -922,10 +895,8 @@ static void set_blocksize(Object *obj, Visitor *v, void *opaque, PropertyInfo qdev_prop_blocksize = { .name = "blocksize", - .get = get_int16, + .get = get_uint16, .set = set_blocksize, - .min = 512, - .max = 65024, }; /* --- public helpers --- */ @@ -122,8 +122,6 @@ struct PropertyInfo { const char *name; const char *legacy_name; const char **enum_table; - int64_t min; - int64_t max; int (*parse)(DeviceState *dev, Property *prop, const char *str); int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len); ObjectPropertyAccessor *get; @@ -267,7 +265,7 @@ extern PropertyInfo qdev_prop_blocksize; #define DEFINE_PROP_HEX64(_n, _s, _f, _d) \ DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex64, uint64_t) #define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d) \ - DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_pci_devfn, uint32_t) + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_pci_devfn, int32_t) #define DEFINE_PROP_PTR(_n, _s, _f) \ DEFINE_PROP(_n, _s, _f, qdev_prop_ptr, void*) diff --git a/hw/realview.c b/hw/realview.c index ecf4701..19db4d0 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -50,7 +50,8 @@ static void realview_init(ram_addr_t ram_size, const char *initrd_filename, const char *cpu_model, enum realview_board_type board_type) { - CPUARMState *env = NULL; + ARMCPU *cpu = NULL; + CPUARMState *env; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram_lo = g_new(MemoryRegion, 1); MemoryRegion *ram_hi = g_new(MemoryRegion, 1); @@ -88,14 +89,15 @@ static void realview_init(ram_addr_t ram_size, break; } for (n = 0; n < smp_cpus; n++) { - env = cpu_init(cpu_model); - if (!env) { + cpu = cpu_arm_init(cpu_model); + if (!cpu) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - irqp = arm_pic_init_cpu(env); + irqp = arm_pic_init_cpu(cpu); cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; } + env = &cpu->env; if (arm_feature(env, ARM_FEATURE_V7)) { if (is_mpcore) { proc_id = 0x0c000000; @@ -325,7 +327,7 @@ static void realview_init(ram_addr_t ram_size, realview_binfo.nb_cpus = smp_cpus; realview_binfo.board_id = realview_board_id[board_type]; realview_binfo.loader_start = (board_type == BOARD_PB_A8 ? 0x70000000 : 0); - arm_load_kernel(first_cpu, &realview_binfo); + arm_load_kernel(arm_env_get_cpu(first_cpu), &realview_binfo); } static void realview_eb_init(ram_addr_t ram_size, diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index 1d38a8f..23ef35b 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -140,7 +140,8 @@ static int s390_virtio_device_init(VirtIOS390Device *dev, VirtIODevice *vdev) s390_virtio_device_sync(dev); s390_virtio_reset_idx(dev); if (dev->qdev.hotplugged) { - CPUS390XState *env = s390_cpu_addr2state(0); + S390CPU *cpu = s390_cpu_addr2state(0); + CPUS390XState *env = &cpu->env; s390_virtio_irq(env, VIRTIO_PARAM_DEV_ADD, dev->dev_offs); } @@ -354,7 +355,8 @@ static void virtio_s390_notify(void *opaque, uint16_t vector) { VirtIOS390Device *dev = (VirtIOS390Device*)opaque; uint64_t token = s390_virtio_device_vq_token(dev, vector); - CPUS390XState *env = s390_cpu_addr2state(0); + S390CPU *cpu = s390_cpu_addr2state(0); + CPUS390XState *env = &cpu->env; s390_virtio_irq(env, 0, token); } diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c index c0e19fd..47eed35 100644 --- a/hw/s390-virtio.c +++ b/hw/s390-virtio.c @@ -61,9 +61,9 @@ #define MAX_BLK_DEVS 10 static VirtIOS390Bus *s390_bus; -static CPUS390XState **ipi_states; +static S390CPU **ipi_states; -CPUS390XState *s390_cpu_addr2state(uint16_t cpu_addr) +S390CPU *s390_cpu_addr2state(uint16_t cpu_addr) { if (cpu_addr >= smp_cpus) { return NULL; @@ -206,16 +206,18 @@ static void s390_init(ram_addr_t my_ram_size, cpu_model = "host"; } - ipi_states = g_malloc(sizeof(CPUS390XState *) * smp_cpus); + ipi_states = g_malloc(sizeof(S390CPU *) * smp_cpus); for (i = 0; i < smp_cpus; i++) { + S390CPU *cpu; CPUS390XState *tmp_env; - tmp_env = cpu_init(cpu_model); + cpu = cpu_s390x_init(cpu_model); + tmp_env = &cpu->env; if (!env) { env = tmp_env; } - ipi_states[i] = tmp_env; + ipi_states[i] = cpu; tmp_env->halted = 1; tmp_env->exception_index = EXCP_HLT; tmp_env->storage_keys = storage_keys; diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index f10f3ec..4a79821 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -1507,10 +1507,9 @@ static void put_scsi_requests(QEMUFile *f, void *pv, size_t size) QTAILQ_FOREACH(req, &s->requests, next) { assert(!req->io_canceled); assert(req->status == -1); - assert(req->retry); assert(req->enqueued); - qemu_put_sbyte(f, 1); + qemu_put_sbyte(f, req->retry ? 1 : 2); qemu_put_buffer(f, req->cmd.buf, sizeof(req->cmd.buf)); qemu_put_be32s(f, &req->tag); qemu_put_be32s(f, &req->lun); @@ -1528,8 +1527,9 @@ static int get_scsi_requests(QEMUFile *f, void *pv, size_t size) { SCSIDevice *s = pv; SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, s->qdev.parent_bus); + int8_t sbyte; - while (qemu_get_sbyte(f)) { + while ((sbyte = qemu_get_sbyte(f)) > 0) { uint8_t buf[SCSI_CMD_BUF_SIZE]; uint32_t tag; uint32_t lun; @@ -1539,6 +1539,7 @@ static int get_scsi_requests(QEMUFile *f, void *pv, size_t size) qemu_get_be32s(f, &tag); qemu_get_be32s(f, &lun); req = scsi_req_new(s, tag, lun, buf, NULL); + req->retry = (sbyte == 1); if (bus->info->load_request) { req->hba_private = bus->info->load_request(f, req); } @@ -1547,7 +1548,6 @@ static int get_scsi_requests(QEMUFile *f, void *pv, size_t size) } /* Just restart it later. */ - req->retry = true; scsi_req_enqueue_internal(req); /* At this point, the request will be kept alive by the reference diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 045c764..1691491 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -132,8 +132,14 @@ static void scsi_disk_save_request(QEMUFile *f, SCSIRequest *req) qemu_put_be64s(f, &r->sector); qemu_put_be32s(f, &r->sector_count); qemu_put_be32s(f, &r->buflen); - if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) { - qemu_put_buffer(f, r->iov.iov_base, r->iov.iov_len); + if (r->buflen) { + if (r->req.cmd.mode == SCSI_XFER_TO_DEV) { + qemu_put_buffer(f, r->iov.iov_base, r->iov.iov_len); + } else if (!req->retry) { + uint32_t len = r->iov.iov_len; + qemu_put_be32s(f, &len); + qemu_put_buffer(f, r->iov.iov_base, r->iov.iov_len); + } } } @@ -148,6 +154,12 @@ static void scsi_disk_load_request(QEMUFile *f, SCSIRequest *req) scsi_init_iovec(r, r->buflen); if (r->req.cmd.mode == SCSI_XFER_TO_DEV) { qemu_get_buffer(f, r->iov.iov_base, r->iov.iov_len); + } else if (!r->req.retry) { + uint32_t len; + qemu_get_be32s(f, &len); + r->iov.iov_len = len; + assert(r->iov.iov_len <= r->buflen); + qemu_get_buffer(f, r->iov.iov_base, r->iov.iov_len); } } @@ -884,7 +884,7 @@ static void spitz_common_init(ram_addr_t ram_size, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model, enum spitz_model_e model, int arm_id) { - PXA2xxState *cpu; + PXA2xxState *mpu; DeviceState *scp0, *scp1 = NULL; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *rom = g_new(MemoryRegion, 1); @@ -893,9 +893,9 @@ static void spitz_common_init(ram_addr_t ram_size, cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0"; /* Setup CPU & memory */ - cpu = pxa270_init(address_space_mem, spitz_binfo.ram_size, cpu_model); + mpu = pxa270_init(address_space_mem, spitz_binfo.ram_size, cpu_model); - sl_flash_register(cpu, (model == spitz) ? FLASH_128M : FLASH_1024M); + sl_flash_register(mpu, (model == spitz) ? FLASH_128M : FLASH_1024M); memory_region_init_ram(rom, "spitz.rom", SPITZ_ROM); vmstate_register_ram_global(rom); @@ -903,36 +903,36 @@ static void spitz_common_init(ram_addr_t ram_size, memory_region_add_subregion(address_space_mem, 0, rom); /* Setup peripherals */ - spitz_keyboard_register(cpu); + spitz_keyboard_register(mpu); - spitz_ssp_attach(cpu); + spitz_ssp_attach(mpu); scp0 = sysbus_create_simple("scoop", 0x10800000, NULL); if (model != akita) { scp1 = sysbus_create_simple("scoop", 0x08800040, NULL); } - spitz_scoop_gpio_setup(cpu, scp0, scp1); + spitz_scoop_gpio_setup(mpu, scp0, scp1); - spitz_gpio_setup(cpu, (model == akita) ? 1 : 2); + spitz_gpio_setup(mpu, (model == akita) ? 1 : 2); - spitz_i2c_setup(cpu); + spitz_i2c_setup(mpu); if (model == akita) - spitz_akita_i2c_setup(cpu); + spitz_akita_i2c_setup(mpu); if (model == terrier) /* A 6.0 GB microdrive is permanently sitting in CF slot 1. */ - spitz_microdrive_attach(cpu, 1); + spitz_microdrive_attach(mpu, 1); else if (model != akita) /* A 4.0 GB microdrive is permanently sitting in CF slot 0. */ - spitz_microdrive_attach(cpu, 0); + spitz_microdrive_attach(mpu, 0); spitz_binfo.kernel_filename = kernel_filename; spitz_binfo.kernel_cmdline = kernel_cmdline; spitz_binfo.initrd_filename = initrd_filename; spitz_binfo.board_id = arm_id; - arm_load_kernel(&cpu->cpu->env, &spitz_binfo); + arm_load_kernel(mpu->cpu, &spitz_binfo); sl_bootparam_write(SL_PXA_PARAM_BASE); } diff --git a/hw/strongarm.c b/hw/strongarm.c index 1b15f39..7150eeb 100644 --- a/hw/strongarm.c +++ b/hw/strongarm.c @@ -1563,9 +1563,9 @@ StrongARMState *sa1110_init(MemoryRegion *sysmem, exit(1); } - s->env = cpu_init(rev); + s->cpu = cpu_arm_init(rev); - if (!s->env) { + if (!s->cpu) { error_report("Unable to find CPU definition"); exit(1); } @@ -1574,7 +1574,7 @@ StrongARMState *sa1110_init(MemoryRegion *sysmem, vmstate_register_ram_global(&s->sdram); memory_region_add_subregion(sysmem, SA_SDCS0, &s->sdram); - pic = arm_pic_init_cpu(s->env); + pic = arm_pic_init_cpu(s->cpu); s->pic = sysbus_create_varargs("strongarm_pic", 0x90050000, pic[ARM_PIC_CPU_IRQ], pic[ARM_PIC_CPU_FIQ], NULL); diff --git a/hw/strongarm.h b/hw/strongarm.h index 02acac3..d30dd6a 100644 --- a/hw/strongarm.h +++ b/hw/strongarm.h @@ -53,7 +53,7 @@ enum { }; typedef struct { - CPUARMState *env; + ARMCPU *cpu; MemoryRegion sdram; DeviceState *pic; DeviceState *gpio; @@ -212,14 +212,14 @@ static void tosa_init(ram_addr_t ram_size, { MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *rom = g_new(MemoryRegion, 1); - PXA2xxState *cpu; + PXA2xxState *mpu; TC6393xbState *tmio; DeviceState *scp0, *scp1; if (!cpu_model) cpu_model = "pxa255"; - cpu = pxa255_init(address_space_mem, tosa_binfo.ram_size); + mpu = pxa255_init(address_space_mem, tosa_binfo.ram_size); memory_region_init_ram(rom, "tosa.rom", TOSA_ROM); vmstate_register_ram_global(rom); @@ -227,22 +227,22 @@ static void tosa_init(ram_addr_t ram_size, memory_region_add_subregion(address_space_mem, 0, rom); tmio = tc6393xb_init(address_space_mem, 0x10000000, - qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_TC6393XB_INT)); + qdev_get_gpio_in(mpu->gpio, TOSA_GPIO_TC6393XB_INT)); scp0 = sysbus_create_simple("scoop", 0x08800000, NULL); scp1 = sysbus_create_simple("scoop", 0x14800040, NULL); - tosa_gpio_setup(cpu, scp0, scp1, tmio); + tosa_gpio_setup(mpu, scp0, scp1, tmio); - tosa_microdrive_attach(cpu); + tosa_microdrive_attach(mpu); - tosa_tg_init(cpu); + tosa_tg_init(mpu); tosa_binfo.kernel_filename = kernel_filename; tosa_binfo.kernel_cmdline = kernel_cmdline; tosa_binfo.initrd_filename = initrd_filename; tosa_binfo.board_id = 0x208; - arm_load_kernel(&cpu->cpu->env, &tosa_binfo); + arm_load_kernel(mpu->cpu, &tosa_binfo); sl_bootparam_write(SL_PXA_PARAM_BASE); } diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index a96c0b9..097d7b4 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -48,10 +48,9 @@ struct usb_msd_csw { typedef struct { USBDevice dev; enum USBMSDMode mode; + uint32_t scsi_off; uint32_t scsi_len; - uint8_t *scsi_buf; uint32_t data_len; - uint32_t residue; struct usb_msd_csw csw; SCSIRequest *req; SCSIBus bus; @@ -179,9 +178,9 @@ static void usb_msd_copy_data(MSDState *s, USBPacket *p) len = p->iov.size - p->result; if (len > s->scsi_len) len = s->scsi_len; - usb_packet_copy(p, s->scsi_buf, len); + usb_packet_copy(p, scsi_req_get_buf(s->req) + s->scsi_off, len); s->scsi_len -= len; - s->scsi_buf += len; + s->scsi_off += len; s->data_len -= len; if (s->scsi_len == 0 || s->data_len == 0) { scsi_req_continue(s->req); @@ -201,6 +200,18 @@ static void usb_msd_send_status(MSDState *s, USBPacket *p) memset(&s->csw, 0, sizeof(s->csw)); } +static void usb_msd_packet_complete(MSDState *s) +{ + USBPacket *p = s->packet; + + /* Set s->packet to NULL before calling usb_packet_complete + because another request may be issued before + usb_packet_complete returns. */ + DPRINTF("Packet complete %p\n", p); + s->packet = NULL; + usb_packet_complete(&s->dev, p); +} + static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len) { MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent); @@ -208,17 +219,12 @@ static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len) assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV)); s->scsi_len = len; - s->scsi_buf = scsi_req_get_buf(req); + s->scsi_off = 0; if (p) { usb_msd_copy_data(s, p); p = s->packet; if (p && p->result == p->iov.size) { - /* Set s->packet to NULL before calling usb_packet_complete - because another request may be issued before - usb_packet_complete returns. */ - DPRINTF("Packet complete %p\n", p); - s->packet = NULL; - usb_packet_complete(&s->dev, p); + usb_msd_packet_complete(s); } } } @@ -229,11 +235,10 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, size_t r USBPacket *p = s->packet; DPRINTF("Command complete %d tag 0x%x\n", status, req->tag); - s->residue = s->data_len; s->csw.sig = cpu_to_le32(0x53425355); s->csw.tag = cpu_to_le32(req->tag); - s->csw.residue = cpu_to_le32(s->residue); + s->csw.residue = cpu_to_le32(s->data_len); s->csw.status = status != 0; if (s->packet) { @@ -252,8 +257,7 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, size_t r s->mode = USB_MSDM_CSW; } } - s->packet = NULL; - usb_packet_complete(&s->dev, p); + usb_msd_packet_complete(s); } else if (s->data_len == 0) { s->mode = USB_MSDM_CSW; } @@ -283,10 +287,8 @@ static void usb_msd_handle_reset(USBDevice *dev) assert(s->req == NULL); if (s->packet) { - USBPacket *p = s->packet; - s->packet = NULL; - p->result = USB_RET_STALL; - usb_packet_complete(dev, p); + s->packet->result = USB_RET_STALL; + usb_msd_packet_complete(s); } s->mode = USB_MSDM_CBW; @@ -378,7 +380,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) } DPRINTF("Command tag 0x%x flags %08x len %d data %d\n", tag, cbw.flags, cbw.cmd_len, s->data_len); - s->residue = 0; + assert(le32_to_cpu(s->csw.residue) == 0); s->scsi_len = 0; s->req = scsi_req_new(s->scsi_dev, tag, 0, cbw.cmd, NULL); scsi_req_enqueue(s->req); @@ -397,7 +399,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) if (s->scsi_len) { usb_msd_copy_data(s, p); } - if (s->residue) { + if (le32_to_cpu(s->csw.residue)) { int len = p->iov.size - p->result; if (len) { usb_packet_skip(p, len); @@ -458,7 +460,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) if (s->scsi_len) { usb_msd_copy_data(s, p); } - if (s->residue) { + if (le32_to_cpu(s->csw.residue)) { int len = p->iov.size - p->result; if (len) { usb_packet_skip(p, len); @@ -504,6 +506,17 @@ static void usb_msd_password_cb(void *opaque, int err) qdev_unplug(&s->dev.qdev, NULL); } +static void *usb_msd_load_request(QEMUFile *f, SCSIRequest *req) +{ + MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent); + + /* nothing to load, just store req in our state struct */ + assert(s->req == NULL); + scsi_req_ref(req); + s->req = req; + return NULL; +} + static const struct SCSIBusInfo usb_msd_scsi_info = { .tcq = false, .max_target = 0, @@ -511,7 +524,8 @@ static const struct SCSIBusInfo usb_msd_scsi_info = { .transfer_data = usb_msd_transfer_data, .complete = usb_msd_command_complete, - .cancel = usb_msd_request_cancelled + .cancel = usb_msd_request_cancelled, + .load_request = usb_msd_load_request, }; static int usb_msd_initfn(USBDevice *dev) @@ -631,11 +645,18 @@ static USBDevice *usb_msd_init(USBBus *bus, const char *filename) static const VMStateDescription vmstate_usb_msd = { .name = "usb-storage", - .unmigratable = 1, /* FIXME: handle transactions which are in flight */ .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField []) { VMSTATE_USB_DEVICE(dev, MSDState), + VMSTATE_UINT32(mode, MSDState), + VMSTATE_UINT32(scsi_len, MSDState), + VMSTATE_UINT32(scsi_off, MSDState), + VMSTATE_UINT32(data_len, MSDState), + VMSTATE_UINT32(csw.sig, MSDState), + VMSTATE_UINT32(csw.tag, MSDState), + VMSTATE_UINT32(csw.residue, MSDState), + VMSTATE_UINT8(csw.status, MSDState), VMSTATE_END_OF_LIST() } }; diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index e759c99..5298204 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -334,6 +334,7 @@ typedef struct EHCIfstn { uint32_t backptr; // Standard next link pointer } EHCIfstn; +typedef struct EHCIPacket EHCIPacket; typedef struct EHCIQueue EHCIQueue; typedef struct EHCIState EHCIState; @@ -343,26 +344,36 @@ enum async_state { EHCI_ASYNC_FINISHED, }; +struct EHCIPacket { + EHCIQueue *queue; + QTAILQ_ENTRY(EHCIPacket) next; + + EHCIqtd qtd; /* copy of current QTD (being worked on) */ + uint32_t qtdaddr; /* address QTD read from */ + + USBPacket packet; + QEMUSGList sgl; + int pid; + uint32_t tbytes; + enum async_state async; + int usb_status; +}; + struct EHCIQueue { EHCIState *ehci; QTAILQ_ENTRY(EHCIQueue) next; uint32_t seen; uint64_t ts; + int async; /* cached data from guest - needs to be flushed * when guest removes an entry (doorbell, handshake sequence) */ - EHCIqh qh; // copy of current QH (being worked on) - uint32_t qhaddr; // address QH read from - EHCIqtd qtd; // copy of current QTD (being worked on) - uint32_t qtdaddr; // address QTD read from - - USBPacket packet; - QEMUSGList sgl; - int pid; - uint32_t tbytes; - enum async_state async; - int usb_status; + EHCIqh qh; /* copy of current QH (being worked on) */ + uint32_t qhaddr; /* address QH read from */ + uint32_t qtdaddr; /* address QTD read from */ + USBDevice *dev; + QTAILQ_HEAD(, EHCIPacket) packets; }; typedef QTAILQ_HEAD(EHCIQueueHead, EHCIQueue) EHCIQueueHead; @@ -375,7 +386,6 @@ struct EHCIState { int companion_count; /* properties */ - uint32_t freq; uint32_t maxframes; /* @@ -403,7 +413,7 @@ struct EHCIState { * Internal states, shadow registers, etc */ QEMUTimer *frame_timer; - int attach_poll_counter; + QEMUBH *async_bh; int astate; // Current state in asynchronous schedule int pstate; // Current state in periodic schedule USBPort ports[NB_PORTS]; @@ -419,6 +429,7 @@ struct EHCIState { QEMUSGList isgl; uint64_t last_run_ns; + uint32_t async_stepdown; }; #define SET_LAST_RUN_CLOCK(s) \ @@ -574,14 +585,37 @@ static inline void ehci_commit_interrupt(EHCIState *s) s->usbsts_pending = 0; } +static void ehci_update_halt(EHCIState *s) +{ + if (s->usbcmd & USBCMD_RUNSTOP) { + ehci_clear_usbsts(s, USBSTS_HALT); + } else { + if (s->astate == EST_INACTIVE && s->pstate == EST_INACTIVE) { + ehci_set_usbsts(s, USBSTS_HALT); + } + } +} + static void ehci_set_state(EHCIState *s, int async, int state) { if (async) { trace_usb_ehci_state("async", state2str(state)); s->astate = state; + if (s->astate == EST_INACTIVE) { + ehci_clear_usbsts(s, USBSTS_ASS); + ehci_update_halt(s); + } else { + ehci_set_usbsts(s, USBSTS_ASS); + } } else { trace_usb_ehci_state("periodic", state2str(state)); s->pstate = state; + if (s->pstate == EST_INACTIVE) { + ehci_clear_usbsts(s, USBSTS_PSS); + ehci_update_halt(s); + } else { + ehci_set_usbsts(s, USBSTS_PSS); + } } } @@ -655,27 +689,71 @@ static void ehci_trace_sitd(EHCIState *s, target_phys_addr_t addr, (bool)(sitd->results & SITD_RESULTS_ACTIVE)); } +static inline bool ehci_enabled(EHCIState *s) +{ + return s->usbcmd & USBCMD_RUNSTOP; +} + +static inline bool ehci_async_enabled(EHCIState *s) +{ + return ehci_enabled(s) && (s->usbcmd & USBCMD_ASE); +} + +static inline bool ehci_periodic_enabled(EHCIState *s) +{ + return ehci_enabled(s) && (s->usbcmd & USBCMD_PSE); +} + +/* packet management */ + +static EHCIPacket *ehci_alloc_packet(EHCIQueue *q) +{ + EHCIPacket *p; + + p = g_new0(EHCIPacket, 1); + p->queue = q; + usb_packet_init(&p->packet); + QTAILQ_INSERT_TAIL(&q->packets, p, next); + trace_usb_ehci_packet_action(p->queue, p, "alloc"); + return p; +} + +static void ehci_free_packet(EHCIPacket *p) +{ + trace_usb_ehci_packet_action(p->queue, p, "free"); + if (p->async == EHCI_ASYNC_INFLIGHT) { + usb_cancel_packet(&p->packet); + } + QTAILQ_REMOVE(&p->queue->packets, p, next); + usb_packet_cleanup(&p->packet); + g_free(p); +} + /* queue management */ -static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, int async) +static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, uint32_t addr, int async) { EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; EHCIQueue *q; q = g_malloc0(sizeof(*q)); q->ehci = ehci; - usb_packet_init(&q->packet); + q->qhaddr = addr; + q->async = async; + QTAILQ_INIT(&q->packets); QTAILQ_INSERT_HEAD(head, q, next); trace_usb_ehci_queue_action(q, "alloc"); return q; } -static void ehci_free_queue(EHCIQueue *q, int async) +static void ehci_free_queue(EHCIQueue *q) { - EHCIQueueHead *head = async ? &q->ehci->aqueues : &q->ehci->pqueues; + EHCIQueueHead *head = q->async ? &q->ehci->aqueues : &q->ehci->pqueues; + EHCIPacket *p; + trace_usb_ehci_queue_action(q, "free"); - if (q->async == EHCI_ASYNC_INFLIGHT) { - usb_cancel_packet(&q->packet); + while ((p = QTAILQ_FIRST(&q->packets)) != NULL) { + ehci_free_packet(p); } QTAILQ_REMOVE(head, q, next); g_free(q); @@ -698,6 +776,7 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr, static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush) { EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; + uint64_t maxage = FRAME_TIMER_NS * ehci->maxframes * 4; EHCIQueue *q, *tmp; QTAILQ_FOREACH_SAFE(q, head, next, tmp) { @@ -706,11 +785,10 @@ 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 + 250000000) { - /* allow 0.25 sec idle */ + if (!flush && ehci->last_run_ns < q->ts + maxage) { continue; } - ehci_free_queue(q, async); + ehci_free_queue(q); } } @@ -720,11 +798,10 @@ static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev, int async) EHCIQueue *q, *tmp; QTAILQ_FOREACH_SAFE(q, head, next, tmp) { - if (!usb_packet_is_inflight(&q->packet) || - q->packet.ep->dev != dev) { + if (q->dev != dev) { continue; } - ehci_free_queue(q, async); + ehci_free_queue(q); } } @@ -734,7 +811,7 @@ static void ehci_queues_rip_all(EHCIState *ehci, int async) EHCIQueue *q, *tmp; QTAILQ_FOREACH_SAFE(q, head, next, tmp) { - ehci_free_queue(q, async); + ehci_free_queue(q); } } @@ -812,6 +889,8 @@ static void ehci_wakeup(USBPort *port) USBPort *companion = s->companion_ports[port->index]; if (companion->ops->wakeup) { companion->ops->wakeup(companion); + } else { + qemu_bh_schedule(s->async_bh); } } } @@ -904,7 +983,6 @@ static void ehci_reset(void *opaque) s->astate = EST_INACTIVE; s->pstate = EST_INACTIVE; - s->attach_poll_counter = 0; for(i = 0; i < NB_PORTS; i++) { if (s->companion_ports[i]) { @@ -920,6 +998,7 @@ static void ehci_reset(void *opaque) ehci_queues_rip_all(s, 0); ehci_queues_rip_all(s, 1); qemu_del_timer(s->frame_timer); + qemu_bh_cancel(s->async_bh); } static uint32_t ehci_mem_readb(void *ptr, target_phys_addr_t addr) @@ -1064,22 +1143,20 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) /* Do any register specific pre-write processing here. */ switch(addr) { case USBCMD: - if ((val & USBCMD_RUNSTOP) && !(s->usbcmd & USBCMD_RUNSTOP)) { - qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock)); - SET_LAST_RUN_CLOCK(s); - ehci_clear_usbsts(s, USBSTS_HALT); - } - - if (!(val & USBCMD_RUNSTOP) && (s->usbcmd & USBCMD_RUNSTOP)) { - qemu_del_timer(s->frame_timer); - ehci_queues_rip_all(s, 0); - ehci_queues_rip_all(s, 1); - ehci_set_usbsts(s, USBSTS_HALT); - } - if (val & USBCMD_HCRESET) { ehci_reset(s); val = s->usbcmd; + break; + } + + if (((USBCMD_RUNSTOP | USBCMD_PSE | USBCMD_ASE) & val) != + ((USBCMD_RUNSTOP | USBCMD_PSE | USBCMD_ASE) & s->usbcmd)) { + if (s->pstate == EST_INACTIVE) { + SET_LAST_RUN_CLOCK(s); + } + ehci_update_halt(s); + s->async_stepdown = 0; + qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock)); } /* not supporting dynamic frame list size at the moment */ @@ -1114,7 +1191,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) break; case PERIODICLISTBASE: - if ((s->usbcmd & USBCMD_PSE) && (s->usbcmd & USBCMD_RUNSTOP)) { + if (ehci_periodic_enabled(s)) { fprintf(stderr, "ehci: PERIODIC list base register set while periodic schedule\n" " is enabled and HC is enabled\n"); @@ -1122,7 +1199,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) break; case ASYNCLISTADDR: - if ((s->usbcmd & USBCMD_ASE) && (s->usbcmd & USBCMD_RUNSTOP)) { + if (ehci_async_enabled(s)) { fprintf(stderr, "ehci: ASYNC list address register set while async schedule\n" " is enabled and HC is enabled\n"); @@ -1169,21 +1246,25 @@ static inline int put_dwords(EHCIState *ehci, uint32_t addr, static int ehci_qh_do_overlay(EHCIQueue *q) { + EHCIPacket *p = QTAILQ_FIRST(&q->packets); int i; int dtoggle; int ping; int eps; int reload; + assert(p != NULL); + assert(p->qtdaddr == q->qtdaddr); + // remember values in fields to preserve in qh after overlay dtoggle = q->qh.token & QTD_TOKEN_DTOGGLE; ping = q->qh.token & QTD_TOKEN_PING; - q->qh.current_qtd = q->qtdaddr; - q->qh.next_qtd = q->qtd.next; - q->qh.altnext_qtd = q->qtd.altnext; - q->qh.token = q->qtd.token; + q->qh.current_qtd = p->qtdaddr; + q->qh.next_qtd = p->qtd.next; + q->qh.altnext_qtd = p->qtd.altnext; + q->qh.token = p->qtd.token; eps = get_field(q->qh.epchar, QH_EPCHAR_EPS); @@ -1196,7 +1277,7 @@ static int ehci_qh_do_overlay(EHCIQueue *q) set_field(&q->qh.altnext_qtd, reload, QH_ALTNEXT_NAKCNT); for (i = 0; i < 5; i++) { - q->qh.bufptr[i] = q->qtd.bufptr[i]; + q->qh.bufptr[i] = p->qtd.bufptr[i]; } if (!(q->qh.epchar & QH_EPCHAR_DTC)) { @@ -1214,15 +1295,15 @@ static int ehci_qh_do_overlay(EHCIQueue *q) return 0; } -static int ehci_init_transfer(EHCIQueue *q) +static int ehci_init_transfer(EHCIPacket *p) { uint32_t cpage, offset, bytes, plen; dma_addr_t page; - cpage = get_field(q->qh.token, QTD_TOKEN_CPAGE); - bytes = get_field(q->qh.token, QTD_TOKEN_TBYTES); - offset = q->qh.bufptr[0] & ~QTD_BUFPTR_MASK; - pci_dma_sglist_init(&q->sgl, &q->ehci->dev, 5); + cpage = get_field(p->qtd.token, QTD_TOKEN_CPAGE); + bytes = get_field(p->qtd.token, QTD_TOKEN_TBYTES); + offset = p->qtd.bufptr[0] & ~QTD_BUFPTR_MASK; + pci_dma_sglist_init(&p->sgl, &p->queue->ehci->dev, 5); while (bytes > 0) { if (cpage > 4) { @@ -1230,7 +1311,7 @@ static int ehci_init_transfer(EHCIQueue *q) return USB_RET_PROCERR; } - page = q->qh.bufptr[cpage] & QTD_BUFPTR_MASK; + page = p->qtd.bufptr[cpage] & QTD_BUFPTR_MASK; page += offset; plen = bytes; if (plen > 4096 - offset) { @@ -1239,7 +1320,7 @@ static int ehci_init_transfer(EHCIQueue *q) cpage++; } - qemu_sglist_add(&q->sgl, page, plen); + qemu_sglist_add(&p->sgl, page, plen); bytes -= plen; } return 0; @@ -1249,8 +1330,6 @@ static void ehci_finish_transfer(EHCIQueue *q, int status) { uint32_t cpage, offset; - qemu_sglist_destroy(&q->sgl); - if (status > 0) { /* update cpage & offset */ cpage = get_field(q->qh.token, QTD_TOKEN_CPAGE); @@ -1268,7 +1347,7 @@ static void ehci_finish_transfer(EHCIQueue *q, int status) static void ehci_async_complete_packet(USBPort *port, USBPacket *packet) { - EHCIQueue *q; + EHCIPacket *p; EHCIState *s = port->opaque; uint32_t portsc = s->portsc[port->index]; @@ -1278,23 +1357,31 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet) return; } - q = container_of(packet, EHCIQueue, packet); - trace_usb_ehci_queue_action(q, "wakeup"); - assert(q->async == EHCI_ASYNC_INFLIGHT); - q->async = EHCI_ASYNC_FINISHED; - q->usb_status = packet->result; + p = container_of(packet, EHCIPacket, packet); + trace_usb_ehci_packet_action(p->queue, p, "wakeup"); + assert(p->async == EHCI_ASYNC_INFLIGHT); + p->async = EHCI_ASYNC_FINISHED; + p->usb_status = packet->result; + + if (p->queue->async) { + qemu_bh_schedule(p->queue->ehci->async_bh); + } } static void ehci_execute_complete(EHCIQueue *q) { - assert(q->async != EHCI_ASYNC_INFLIGHT); - q->async = EHCI_ASYNC_NONE; + EHCIPacket *p = QTAILQ_FIRST(&q->packets); + + assert(p != NULL); + assert(p->qtdaddr == q->qtdaddr); + assert(p->async != EHCI_ASYNC_INFLIGHT); + p->async = EHCI_ASYNC_NONE; DPRINTF("execute_complete: qhaddr 0x%x, next %x, qtdaddr 0x%x, status %d\n", q->qhaddr, q->qh.next, q->qtdaddr, q->usb_status); - if (q->usb_status < 0) { - switch(q->usb_status) { + if (p->usb_status < 0) { + switch (p->usb_status) { case USB_RET_IOERROR: case USB_RET_NODEV: q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_XACTERR); @@ -1314,28 +1401,29 @@ static void ehci_execute_complete(EHCIQueue *q) break; default: /* should not be triggerable */ - fprintf(stderr, "USB invalid response %d to handle\n", q->usb_status); + fprintf(stderr, "USB invalid response %d\n", p->usb_status); assert(0); break; } - } else if ((q->usb_status > q->tbytes) && (q->pid == USB_TOKEN_IN)) { - q->usb_status = USB_RET_BABBLE; + } else if ((p->usb_status > p->tbytes) && (p->pid == USB_TOKEN_IN)) { + p->usb_status = USB_RET_BABBLE; q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE); ehci_record_interrupt(q->ehci, USBSTS_ERRINT); } else { // TODO check 4.12 for splits - if (q->tbytes && q->pid == USB_TOKEN_IN) { - q->tbytes -= q->usb_status; + if (p->tbytes && p->pid == USB_TOKEN_IN) { + p->tbytes -= p->usb_status; } else { - q->tbytes = 0; + p->tbytes = 0; } - DPRINTF("updating tbytes to %d\n", q->tbytes); - set_field(&q->qh.token, q->tbytes, QTD_TOKEN_TBYTES); + DPRINTF("updating tbytes to %d\n", p->tbytes); + set_field(&q->qh.token, p->tbytes, QTD_TOKEN_TBYTES); } - ehci_finish_transfer(q, q->usb_status); - usb_packet_unmap(&q->packet); + ehci_finish_transfer(q, p->usb_status); + qemu_sglist_destroy(&p->sgl); + usb_packet_unmap(&p->packet); q->qh.token ^= QTD_TOKEN_DTOGGLE; q->qh.token &= ~QTD_TOKEN_ACTIVE; @@ -1347,48 +1435,51 @@ static void ehci_execute_complete(EHCIQueue *q) // 4.10.3 -static int ehci_execute(EHCIQueue *q) +static int ehci_execute(EHCIPacket *p, const char *action) { - USBDevice *dev; USBEndpoint *ep; int ret; int endp; - int devadr; - if ( !(q->qh.token & QTD_TOKEN_ACTIVE)) { - fprintf(stderr, "Attempting to execute inactive QH\n"); + if (!(p->qtd.token & QTD_TOKEN_ACTIVE)) { + fprintf(stderr, "Attempting to execute inactive qtd\n"); return USB_RET_PROCERR; } - q->tbytes = (q->qh.token & QTD_TOKEN_TBYTES_MASK) >> QTD_TOKEN_TBYTES_SH; - if (q->tbytes > BUFF_SIZE) { + p->tbytes = (p->qtd.token & QTD_TOKEN_TBYTES_MASK) >> QTD_TOKEN_TBYTES_SH; + if (p->tbytes > BUFF_SIZE) { fprintf(stderr, "Request for more bytes than allowed\n"); return USB_RET_PROCERR; } - q->pid = (q->qh.token & QTD_TOKEN_PID_MASK) >> QTD_TOKEN_PID_SH; - switch(q->pid) { - case 0: q->pid = USB_TOKEN_OUT; break; - case 1: q->pid = USB_TOKEN_IN; break; - case 2: q->pid = USB_TOKEN_SETUP; break; - default: fprintf(stderr, "bad token\n"); break; + p->pid = (p->qtd.token & QTD_TOKEN_PID_MASK) >> QTD_TOKEN_PID_SH; + switch (p->pid) { + case 0: + p->pid = USB_TOKEN_OUT; + break; + case 1: + p->pid = USB_TOKEN_IN; + break; + case 2: + p->pid = USB_TOKEN_SETUP; + break; + default: + fprintf(stderr, "bad token\n"); + break; } - if (ehci_init_transfer(q) != 0) { + if (ehci_init_transfer(p) != 0) { return USB_RET_PROCERR; } - endp = get_field(q->qh.epchar, QH_EPCHAR_EP); - devadr = get_field(q->qh.epchar, QH_EPCHAR_DEVADDR); + endp = get_field(p->queue->qh.epchar, QH_EPCHAR_EP); + ep = usb_ep_get(p->queue->dev, p->pid, endp); - /* TODO: associating device with ehci port */ - dev = ehci_find_device(q->ehci, devadr); - ep = usb_ep_get(dev, q->pid, endp); + usb_packet_setup(&p->packet, p->pid, ep); + usb_packet_map(&p->packet, &p->sgl); - usb_packet_setup(&q->packet, q->pid, ep); - usb_packet_map(&q->packet, &q->sgl); - - ret = usb_handle_packet(dev, &q->packet); + trace_usb_ehci_packet_action(p->queue, p, action); + ret = usb_handle_packet(p->queue->dev, &p->packet); DPRINTF("submit: qh %x next %x qtd %x pid %x len %zd " "(total %d) endp %x ret %d\n", q->qhaddr, q->qh.next, q->qtdaddr, q->pid, @@ -1504,6 +1595,24 @@ static int ehci_process_itd(EHCIState *ehci, return 0; } + +/* + * Write the qh back to guest physical memory. This step isn't + * in the EHCI spec but we need to do it since we don't share + * physical memory with our guest VM. + * + * The first three dwords are read-only for the EHCI, so skip them + * when writing back the qh. + */ +static void ehci_flush_qh(EHCIQueue *q) +{ + uint32_t *qh = (uint32_t *) &q->qh; + uint32_t dwords = sizeof(EHCIqh) >> 2; + uint32_t addr = NLPTR_GET(q->qhaddr); + + put_dwords(q->ehci, addr + 3 * sizeof(uint32_t), qh + 3, dwords - 3); +} + /* This state is the entry point for asynchronous schedule * processing. Entry here consitutes a EHCI start event state (4.8.5) */ @@ -1601,17 +1710,18 @@ out: static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) { - uint32_t entry; + EHCIPacket *p; + uint32_t entry, devaddr; EHCIQueue *q; entry = ehci_get_fetch_addr(ehci, async); q = ehci_find_queue_by_qh(ehci, entry, async); if (NULL == q) { - q = ehci_alloc_queue(ehci, async); + q = ehci_alloc_queue(ehci, entry, async); } - q->qhaddr = entry; - q->seen++; + p = QTAILQ_FIRST(&q->packets); + q->seen++; if (q->seen > 1) { /* we are going in circles -- stop processing */ ehci_set_state(ehci, async, EST_ACTIVE); @@ -1623,14 +1733,28 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) (uint32_t *) &q->qh, sizeof(EHCIqh) >> 2); ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &q->qh); - if (q->async == EHCI_ASYNC_INFLIGHT) { + devaddr = get_field(q->qh.epchar, QH_EPCHAR_DEVADDR); + if (q->dev != NULL && q->dev->addr != devaddr) { + if (!QTAILQ_EMPTY(&q->packets)) { + /* should not happen (guest bug) */ + while ((p = QTAILQ_FIRST(&q->packets)) != NULL) { + ehci_free_packet(p); + } + } + q->dev = NULL; + } + if (q->dev == NULL) { + q->dev = ehci_find_device(q->ehci, devaddr); + } + + if (p && p->async == EHCI_ASYNC_INFLIGHT) { /* I/O still in progress -- skip queue */ ehci_set_state(ehci, async, EST_HORIZONTALQH); goto out; } - if (q->async == EHCI_ASYNC_FINISHED) { + if (p && p->async == EHCI_ASYNC_FINISHED) { /* I/O finished -- continue processing queue */ - trace_usb_ehci_queue_action(q, "resume"); + trace_usb_ehci_packet_action(p->queue, p, "complete"); ehci_set_state(ehci, async, EST_EXECUTING); goto out; } @@ -1726,7 +1850,7 @@ static int ehci_state_fetchsitd(EHCIState *ehci, int async) } /* Section 4.10.2 - paragraph 3 */ -static int ehci_state_advqueue(EHCIQueue *q, int async) +static int ehci_state_advqueue(EHCIQueue *q) { #if 0 /* TO-DO: 4.10.2 - paragraph 2 @@ -1745,81 +1869,117 @@ static int ehci_state_advqueue(EHCIQueue *q, int async) if (((q->qh.token & QTD_TOKEN_TBYTES_MASK) != 0) && (NLPTR_TBIT(q->qh.altnext_qtd) == 0)) { q->qtdaddr = q->qh.altnext_qtd; - ehci_set_state(q->ehci, async, EST_FETCHQTD); + ehci_set_state(q->ehci, q->async, EST_FETCHQTD); /* * next qTD is valid */ } else if (NLPTR_TBIT(q->qh.next_qtd) == 0) { q->qtdaddr = q->qh.next_qtd; - ehci_set_state(q->ehci, async, EST_FETCHQTD); + ehci_set_state(q->ehci, q->async, EST_FETCHQTD); /* * no valid qTD, try next QH */ } else { - ehci_set_state(q->ehci, async, EST_HORIZONTALQH); + ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); } return 1; } /* Section 4.10.2 - paragraph 4 */ -static int ehci_state_fetchqtd(EHCIQueue *q, int async) +static int ehci_state_fetchqtd(EHCIQueue *q) { + EHCIqtd qtd; + EHCIPacket *p; int again = 0; - get_dwords(q->ehci, NLPTR_GET(q->qtdaddr), (uint32_t *) &q->qtd, + get_dwords(q->ehci, NLPTR_GET(q->qtdaddr), (uint32_t *) &qtd, sizeof(EHCIqtd) >> 2); - ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), &q->qtd); + ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), &qtd); - if (q->qtd.token & QTD_TOKEN_ACTIVE) { - ehci_set_state(q->ehci, async, EST_EXECUTE); + p = QTAILQ_FIRST(&q->packets); + while (p != NULL && p->qtdaddr != q->qtdaddr) { + /* should not happen (guest bug) */ + ehci_free_packet(p); + p = QTAILQ_FIRST(&q->packets); + } + if (p != NULL) { + ehci_qh_do_overlay(q); + ehci_flush_qh(q); + if (p->async == EHCI_ASYNC_INFLIGHT) { + ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); + } else { + ehci_set_state(q->ehci, q->async, EST_EXECUTING); + } + again = 1; + } else if (qtd.token & QTD_TOKEN_ACTIVE) { + p = ehci_alloc_packet(q); + p->qtdaddr = q->qtdaddr; + p->qtd = qtd; + ehci_set_state(q->ehci, q->async, EST_EXECUTE); again = 1; } else { - ehci_set_state(q->ehci, async, EST_HORIZONTALQH); + ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); again = 1; } return again; } -static int ehci_state_horizqh(EHCIQueue *q, int async) +static int ehci_state_horizqh(EHCIQueue *q) { int again = 0; - if (ehci_get_fetch_addr(q->ehci, async) != q->qh.next) { - ehci_set_fetch_addr(q->ehci, async, q->qh.next); - ehci_set_state(q->ehci, async, EST_FETCHENTRY); + if (ehci_get_fetch_addr(q->ehci, q->async) != q->qh.next) { + ehci_set_fetch_addr(q->ehci, q->async, q->qh.next); + ehci_set_state(q->ehci, q->async, EST_FETCHENTRY); again = 1; } else { - ehci_set_state(q->ehci, async, EST_ACTIVE); + ehci_set_state(q->ehci, q->async, EST_ACTIVE); } return again; } -/* - * Write the qh back to guest physical memory. This step isn't - * in the EHCI spec but we need to do it since we don't share - * physical memory with our guest VM. - * - * The first three dwords are read-only for the EHCI, so skip them - * when writing back the qh. - */ -static void ehci_flush_qh(EHCIQueue *q) +static void ehci_fill_queue(EHCIPacket *p) { - uint32_t *qh = (uint32_t *) &q->qh; - uint32_t dwords = sizeof(EHCIqh) >> 2; - uint32_t addr = NLPTR_GET(q->qhaddr); + EHCIQueue *q = p->queue; + EHCIqtd qtd = p->qtd; + uint32_t qtdaddr; - put_dwords(q->ehci, addr + 3 * sizeof(uint32_t), qh + 3, dwords - 3); + for (;;) { + if (NLPTR_TBIT(qtd.altnext) == 0) { + break; + } + if (NLPTR_TBIT(qtd.next) != 0) { + break; + } + qtdaddr = qtd.next; + get_dwords(q->ehci, NLPTR_GET(qtdaddr), + (uint32_t *) &qtd, sizeof(EHCIqtd) >> 2); + ehci_trace_qtd(q, NLPTR_GET(qtdaddr), &qtd); + if (!(qtd.token & QTD_TOKEN_ACTIVE)) { + break; + } + p = ehci_alloc_packet(q); + p->qtdaddr = qtdaddr; + p->qtd = qtd; + p->usb_status = ehci_execute(p, "queue"); + assert(p->usb_status = USB_RET_ASYNC); + p->async = EHCI_ASYNC_INFLIGHT; + } } -static int ehci_state_execute(EHCIQueue *q, int async) +static int ehci_state_execute(EHCIQueue *q) { + EHCIPacket *p = QTAILQ_FIRST(&q->packets); int again = 0; + assert(p != NULL); + assert(p->qtdaddr == q->qtdaddr); + if (ehci_qh_do_overlay(q) != 0) { return -1; } @@ -1828,55 +1988,60 @@ static int ehci_state_execute(EHCIQueue *q, int async) // TODO write back ptr to async list when done or out of time // TODO Windows does not seem to ever set the MULT field - if (!async) { + if (!q->async) { int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT); if (!transactCtr) { - ehci_set_state(q->ehci, async, EST_HORIZONTALQH); + ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); again = 1; goto out; } } - if (async) { + if (q->async) { ehci_set_usbsts(q->ehci, USBSTS_REC); } - q->usb_status = ehci_execute(q); - if (q->usb_status == USB_RET_PROCERR) { + p->usb_status = ehci_execute(p, "process"); + if (p->usb_status == USB_RET_PROCERR) { again = -1; goto out; } - if (q->usb_status == USB_RET_ASYNC) { + if (p->usb_status == USB_RET_ASYNC) { ehci_flush_qh(q); - trace_usb_ehci_queue_action(q, "suspend"); - q->async = EHCI_ASYNC_INFLIGHT; - ehci_set_state(q->ehci, async, EST_HORIZONTALQH); + trace_usb_ehci_packet_action(p->queue, p, "async"); + p->async = EHCI_ASYNC_INFLIGHT; + ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); again = 1; + ehci_fill_queue(p); goto out; } - ehci_set_state(q->ehci, async, EST_EXECUTING); + ehci_set_state(q->ehci, q->async, EST_EXECUTING); again = 1; out: return again; } -static int ehci_state_executing(EHCIQueue *q, int async) +static int ehci_state_executing(EHCIQueue *q) { + EHCIPacket *p = QTAILQ_FIRST(&q->packets); int again = 0; + assert(p != NULL); + assert(p->qtdaddr == q->qtdaddr); + ehci_execute_complete(q); - if (q->usb_status == USB_RET_ASYNC) { + if (p->usb_status == USB_RET_ASYNC) { goto out; } - if (q->usb_status == USB_RET_PROCERR) { + if (p->usb_status == USB_RET_PROCERR) { again = -1; goto out; } // 4.10.3 - if (!async) { + if (!q->async) { int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT); transactCtr--; set_field(&q->qh.epcap, transactCtr, QH_EPCAP_MULT); @@ -1885,10 +2050,10 @@ static int ehci_state_executing(EHCIQueue *q, int async) } /* 4.10.5 */ - if (q->usb_status == USB_RET_NAK) { - ehci_set_state(q->ehci, async, EST_HORIZONTALQH); + if (p->usb_status == USB_RET_NAK) { + ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); } else { - ehci_set_state(q->ehci, async, EST_WRITEBACK); + ehci_set_state(q->ehci, q->async, EST_WRITEBACK); } again = 1; @@ -1899,14 +2064,19 @@ out: } -static int ehci_state_writeback(EHCIQueue *q, int async) +static int ehci_state_writeback(EHCIQueue *q) { + EHCIPacket *p = QTAILQ_FIRST(&q->packets); int again = 0; /* Write back the QTD from the QH area */ - ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), (EHCIqtd*) &q->qh.next_qtd); - put_dwords(q->ehci, NLPTR_GET(q->qtdaddr), (uint32_t *) &q->qh.next_qtd, + assert(p != NULL); + assert(p->qtdaddr == q->qtdaddr); + + ehci_trace_qtd(q, NLPTR_GET(p->qtdaddr), (EHCIqtd *) &q->qh.next_qtd); + put_dwords(q->ehci, NLPTR_GET(p->qtdaddr), (uint32_t *) &q->qh.next_qtd, sizeof(EHCIqtd) >> 2); + ehci_free_packet(p); /* * EHCI specs say go horizontal here. @@ -1917,10 +2087,10 @@ static int ehci_state_writeback(EHCIQueue *q, int async) * bit is clear. */ if (q->qh.token & QTD_TOKEN_HALT) { - ehci_set_state(q->ehci, async, EST_HORIZONTALQH); + ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); again = 1; } else { - ehci_set_state(q->ehci, async, EST_ADVANCEQUEUE); + ehci_set_state(q->ehci, q->async, EST_ADVANCEQUEUE); again = 1; } return again; @@ -1930,8 +2100,7 @@ static int ehci_state_writeback(EHCIQueue *q, int async) * This is the state machine that is common to both async and periodic */ -static void ehci_advance_state(EHCIState *ehci, - int async) +static void ehci_advance_state(EHCIState *ehci, int async) { EHCIQueue *q = NULL; int again; @@ -1948,7 +2117,12 @@ static void ehci_advance_state(EHCIState *ehci, case EST_FETCHQH: q = ehci_state_fetchqh(ehci, async); - again = q ? 1 : 0; + if (q != NULL) { + assert(q->async == async); + again = 1; + } else { + again = 0; + } break; case EST_FETCHITD: @@ -1960,29 +2134,35 @@ static void ehci_advance_state(EHCIState *ehci, break; case EST_ADVANCEQUEUE: - again = ehci_state_advqueue(q, async); + again = ehci_state_advqueue(q); break; case EST_FETCHQTD: - again = ehci_state_fetchqtd(q, async); + again = ehci_state_fetchqtd(q); break; case EST_HORIZONTALQH: - again = ehci_state_horizqh(q, async); + again = ehci_state_horizqh(q); break; case EST_EXECUTE: - again = ehci_state_execute(q, async); + again = ehci_state_execute(q); + if (async) { + ehci->async_stepdown = 0; + } break; case EST_EXECUTING: assert(q != NULL); - again = ehci_state_executing(q, async); + if (async) { + ehci->async_stepdown = 0; + } + again = ehci_state_executing(q); break; case EST_WRITEBACK: assert(q != NULL); - again = ehci_state_writeback(q, async); + again = ehci_state_writeback(q); break; default: @@ -2009,17 +2189,15 @@ static void ehci_advance_async_state(EHCIState *ehci) switch(ehci_get_state(ehci, async)) { case EST_INACTIVE: - if (!(ehci->usbcmd & USBCMD_ASE)) { + if (!ehci_async_enabled(ehci)) { break; } - ehci_set_usbsts(ehci, USBSTS_ASS); ehci_set_state(ehci, async, EST_ACTIVE); // No break, fall through to ACTIVE case EST_ACTIVE: - if ( !(ehci->usbcmd & USBCMD_ASE)) { + if (!ehci_async_enabled(ehci)) { ehci_queues_rip_all(ehci, async); - ehci_clear_usbsts(ehci, USBSTS_ASS); ehci_set_state(ehci, async, EST_INACTIVE); break; } @@ -2070,17 +2248,15 @@ static void ehci_advance_periodic_state(EHCIState *ehci) switch(ehci_get_state(ehci, async)) { case EST_INACTIVE: - if ( !(ehci->frindex & 7) && (ehci->usbcmd & USBCMD_PSE)) { - ehci_set_usbsts(ehci, USBSTS_PSS); + if (!(ehci->frindex & 7) && ehci_periodic_enabled(ehci)) { ehci_set_state(ehci, async, EST_ACTIVE); // No break, fall through to ACTIVE } else break; case EST_ACTIVE: - if ( !(ehci->frindex & 7) && !(ehci->usbcmd & USBCMD_PSE)) { + if (!(ehci->frindex & 7) && !ehci_periodic_enabled(ehci)) { ehci_queues_rip_all(ehci, async); - ehci_clear_usbsts(ehci, USBSTS_PSS); ehci_set_state(ehci, async, EST_INACTIVE); break; } @@ -2111,58 +2287,86 @@ static void ehci_advance_periodic_state(EHCIState *ehci) } } +static void ehci_update_frindex(EHCIState *ehci, int frames) +{ + int i; + + if (!ehci_enabled(ehci)) { + return; + } + + for (i = 0; i < frames; i++) { + ehci->frindex += 8; + + if (ehci->frindex == 0x00002000) { + ehci_set_interrupt(ehci, USBSTS_FLR); + } + + if (ehci->frindex == 0x00004000) { + ehci_set_interrupt(ehci, USBSTS_FLR); + ehci->frindex = 0; + } + } +} + static void ehci_frame_timer(void *opaque) { EHCIState *ehci = opaque; + int schedules = 0; int64_t expire_time, t_now; uint64_t ns_elapsed; - int frames; + int frames, skipped_frames; int i; - int skipped_frames = 0; t_now = qemu_get_clock_ns(vm_clock); - expire_time = t_now + (get_ticks_per_sec() / ehci->freq); - ns_elapsed = t_now - ehci->last_run_ns; frames = ns_elapsed / FRAME_TIMER_NS; - for (i = 0; i < frames; i++) { - if ( !(ehci->usbsts & USBSTS_HALT)) { - ehci->frindex += 8; - - if (ehci->frindex == 0x00002000) { - ehci_set_interrupt(ehci, USBSTS_FLR); - } + if (ehci_periodic_enabled(ehci) || ehci->pstate != EST_INACTIVE) { + schedules++; + expire_time = t_now + (get_ticks_per_sec() / FRAME_TIMER_FREQ); - if (ehci->frindex == 0x00004000) { - ehci_set_interrupt(ehci, USBSTS_FLR); - ehci->frindex = 0; - } + if (frames > ehci->maxframes) { + skipped_frames = frames - ehci->maxframes; + ehci_update_frindex(ehci, skipped_frames); + ehci->last_run_ns += FRAME_TIMER_NS * skipped_frames; + frames -= skipped_frames; + DPRINTF("WARNING - EHCI skipped %d frames\n", skipped_frames); } - if (frames - i > ehci->maxframes) { - skipped_frames++; - } else { + for (i = 0; i < frames; i++) { + ehci_update_frindex(ehci, 1); ehci_advance_periodic_state(ehci); + ehci->last_run_ns += FRAME_TIMER_NS; } - - ehci->last_run_ns += FRAME_TIMER_NS; - } - -#if 0 - if (skipped_frames) { - DPRINTF("WARNING - EHCI skipped %d frames\n", skipped_frames); + } else { + if (ehci->async_stepdown < ehci->maxframes / 2) { + ehci->async_stepdown++; + } + expire_time = t_now + (get_ticks_per_sec() + * ehci->async_stepdown / FRAME_TIMER_FREQ); + ehci_update_frindex(ehci, frames); + ehci->last_run_ns += FRAME_TIMER_NS * frames; } -#endif /* Async is not inside loop since it executes everything it can once * called */ - ehci_advance_async_state(ehci); + if (ehci_async_enabled(ehci) || ehci->astate != EST_INACTIVE) { + schedules++; + qemu_bh_schedule(ehci->async_bh); + } - qemu_mod_timer(ehci->frame_timer, expire_time); + if (schedules) { + qemu_mod_timer(ehci->frame_timer, expire_time); + } } +static void ehci_async_bh(void *opaque) +{ + EHCIState *ehci = opaque; + ehci_advance_async_state(ehci); +} static const MemoryRegionOps ehci_mem_ops = { .old_mmio = { @@ -2192,7 +2396,6 @@ static const VMStateDescription vmstate_ehci = { }; static Property ehci_properties[] = { - DEFINE_PROP_UINT32("freq", EHCIState, freq, FRAME_TIMER_FREQ), DEFINE_PROP_UINT32("maxframes", EHCIState, maxframes, 128), DEFINE_PROP_END_OF_LIST(), }; @@ -2298,6 +2501,7 @@ static int usb_ehci_initfn(PCIDevice *dev) } s->frame_timer = qemu_new_timer_ns(vm_clock, ehci_frame_timer, s); + s->async_bh = qemu_bh_new(ehci_async_bh, s); QTAILQ_INIT(&s->aqueues); QTAILQ_INIT(&s->pqueues); diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index 9e211a0..9871e24 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -131,10 +131,14 @@ struct UHCIState { uint8_t status2; /* bit 0 and 1 are used to generate UHCI_STS_USBINT */ int64_t expire_time; QEMUTimer *frame_timer; + QEMUBH *bh; + uint32_t frame_bytes; + uint32_t frame_bandwidth; UHCIPort ports[NB_PORTS]; /* Interrupts that should be raised at the end of the current frame. */ uint32_t pending_int_mask; + int irq_pin; /* Active packets */ QTAILQ_HEAD(, UHCIQueue) queues; @@ -337,7 +341,7 @@ static void uhci_update_irq(UHCIState *s) } else { level = 0; } - qemu_set_irq(s->dev.irq[3], level); + qemu_set_irq(s->dev.irq[s->irq_pin], level); } static void uhci_reset(void *opaque) @@ -369,16 +373,10 @@ static void uhci_reset(void *opaque) } uhci_async_cancel_all(s); + qemu_bh_cancel(s->bh); uhci_update_irq(s); } -static void uhci_pre_save(void *opaque) -{ - UHCIState *s = opaque; - - uhci_async_cancel_all(s); -} - static const VMStateDescription vmstate_uhci_port = { .name = "uhci port", .version_id = 1, @@ -395,7 +393,6 @@ static const VMStateDescription vmstate_uhci = { .version_id = 2, .minimum_version_id = 1, .minimum_version_id_old = 1, - .pre_save = uhci_pre_save, .fields = (VMStateField []) { VMSTATE_PCI_DEVICE(dev, UHCIState), VMSTATE_UINT8_EQUAL(num_ports_vmstate, UHCIState), @@ -905,7 +902,9 @@ static void uhci_async_complete(USBPort *port, USBPacket *packet) uhci_async_free(async); } else { async->done = 1; - uhci_process_frame(s); + if (s->frame_bytes < s->frame_bandwidth) { + qemu_bh_schedule(s->bh); + } } } @@ -985,7 +984,7 @@ static void uhci_fill_queue(UHCIState *s, UHCI_TD *td) static void uhci_process_frame(UHCIState *s) { uint32_t frame_addr, link, old_td_ctrl, val, int_mask; - uint32_t curr_qh, td_count = 0, bytes_count = 0; + uint32_t curr_qh, td_count = 0; int cnt, ret; UHCI_TD td; UHCI_QH qh; @@ -1002,6 +1001,12 @@ static void uhci_process_frame(UHCIState *s) qhdb_reset(&qhdb); for (cnt = FRAME_MAX_LOOPS; is_valid(link) && cnt; cnt--) { + if (s->frame_bytes >= s->frame_bandwidth) { + /* We've reached the usb 1.1 bandwidth, which is + 1280 bytes/frame, stop processing */ + trace_usb_uhci_frame_stop_bandwidth(); + break; + } if (is_qh(link)) { /* QH */ trace_usb_uhci_qh_load(link & ~0xf); @@ -1011,18 +1016,12 @@ static void uhci_process_frame(UHCIState *s) * We're going in circles. Which is not a bug because * HCD is allowed to do that as part of the BW management. * - * Stop processing here if - * (a) no transaction has been done since we've been - * here last time, or - * (b) we've reached the usb 1.1 bandwidth, which is - * 1280 bytes/frame. + * Stop processing here if no transaction has been done + * since we've been here last time. */ if (td_count == 0) { trace_usb_uhci_frame_loop_stop_idle(); break; - } else if (bytes_count >= 1280) { - trace_usb_uhci_frame_loop_stop_bandwidth(); - break; } else { trace_usb_uhci_frame_loop_continue(); td_count = 0; @@ -1085,7 +1084,7 @@ static void uhci_process_frame(UHCIState *s) trace_usb_uhci_td_complete(curr_qh & ~0xf, link & ~0xf); link = td.link; td_count++; - bytes_count += (td.ctrl & 0x7ff) + 1; + s->frame_bytes += (td.ctrl & 0x7ff) + 1; if (curr_qh) { /* update QH element link */ @@ -1112,12 +1111,20 @@ out: s->pending_int_mask |= int_mask; } +static void uhci_bh(void *opaque) +{ + UHCIState *s = opaque; + uhci_process_frame(s); +} + static void uhci_frame_timer(void *opaque) { UHCIState *s = opaque; /* prepare the timer for the next frame */ s->expire_time += (get_ticks_per_sec() / FRAME_TIMER_FREQ); + s->frame_bytes = 0; + qemu_bh_cancel(s->bh); if (!(s->cmd & UHCI_CMD_RS)) { /* Full stop */ @@ -1178,15 +1185,31 @@ static USBBusOps uhci_bus_ops = { static int usb_uhci_common_initfn(PCIDevice *dev) { + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); UHCIState *s = DO_UPCAST(UHCIState, dev, dev); uint8_t *pci_conf = s->dev.config; int i; pci_conf[PCI_CLASS_PROG] = 0x00; /* TODO: reset value should be 0. */ - pci_conf[PCI_INTERRUPT_PIN] = 4; /* interrupt pin D */ pci_conf[USB_SBRN] = USB_RELEASE_1; // release number + switch (pc->device_id) { + case PCI_DEVICE_ID_INTEL_82801I_UHCI1: + s->irq_pin = 0; /* A */ + break; + case PCI_DEVICE_ID_INTEL_82801I_UHCI2: + s->irq_pin = 1; /* B */ + break; + case PCI_DEVICE_ID_INTEL_82801I_UHCI3: + s->irq_pin = 2; /* C */ + break; + default: + s->irq_pin = 3; /* D */ + break; + } + pci_config_set_interrupt_pin(pci_conf, s->irq_pin + 1); + if (s->masterbus) { USBPort *ports[NB_PORTS]; for(i = 0; i < NB_PORTS; i++) { @@ -1204,6 +1227,7 @@ static int usb_uhci_common_initfn(PCIDevice *dev) USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); } } + s->bh = qemu_bh_new(uhci_bh, s); s->frame_timer = qemu_new_timer_ns(vm_clock, uhci_frame_timer, s); s->num_ports_vmstate = NB_PORTS; QTAILQ_INIT(&s->queues); @@ -1244,6 +1268,7 @@ static int usb_uhci_exit(PCIDevice *dev) static Property uhci_properties[] = { DEFINE_PROP_STRING("masterbus", UHCIState, masterbus), DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0), + DEFINE_PROP_UINT32("bandwidth", UHCIState, frame_bandwidth, 1280), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 5cf1a64..6c2ff02 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -23,6 +23,7 @@ #include "hw/usb.h" #include "hw/pci.h" #include "hw/msi.h" +#include "trace.h" //#define DEBUG_XHCI //#define DEBUG_DATA @@ -421,7 +422,6 @@ typedef struct XHCIEvRingSeg { uint32_t rsvd; } XHCIEvRingSeg; -#ifdef DEBUG_XHCI static const char *TRBType_names[] = { [TRB_RESERVED] = "TRB_RESERVED", [TR_NORMAL] = "TR_NORMAL", @@ -473,7 +473,6 @@ static const char *trb_name(XHCITRB *trb) return lookup_name(TRB_TYPE(*trb), TRBType_names, ARRAY_SIZE(TRBType_names)); } -#endif static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid); @@ -505,14 +504,13 @@ static void xhci_irq_update(XHCIState *xhci) level = 1; } - DPRINTF("xhci_irq_update(): %d\n", level); - if (xhci->msi && msi_enabled(&xhci->pci_dev)) { if (level) { - DPRINTF("xhci_irq_update(): MSI signal\n"); + trace_usb_xhci_irq_msi(0); msi_notify(&xhci->pci_dev, 0); } } else { + trace_usb_xhci_irq_intx(level); qemu_set_irq(xhci->irq, level); } } @@ -542,9 +540,8 @@ static void xhci_write_event(XHCIState *xhci, XHCIEvent *event) } ev_trb.control = cpu_to_le32(ev_trb.control); - DPRINTF("xhci_write_event(): [%d] %016"PRIx64" %08x %08x %s\n", - xhci->er_ep_idx, ev_trb.parameter, ev_trb.status, ev_trb.control, - trb_name(&ev_trb)); + trace_usb_xhci_queue_event(xhci->er_ep_idx, trb_name(&ev_trb), + ev_trb.parameter, ev_trb.status, ev_trb.control); addr = xhci->er_start + TRB_SIZE*xhci->er_ep_idx; pci_dma_write(&xhci->pci_dev, addr, &ev_trb, TRB_SIZE); @@ -704,10 +701,8 @@ static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb, le32_to_cpus(&trb->status); le32_to_cpus(&trb->control); - DPRINTF("xhci: TRB fetched [" DMA_ADDR_FMT "]: " - "%016" PRIx64 " %08x %08x %s\n", - ring->dequeue, trb->parameter, trb->status, trb->control, - trb_name(trb)); + trace_usb_xhci_fetch_trb(ring->dequeue, trb_name(trb), + trb->parameter, trb->status, trb->control); if ((trb->control & TRB_C) != ring->ccs) { return 0; @@ -746,10 +741,6 @@ static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring) le32_to_cpus(&trb.status); le32_to_cpus(&trb.control); - DPRINTF("xhci: TRB peeked [" DMA_ADDR_FMT "]: " - "%016" PRIx64 " %08x %08x\n", - dequeue, trb.parameter, trb.status, trb.control); - if ((trb.control & TRB_C) != ccs) { return -length; } @@ -812,14 +803,13 @@ static void xhci_er_reset(XHCIState *xhci) static void xhci_run(XHCIState *xhci) { - DPRINTF("xhci_run()\n"); - + trace_usb_xhci_run(); xhci->usbsts &= ~USBSTS_HCH; } static void xhci_stop(XHCIState *xhci) { - DPRINTF("xhci_stop()\n"); + trace_usb_xhci_stop(); xhci->usbsts |= USBSTS_HCH; xhci->crcr_low &= ~CRCR_CRR; } @@ -852,11 +842,10 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid, dma_addr_t dequeue; int i; + trace_usb_xhci_ep_enable(slotid, epid); assert(slotid >= 1 && slotid <= MAXSLOTS); assert(epid >= 1 && epid <= 31); - DPRINTF("xhci_enable_ep(%d, %d)\n", slotid, epid); - slot = &xhci->slots[slotid-1]; if (slot->eps[epid-1]) { fprintf(stderr, "xhci: slot %d ep %d already enabled!\n", slotid, epid); @@ -971,11 +960,10 @@ static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid, XHCISlot *slot; XHCIEPContext *epctx; + trace_usb_xhci_ep_disable(slotid, epid); assert(slotid >= 1 && slotid <= MAXSLOTS); assert(epid >= 1 && epid <= 31); - DPRINTF("xhci_disable_ep(%d, %d)\n", slotid, epid); - slot = &xhci->slots[slotid-1]; if (!slot->eps[epid-1]) { @@ -1001,8 +989,7 @@ static TRBCCode xhci_stop_ep(XHCIState *xhci, unsigned int slotid, XHCISlot *slot; XHCIEPContext *epctx; - DPRINTF("xhci_stop_ep(%d, %d)\n", slotid, epid); - + trace_usb_xhci_ep_stop(slotid, epid); assert(slotid >= 1 && slotid <= MAXSLOTS); if (epid < 1 || epid > 31) { @@ -1036,10 +1023,9 @@ static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid, XHCIEPContext *epctx; USBDevice *dev; + trace_usb_xhci_ep_reset(slotid, epid); assert(slotid >= 1 && slotid <= MAXSLOTS); - DPRINTF("xhci_reset_ep(%d, %d)\n", slotid, epid); - if (epid < 1 || epid > 31) { fprintf(stderr, "xhci: bad ep %d\n", epid); return CC_TRB_ERROR; @@ -1416,12 +1402,14 @@ static int xhci_setup_packet(XHCITransfer *xfer, USBDevice *dev) static int xhci_complete_packet(XHCITransfer *xfer, int ret) { if (ret == USB_RET_ASYNC) { + trace_usb_xhci_xfer_async(xfer); xfer->running_async = 1; xfer->running_retry = 0; xfer->complete = 0; xfer->cancelled = 0; return 0; } else if (ret == USB_RET_NAK) { + trace_usb_xhci_xfer_nak(xfer); xfer->running_async = 0; xfer->running_retry = 1; xfer->complete = 0; @@ -1436,10 +1424,12 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret) if (ret >= 0) { xfer->status = CC_SUCCESS; xhci_xfer_data(xfer, xfer->data, ret, xfer->in_xfer, 0, 1); + trace_usb_xhci_xfer_success(xfer, ret); return 0; } /* error */ + trace_usb_xhci_xfer_error(xfer, ret); switch (ret) { case USB_RET_NODEV: xfer->status = CC_USB_TRANSACTION_ERROR; @@ -1475,11 +1465,12 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) USBDevice *dev; int ret; - DPRINTF("xhci_fire_ctl_transfer(slot=%d)\n", xfer->slotid); - trb_setup = &xfer->trbs[0]; trb_status = &xfer->trbs[xfer->trb_count-1]; + trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, + trb_setup->parameter >> 48); + /* at most one Event Data TRB allowed after STATUS */ if (TRB_TYPE(*trb_status) == TR_EVDATA && xfer->trb_count > 2) { trb_status--; @@ -1620,15 +1611,14 @@ static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext unsigned int length = 0; XHCITRB *trb; - DPRINTF("xhci_fire_transfer(slotid=%d,epid=%d)\n", xfer->slotid, xfer->epid); - for (i = 0; i < xfer->trb_count; i++) { trb = &xfer->trbs[i]; if (TRB_TYPE(*trb) == TR_NORMAL || TRB_TYPE(*trb) == TR_ISOCH) { length += trb->status & 0x1ffff; } } - DPRINTF("xhci: total TD length=%d\n", length); + + trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, length); if (!epctx->has_bg) { xfer->data_length = length; @@ -1664,9 +1654,9 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid int length; int i; + trace_usb_xhci_ep_kick(slotid, epid); assert(slotid >= 1 && slotid <= MAXSLOTS); assert(epid >= 1 && epid <= 31); - DPRINTF("xhci_kick_ep(%d, %d)\n", slotid, epid); if (!xhci->slots[slotid-1].enabled) { fprintf(stderr, "xhci: xhci_kick_ep for disabled slot %d\n", slotid); @@ -1684,15 +1674,13 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid XHCITransfer *xfer = epctx->retry; int result; - DPRINTF("xhci: retry nack'ed transfer ...\n"); + trace_usb_xhci_xfer_retry(xfer); assert(xfer->running_retry); xhci_setup_packet(xfer, xfer->packet.ep->dev); result = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); if (result == USB_RET_NAK) { - DPRINTF("xhci: ... xfer still nacked\n"); return; } - DPRINTF("xhci: ... result %d\n", result); xhci_complete_packet(xfer, result); assert(!xfer->running_retry); epctx->retry = NULL; @@ -1708,21 +1696,14 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid while (1) { XHCITransfer *xfer = &epctx->transfers[epctx->next_xfer]; if (xfer->running_async || xfer->running_retry || xfer->backgrounded) { - DPRINTF("xhci: ep is busy (#%d,%d,%d,%d)\n", - epctx->next_xfer, xfer->running_async, - xfer->running_retry, xfer->backgrounded); break; - } else { - DPRINTF("xhci: ep: using #%d\n", epctx->next_xfer); } length = xhci_ring_chain_length(xhci, &epctx->ring); if (length < 0) { - DPRINTF("xhci: incomplete TD (%d TRBs)\n", -length); break; } else if (length == 0) { break; } - DPRINTF("xhci: fetching %d-TRB TD\n", length); if (xfer->trbs && xfer->trb_alloced < length) { xfer->trb_count = 0; xfer->trb_alloced = 0; @@ -1757,7 +1738,6 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid } if (epctx->state == EP_HALTED) { - DPRINTF("xhci: ep halted, stopping schedule\n"); break; } if (xfer->running_retry) { @@ -1770,8 +1750,8 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid static TRBCCode xhci_enable_slot(XHCIState *xhci, unsigned int slotid) { + trace_usb_xhci_slot_enable(slotid); assert(slotid >= 1 && slotid <= MAXSLOTS); - DPRINTF("xhci_enable_slot(%d)\n", slotid); xhci->slots[slotid-1].enabled = 1; xhci->slots[slotid-1].port = 0; memset(xhci->slots[slotid-1].eps, 0, sizeof(XHCIEPContext*)*31); @@ -1783,8 +1763,8 @@ static TRBCCode xhci_disable_slot(XHCIState *xhci, unsigned int slotid) { int i; + trace_usb_xhci_slot_disable(slotid); assert(slotid >= 1 && slotid <= MAXSLOTS); - DPRINTF("xhci_disable_slot(%d)\n", slotid); for (i = 1; i <= 31; i++) { if (xhci->slots[slotid-1].eps[i-1]) { @@ -1810,8 +1790,8 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid, int i; TRBCCode res; + trace_usb_xhci_slot_address(slotid); assert(slotid >= 1 && slotid <= MAXSLOTS); - DPRINTF("xhci_address_slot(%d)\n", slotid); dcbaap = xhci_addr64(xhci->dcbaap_low, xhci->dcbaap_high); pci_dma_read(&xhci->pci_dev, dcbaap + 8*slotid, &poctx, sizeof(poctx)); @@ -1897,8 +1877,8 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid, int i; TRBCCode res; + trace_usb_xhci_slot_configure(slotid); assert(slotid >= 1 && slotid <= MAXSLOTS); - DPRINTF("xhci_configure_slot(%d)\n", slotid); ictx = xhci_mask64(pictx); octx = xhci->slots[slotid-1].ctx; @@ -1985,8 +1965,8 @@ static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid, uint32_t islot_ctx[4]; uint32_t slot_ctx[4]; + trace_usb_xhci_slot_evaluate(slotid); assert(slotid >= 1 && slotid <= MAXSLOTS); - DPRINTF("xhci_evaluate_slot(%d)\n", slotid); ictx = xhci_mask64(pictx); octx = xhci->slots[slotid-1].ctx; @@ -2048,8 +2028,8 @@ static TRBCCode xhci_reset_slot(XHCIState *xhci, unsigned int slotid) dma_addr_t octx; int i; + trace_usb_xhci_slot_reset(slotid); assert(slotid >= 1 && slotid <= MAXSLOTS); - DPRINTF("xhci_reset_slot(%d)\n", slotid); octx = xhci->slots[slotid-1].ctx; @@ -2296,12 +2276,12 @@ static void xhci_update_port(XHCIState *xhci, XHCIPort *port, int is_detach) } } -static void xhci_reset(void *opaque) +static void xhci_reset(DeviceState *dev) { - XHCIState *xhci = opaque; + XHCIState *xhci = DO_UPCAST(XHCIState, pci_dev.qdev, dev); int i; - DPRINTF("xhci: full reset\n"); + trace_usb_xhci_reset(); if (!(xhci->usbsts & USBSTS_HCH)) { fprintf(stderr, "xhci: reset while running!\n"); } @@ -2342,77 +2322,98 @@ static void xhci_reset(void *opaque) static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg) { - DPRINTF("xhci_cap_read(0x%x)\n", reg); + uint32_t ret; switch (reg) { case 0x00: /* HCIVERSION, CAPLENGTH */ - return 0x01000000 | LEN_CAP; + ret = 0x01000000 | LEN_CAP; + break; case 0x04: /* HCSPARAMS 1 */ - return (MAXPORTS<<24) | (MAXINTRS<<8) | MAXSLOTS; + ret = (MAXPORTS<<24) | (MAXINTRS<<8) | MAXSLOTS; + break; case 0x08: /* HCSPARAMS 2 */ - return 0x0000000f; + ret = 0x0000000f; + break; case 0x0c: /* HCSPARAMS 3 */ - return 0x00000000; + ret = 0x00000000; + break; case 0x10: /* HCCPARAMS */ -#if TARGET_PHYS_ADDR_BITS > 32 - return 0x00081001; -#else - return 0x00081000; -#endif + if (sizeof(dma_addr_t) == 4) { + ret = 0x00081000; + } else { + ret = 0x00081001; + } + break; case 0x14: /* DBOFF */ - return OFF_DOORBELL; + ret = OFF_DOORBELL; + break; case 0x18: /* RTSOFF */ - return OFF_RUNTIME; + ret = OFF_RUNTIME; + break; /* extended capabilities */ case 0x20: /* Supported Protocol:00 */ -#if USB3_PORTS > 0 - return 0x02000402; /* USB 2.0 */ -#else - return 0x02000002; /* USB 2.0 */ -#endif + ret = 0x02000402; /* USB 2.0 */ + break; case 0x24: /* Supported Protocol:04 */ - return 0x20425455; /* "USB " */ + ret = 0x20425455; /* "USB " */ + break; case 0x28: /* Supported Protocol:08 */ - return 0x00000001 | (USB2_PORTS<<8); + ret = 0x00000001 | (USB2_PORTS<<8); + break; case 0x2c: /* Supported Protocol:0c */ - return 0x00000000; /* reserved */ -#if USB3_PORTS > 0 + ret = 0x00000000; /* reserved */ + break; case 0x30: /* Supported Protocol:00 */ - return 0x03000002; /* USB 3.0 */ + ret = 0x03000002; /* USB 3.0 */ + break; case 0x34: /* Supported Protocol:04 */ - return 0x20425455; /* "USB " */ + ret = 0x20425455; /* "USB " */ + break; case 0x38: /* Supported Protocol:08 */ - return 0x00000000 | (USB2_PORTS+1) | (USB3_PORTS<<8); + ret = 0x00000000 | (USB2_PORTS+1) | (USB3_PORTS<<8); + break; case 0x3c: /* Supported Protocol:0c */ - return 0x00000000; /* reserved */ -#endif + ret = 0x00000000; /* reserved */ + break; default: fprintf(stderr, "xhci_cap_read: reg %d unimplemented\n", reg); + ret = 0; } - return 0; + + trace_usb_xhci_cap_read(reg, ret); + return ret; } static uint32_t xhci_port_read(XHCIState *xhci, uint32_t reg) { uint32_t port = reg >> 4; + uint32_t ret; + if (port >= MAXPORTS) { fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port); - return 0; + ret = 0; + goto out; } switch (reg & 0xf) { case 0x00: /* PORTSC */ - return xhci->ports[port].portsc; + ret = xhci->ports[port].portsc; + break; case 0x04: /* PORTPMSC */ case 0x08: /* PORTLI */ - return 0; + ret = 0; + break; case 0x0c: /* reserved */ default: fprintf(stderr, "xhci_port_read (port %d): reg 0x%x unimplemented\n", port, reg); - return 0; + ret = 0; } + +out: + trace_usb_xhci_port_read(port, reg & 0x0f, ret); + return ret; } static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val) @@ -2420,6 +2421,8 @@ static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val) uint32_t port = reg >> 4; uint32_t portsc; + trace_usb_xhci_port_write(port, reg & 0x0f, val); + if (port >= MAXPORTS) { fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port); return; @@ -2457,7 +2460,7 @@ static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val) static uint32_t xhci_oper_read(XHCIState *xhci, uint32_t reg) { - DPRINTF("xhci_oper_read(0x%x)\n", reg); + uint32_t ret; if (reg >= 0x400) { return xhci_port_read(xhci, reg - 0x400); @@ -2465,38 +2468,50 @@ static uint32_t xhci_oper_read(XHCIState *xhci, uint32_t reg) switch (reg) { case 0x00: /* USBCMD */ - return xhci->usbcmd; + ret = xhci->usbcmd; + break; case 0x04: /* USBSTS */ - return xhci->usbsts; + ret = xhci->usbsts; + break; case 0x08: /* PAGESIZE */ - return 1; /* 4KiB */ + ret = 1; /* 4KiB */ + break; case 0x14: /* DNCTRL */ - return xhci->dnctrl; + ret = xhci->dnctrl; + break; case 0x18: /* CRCR low */ - return xhci->crcr_low & ~0xe; + ret = xhci->crcr_low & ~0xe; + break; case 0x1c: /* CRCR high */ - return xhci->crcr_high; + ret = xhci->crcr_high; + break; case 0x30: /* DCBAAP low */ - return xhci->dcbaap_low; + ret = xhci->dcbaap_low; + break; case 0x34: /* DCBAAP high */ - return xhci->dcbaap_high; + ret = xhci->dcbaap_high; + break; case 0x38: /* CONFIG */ - return xhci->config; + ret = xhci->config; + break; default: fprintf(stderr, "xhci_oper_read: reg 0x%x unimplemented\n", reg); + ret = 0; } - return 0; + + trace_usb_xhci_oper_read(reg, ret); + return ret; } static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) { - DPRINTF("xhci_oper_write(0x%x, 0x%08x)\n", reg, val); - if (reg >= 0x400) { xhci_port_write(xhci, reg - 0x400, val); return; } + trace_usb_xhci_oper_write(reg, val); + switch (reg) { case 0x00: /* USBCMD */ if ((val & USBCMD_RS) && !(xhci->usbcmd & USBCMD_RS)) { @@ -2506,7 +2521,7 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) } xhci->usbcmd = val & 0xc0f; if (val & USBCMD_HCRST) { - xhci_reset(xhci); + xhci_reset(&xhci->pci_dev.qdev); } xhci_irq_update(xhci); break; @@ -2552,35 +2567,46 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg) { - DPRINTF("xhci_runtime_read(0x%x)\n", reg); + uint32_t ret; switch (reg) { case 0x00: /* MFINDEX */ fprintf(stderr, "xhci_runtime_read: MFINDEX not yet implemented\n"); - return xhci->mfindex; + ret = xhci->mfindex; + break; case 0x20: /* IMAN */ - return xhci->iman; + ret = xhci->iman; + break; case 0x24: /* IMOD */ - return xhci->imod; + ret = xhci->imod; + break; case 0x28: /* ERSTSZ */ - return xhci->erstsz; + ret = xhci->erstsz; + break; case 0x30: /* ERSTBA low */ - return xhci->erstba_low; + ret = xhci->erstba_low; + break; case 0x34: /* ERSTBA high */ - return xhci->erstba_high; + ret = xhci->erstba_high; + break; case 0x38: /* ERDP low */ - return xhci->erdp_low; + ret = xhci->erdp_low; + break; case 0x3c: /* ERDP high */ - return xhci->erdp_high; + ret = xhci->erdp_high; + break; default: fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n", reg); + ret = 0; } - return 0; + + trace_usb_xhci_runtime_read(reg, ret); + return ret; } static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val) { - DPRINTF("xhci_runtime_write(0x%x, 0x%08x)\n", reg, val); + trace_usb_xhci_runtime_read(reg, val); switch (reg) { case 0x20: /* IMAN */ @@ -2623,14 +2649,14 @@ static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val) static uint32_t xhci_doorbell_read(XHCIState *xhci, uint32_t reg) { - DPRINTF("xhci_doorbell_read(0x%x)\n", reg); /* doorbells always read as 0 */ + trace_usb_xhci_doorbell_read(reg, 0); return 0; } static void xhci_doorbell_write(XHCIState *xhci, uint32_t reg, uint32_t val) { - DPRINTF("xhci_doorbell_write(0x%x, 0x%08x)\n", reg, val); + trace_usb_xhci_doorbell_write(reg, val); if (!xhci_running(xhci)) { fprintf(stderr, "xhci: wrote doorbell while xHC stopped or paused\n"); @@ -2831,8 +2857,6 @@ static void usb_xhci_init(XHCIState *xhci, DeviceState *dev) for (i = 0; i < MAXSLOTS; i++) { xhci->slots[i].enabled = 0; } - - qemu_register_reset(xhci_reset, xhci); } static int usb_xhci_initfn(struct PCIDevice *dev) @@ -2895,6 +2919,7 @@ static void xhci_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_xhci; dc->props = xhci_properties; + dc->reset = xhci_reset; k->init = usb_xhci_initfn; k->vendor_id = PCI_VENDOR_ID_NEC; k->device_id = PCI_DEVICE_ID_NEC_UPD720200; diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 7c79c54..4fd5d9b 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -173,7 +173,7 @@ static void versatile_init(ram_addr_t ram_size, const char *initrd_filename, const char *cpu_model, int board_id) { - CPUARMState *env; + ARMCPU *cpu; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); qemu_irq *cpu_pic; @@ -189,10 +189,11 @@ static void versatile_init(ram_addr_t ram_size, int done_smc = 0; DriveInfo *dinfo; - if (!cpu_model) + if (!cpu_model) { cpu_model = "arm926"; - env = cpu_init(cpu_model); - if (!env) { + } + cpu = cpu_arm_init(cpu_model); + if (!cpu) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } @@ -208,7 +209,7 @@ static void versatile_init(ram_addr_t ram_size, qdev_init_nofail(sysctl); sysbus_mmio_map(sysbus_from_qdev(sysctl), 0, 0x10000000); - cpu_pic = arm_pic_init_cpu(env); + cpu_pic = arm_pic_init_cpu(cpu); dev = sysbus_create_varargs("pl190", 0x10140000, cpu_pic[0], cpu_pic[1], NULL); for (n = 0; n < 32; n++) { @@ -338,7 +339,7 @@ static void versatile_init(ram_addr_t ram_size, versatile_binfo.kernel_cmdline = kernel_cmdline; versatile_binfo.initrd_filename = initrd_filename; versatile_binfo.board_id = board_id; - arm_load_kernel(env, &versatile_binfo); + arm_load_kernel(cpu, &versatile_binfo); } static void vpb_init(ram_addr_t ram_size, diff --git a/hw/vexpress.c b/hw/vexpress.c index 18d87ac..8072c5a 100644 --- a/hw/vexpress.c +++ b/hw/vexpress.c @@ -159,7 +159,6 @@ static void a9_daughterboard_init(const VEDBoardInfo *daughterboard, const char *cpu_model, qemu_irq *pic, uint32_t *proc_id) { - CPUARMState *env = NULL; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); MemoryRegion *lowram = g_new(MemoryRegion, 1); @@ -177,12 +176,12 @@ static void a9_daughterboard_init(const VEDBoardInfo *daughterboard, *proc_id = 0x0c000191; for (n = 0; n < smp_cpus; n++) { - env = cpu_init(cpu_model); - if (!env) { + ARMCPU *cpu = cpu_arm_init(cpu_model); + if (!cpu) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - irqp = arm_pic_init_cpu(env); + irqp = arm_pic_init_cpu(cpu); cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; } @@ -259,7 +258,6 @@ static void a15_daughterboard_init(const VEDBoardInfo *daughterboard, qemu_irq *pic, uint32_t *proc_id) { int n; - CPUARMState *env = NULL; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); MemoryRegion *sram = g_new(MemoryRegion, 1); @@ -274,13 +272,15 @@ static void a15_daughterboard_init(const VEDBoardInfo *daughterboard, *proc_id = 0x14000217; for (n = 0; n < smp_cpus; n++) { + ARMCPU *cpu; qemu_irq *irqp; - env = cpu_init(cpu_model); - if (!env) { + + cpu = cpu_arm_init(cpu_model); + if (!cpu) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - irqp = arm_pic_init_cpu(env); + irqp = arm_pic_init_cpu(cpu); cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; } @@ -438,7 +438,7 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard, vexpress_binfo.smp_loader_start = map[VE_SRAM]; vexpress_binfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30; vexpress_binfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr; - arm_load_kernel(first_cpu, &vexpress_binfo); + arm_load_kernel(arm_env_get_cpu(first_cpu), &vexpress_binfo); } static void vexpress_a9_init(ram_addr_t ram_size, diff --git a/hw/xen_disk.c b/hw/xen_disk.c index 07594bc..de7e8a4 100644 --- a/hw/xen_disk.c +++ b/hw/xen_disk.c @@ -537,6 +537,15 @@ static void blk_bh(void *opaque) blk_handle_requests(blkdev); } +/* + * We need to account for the grant allocations requiring contiguous + * chunks; the worst case number would be + * max_req * max_seg + (max_req - 1) * (max_seg - 1) + 1, + * but in order to keep things simple just use + * 2 * max_req * max_seg. + */ +#define MAX_GRANTS(max_req, max_seg) (2 * (max_req) * (max_seg)) + static void blk_alloc(struct XenDevice *xendev) { struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); @@ -548,6 +557,11 @@ static void blk_alloc(struct XenDevice *xendev) if (xen_mode != XEN_EMULATE) { batch_maps = 1; } + if (xc_gnttab_set_max_grants(xendev->gnttabdev, + MAX_GRANTS(max_requests, BLKIF_MAX_SEGMENTS_PER_REQUEST)) < 0) { + xen_be_printf(xendev, 0, "xc_gnttab_set_max_grants failed: %s\n", + strerror(errno)); + } } static int blk_init(struct XenDevice *xendev) diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c index 7eee770..4b72aa7 100644 --- a/hw/xen_machine_pv.c +++ b/hw/xen_machine_pv.c @@ -36,6 +36,7 @@ static void xen_init_pv(ram_addr_t ram_size, const char *initrd_filename, const char *cpu_model) { + X86CPU *cpu; CPUX86State *env; DriveInfo *dinfo; int i; @@ -48,7 +49,8 @@ static void xen_init_pv(ram_addr_t ram_size, cpu_model = "qemu32"; #endif } - env = cpu_init(cpu_model); + cpu = cpu_x86_init(cpu_model); + env = &cpu->env; env->halted = 1; /* Initialize backend core & drivers */ diff --git a/hw/xilinx_zynq.c b/hw/xilinx_zynq.c index 7290c64..7e6c273 100644 --- a/hw/xilinx_zynq.c +++ b/hw/xilinx_zynq.c @@ -50,7 +50,7 @@ static void zynq_init(ram_addr_t ram_size, const char *boot_device, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { - CPUARMState *env = NULL; + ARMCPU *cpu; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ext_ram = g_new(MemoryRegion, 1); MemoryRegion *ocm_ram = g_new(MemoryRegion, 1); @@ -66,12 +66,12 @@ static void zynq_init(ram_addr_t ram_size, const char *boot_device, cpu_model = "cortex-a9"; } - env = cpu_init(cpu_model); - if (!env) { + cpu = cpu_arm_init(cpu_model); + if (!cpu) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - irqp = arm_pic_init_cpu(env); + irqp = arm_pic_init_cpu(cpu); cpu_irq = irqp[ARM_PIC_CPU_IRQ]; /* max 2GB ram */ @@ -137,7 +137,7 @@ static void zynq_init(ram_addr_t ram_size, const char *boot_device, zynq_binfo.nb_cpus = 1; zynq_binfo.board_id = 0xd32; zynq_binfo.loader_start = 0; - arm_load_kernel(first_cpu, &zynq_binfo); + arm_load_kernel(arm_env_get_cpu(first_cpu), &zynq_binfo); } static QEMUMachine zynq_machine = { @@ -301,7 +301,7 @@ static void z2_init(ram_addr_t ram_size, { MemoryRegion *address_space_mem = get_system_memory(); uint32_t sector_len = 0x10000; - PXA2xxState *cpu; + PXA2xxState *mpu; DriveInfo *dinfo; int be; void *z2_lcd; @@ -313,7 +313,7 @@ static void z2_init(ram_addr_t ram_size, } /* Setup CPU & memory */ - cpu = pxa270_init(address_space_mem, z2_binfo.ram_size, cpu_model); + mpu = pxa270_init(address_space_mem, z2_binfo.ram_size, cpu_model); #ifdef TARGET_WORDS_BIGENDIAN be = 1; @@ -337,25 +337,25 @@ static void z2_init(ram_addr_t ram_size, } /* setup keypad */ - pxa27x_register_keypad(cpu->kp, map, 0x100); + pxa27x_register_keypad(mpu->kp, map, 0x100); /* MMC/SD host */ - pxa2xx_mmci_handlers(cpu->mmc, + pxa2xx_mmci_handlers(mpu->mmc, NULL, - qdev_get_gpio_in(cpu->gpio, Z2_GPIO_SD_DETECT)); + qdev_get_gpio_in(mpu->gpio, Z2_GPIO_SD_DETECT)); type_register_static(&zipit_lcd_info); type_register_static(&aer915_info); - z2_lcd = ssi_create_slave(cpu->ssp[1], "zipit-lcd"); - bus = pxa2xx_i2c_bus(cpu->i2c[0]); + z2_lcd = ssi_create_slave(mpu->ssp[1], "zipit-lcd"); + bus = pxa2xx_i2c_bus(mpu->i2c[0]); i2c_create_slave(bus, "aer915", 0x55); wm = i2c_create_slave(bus, "wm8750", 0x1b); - cpu->i2s->opaque = wm; - cpu->i2s->codec_out = wm8750_dac_dat; - cpu->i2s->codec_in = wm8750_adc_dat; - wm8750_data_req_set(wm, cpu->i2s->data_req, cpu->i2s); + mpu->i2s->opaque = wm; + mpu->i2s->codec_out = wm8750_dac_dat; + mpu->i2s->codec_in = wm8750_adc_dat; + wm8750_data_req_set(wm, mpu->i2s->data_req, mpu->i2s); - qdev_connect_gpio_out(cpu->gpio, Z2_GPIO_LCD_CS, + qdev_connect_gpio_out(mpu->gpio, Z2_GPIO_LCD_CS, qemu_allocate_irqs(z2_lcd_cs, z2_lcd, 1)[0]); if (kernel_filename) { @@ -363,7 +363,7 @@ static void z2_init(ram_addr_t ram_size, z2_binfo.kernel_cmdline = kernel_cmdline; z2_binfo.initrd_filename = initrd_filename; z2_binfo.board_id = 0x6dd; - arm_load_kernel(&cpu->cpu->env, &z2_binfo); + arm_load_kernel(mpu->cpu, &z2_binfo); } } diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c index a4e088c..ffffbf7 100644 --- a/qapi/qapi-visit-core.c +++ b/qapi/qapi-visit-core.c @@ -97,6 +97,145 @@ void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp) } } +void visit_type_uint8(Visitor *v, uint8_t *obj, const char *name, Error **errp) +{ + int64_t value; + if (!error_is_set(errp)) { + if (v->type_uint8) { + v->type_uint8(v, obj, name, errp); + } else { + value = *obj; + v->type_int(v, &value, name, errp); + if (value < 0 || value > UINT8_MAX) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", + "uint8_t"); + return; + } + *obj = value; + } + } +} + +void visit_type_uint16(Visitor *v, uint16_t *obj, const char *name, Error **errp) +{ + int64_t value; + if (!error_is_set(errp)) { + if (v->type_uint16) { + v->type_uint16(v, obj, name, errp); + } else { + value = *obj; + v->type_int(v, &value, name, errp); + if (value < 0 || value > UINT16_MAX) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", + "uint16_t"); + return; + } + *obj = value; + } + } +} + +void visit_type_uint32(Visitor *v, uint32_t *obj, const char *name, Error **errp) +{ + int64_t value; + if (!error_is_set(errp)) { + if (v->type_uint32) { + v->type_uint32(v, obj, name, errp); + } else { + value = *obj; + v->type_int(v, &value, name, errp); + if (value < 0 || value > UINT32_MAX) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", + "uint32_t"); + return; + } + *obj = value; + } + } +} + +void visit_type_uint64(Visitor *v, uint64_t *obj, const char *name, Error **errp) +{ + int64_t value; + if (!error_is_set(errp)) { + if (v->type_uint64) { + v->type_uint64(v, obj, name, errp); + } else { + value = *obj; + v->type_int(v, &value, name, errp); + *obj = value; + } + } +} + +void visit_type_int8(Visitor *v, int8_t *obj, const char *name, Error **errp) +{ + int64_t value; + if (!error_is_set(errp)) { + if (v->type_int8) { + v->type_int8(v, obj, name, errp); + } else { + value = *obj; + v->type_int(v, &value, name, errp); + if (value < INT8_MIN || value > INT8_MAX) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", + "int8_t"); + return; + } + *obj = value; + } + } +} + +void visit_type_int16(Visitor *v, int16_t *obj, const char *name, Error **errp) +{ + int64_t value; + if (!error_is_set(errp)) { + if (v->type_int16) { + v->type_int16(v, obj, name, errp); + } else { + value = *obj; + v->type_int(v, &value, name, errp); + if (value < INT16_MIN || value > INT16_MAX) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", + "int16_t"); + return; + } + *obj = value; + } + } +} + +void visit_type_int32(Visitor *v, int32_t *obj, const char *name, Error **errp) +{ + int64_t value; + if (!error_is_set(errp)) { + if (v->type_int32) { + v->type_int32(v, obj, name, errp); + } else { + value = *obj; + v->type_int(v, &value, name, errp); + if (value < INT32_MIN || value > INT32_MAX) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", + "int32_t"); + return; + } + *obj = value; + } + } +} + +void visit_type_int64(Visitor *v, int64_t *obj, const char *name, Error **errp) +{ + if (!error_is_set(errp)) { + if (v->type_int64) { + v->type_int64(v, obj, name, errp); + } else { + v->type_int(v, obj, name, errp); + } + } +} + void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp) { if (!error_is_set(errp)) { diff --git a/qapi/qapi-visit-core.h b/qapi/qapi-visit-core.h index e850746..a19d70c 100644 --- a/qapi/qapi-visit-core.h +++ b/qapi/qapi-visit-core.h @@ -52,6 +52,14 @@ struct Visitor void (*start_handle)(Visitor *v, void **obj, const char *kind, const char *name, Error **errp); void (*end_handle)(Visitor *v, Error **errp); + void (*type_uint8)(Visitor *v, uint8_t *obj, const char *name, Error **errp); + void (*type_uint16)(Visitor *v, uint16_t *obj, const char *name, Error **errp); + void (*type_uint32)(Visitor *v, uint32_t *obj, const char *name, Error **errp); + void (*type_uint64)(Visitor *v, uint64_t *obj, const char *name, Error **errp); + void (*type_int8)(Visitor *v, int8_t *obj, const char *name, Error **errp); + void (*type_int16)(Visitor *v, int16_t *obj, const char *name, Error **errp); + void (*type_int32)(Visitor *v, int32_t *obj, const char *name, Error **errp); + void (*type_int64)(Visitor *v, int64_t *obj, const char *name, Error **errp); }; void visit_start_handle(Visitor *v, void **obj, const char *kind, @@ -69,6 +77,14 @@ void visit_end_optional(Visitor *v, Error **errp); void visit_type_enum(Visitor *v, int *obj, const char *strings[], const char *kind, const char *name, Error **errp); void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp); +void visit_type_uint8(Visitor *v, uint8_t *obj, const char *name, Error **errp); +void visit_type_uint16(Visitor *v, uint16_t *obj, const char *name, Error **errp); +void visit_type_uint32(Visitor *v, uint32_t *obj, const char *name, Error **errp); +void visit_type_uint64(Visitor *v, uint64_t *obj, const char *name, Error **errp); +void visit_type_int8(Visitor *v, int8_t *obj, const char *name, Error **errp); +void visit_type_int16(Visitor *v, int16_t *obj, const char *name, Error **errp); +void visit_type_int32(Visitor *v, int32_t *obj, const char *name, Error **errp); +void visit_type_int64(Visitor *v, int64_t *obj, const char *name, Error **errp); void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp); void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp); void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp); diff --git a/qapi/string-output-visitor.c b/qapi/string-output-visitor.c index 92b0305..34e525e 100644 --- a/qapi/string-output-visitor.c +++ b/qapi/string-output-visitor.c @@ -52,7 +52,7 @@ static void print_type_number(Visitor *v, double *obj, const char *name, Error **errp) { StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v); - string_output_set(sov, g_strdup_printf("%g", *obj)); + string_output_set(sov, g_strdup_printf("%f", *obj)); } char *string_output_get_string(StringOutputVisitor *sov) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 388bc5c..0b61162 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -723,66 +723,32 @@ static void x86_cpuid_get_level(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { X86CPU *cpu = X86_CPU(obj); - int64_t value; - value = cpu->env.cpuid_level; - /* TODO Use visit_type_uint32() once available */ - visit_type_int(v, &value, name, errp); + visit_type_uint32(v, &cpu->env.cpuid_level, name, errp); } static void x86_cpuid_set_level(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { X86CPU *cpu = X86_CPU(obj); - const int64_t min = 0; - const int64_t max = UINT32_MAX; - int64_t value; - - /* TODO Use visit_type_uint32() once available */ - visit_type_int(v, &value, name, errp); - if (error_is_set(errp)) { - return; - } - if (value < min || value > max) { - error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "", - name ? name : "null", value, min, max); - return; - } - cpu->env.cpuid_level = value; + visit_type_uint32(v, &cpu->env.cpuid_level, name, errp); } static void x86_cpuid_get_xlevel(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { X86CPU *cpu = X86_CPU(obj); - int64_t value; - value = cpu->env.cpuid_xlevel; - /* TODO Use visit_type_uint32() once available */ - visit_type_int(v, &value, name, errp); + visit_type_uint32(v, &cpu->env.cpuid_xlevel, name, errp); } static void x86_cpuid_set_xlevel(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { X86CPU *cpu = X86_CPU(obj); - const int64_t min = 0; - const int64_t max = UINT32_MAX; - int64_t value; - - /* TODO Use visit_type_uint32() once available */ - visit_type_int(v, &value, name, errp); - if (error_is_set(errp)) { - return; - } - if (value < min || value > max) { - error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "", - name ? name : "null", value, min, max); - return; - } - cpu->env.cpuid_xlevel = value; + visit_type_uint32(v, &cpu->env.cpuid_xlevel, name, errp); } static char *x86_cpuid_get_vendor(Object *obj, Error **errp) diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index f183213..619b202 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -20,7 +20,7 @@ * <http://www.gnu.org/licenses/lgpl-2.1.html> */ -#include "cpu-qom.h" +#include "cpu.h" #include "qemu-common.h" #include "qemu-timer.h" diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 2f3f394..c30ac3a 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -105,6 +105,8 @@ typedef struct CPUS390XState { QEMUTimer *cpu_timer; } CPUS390XState; +#include "cpu-qom.h" + #if defined(CONFIG_USER_ONLY) static inline void cpu_clone_regs(CPUS390XState *env, target_ulong newsp) { @@ -271,7 +273,7 @@ static inline int get_ilc(uint8_t opc) #define ILC_LATER_INC_2 0x22 -CPUS390XState *cpu_s390x_init(const char *cpu_model); +S390CPU *cpu_s390x_init(const char *cpu_model); void s390x_translate_init(void); int cpu_s390x_exec(CPUS390XState *s); void cpu_s390x_close(CPUS390XState *s); @@ -314,7 +316,7 @@ static inline void kvm_s390_interrupt_internal(CPUS390XState *env, int type, { } #endif -CPUS390XState *s390_cpu_addr2state(uint16_t cpu_addr); +S390CPU *s390_cpu_addr2state(uint16_t cpu_addr); void s390_add_running_cpu(CPUS390XState *env); unsigned s390_del_running_cpu(CPUS390XState *env); @@ -340,7 +342,7 @@ static inline void cpu_set_tls(CPUS390XState *env, target_ulong newtls) env->aregs[1] = newtls & 0xffffffffULL; } -#define cpu_init cpu_s390x_init +#define cpu_init(model) (&cpu_s390x_init(model)->env) #define cpu_exec cpu_s390x_exec #define cpu_gen_code cpu_s390x_gen_code #define cpu_signal_handler cpu_s390x_signal_handler @@ -994,6 +996,4 @@ static inline void cpu_pc_from_tb(CPUS390XState *env, TranslationBlock* tb) env->psw.addr = tb->pc; } -#include "cpu-qom.h" - #endif diff --git a/target-s390x/helper.c b/target-s390x/helper.c index a34a35b..d0a1180 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -70,7 +70,7 @@ void s390x_cpu_timer(void *opaque) } #endif -CPUS390XState *cpu_s390x_init(const char *cpu_model) +S390CPU *cpu_s390x_init(const char *cpu_model) { S390CPU *cpu; CPUS390XState *env; @@ -86,7 +86,7 @@ CPUS390XState *cpu_s390x_init(const char *cpu_model) env->cpu_model_str = cpu_model; qemu_init_vcpu(env); - return env; + return cpu; } #if defined(CONFIG_USER_ONLY) diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 90aad61..5800fd6 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -292,8 +292,10 @@ static int handle_diag(CPUS390XState *env, struct kvm_run *run, int ipb_code) return r; } -static int s390_cpu_restart(CPUS390XState *env) +static int s390_cpu_restart(S390CPU *cpu) { + CPUS390XState *env = &cpu->env; + kvm_s390_interrupt(env, KVM_S390_RESTART, 0); s390_add_running_cpu(env); qemu_cpu_kick(env); @@ -333,6 +335,7 @@ static int handle_sigp(CPUS390XState *env, struct kvm_run *run, uint8_t ipa1) uint16_t cpu_addr; uint8_t t; int r = -1; + S390CPU *target_cpu; CPUS390XState *target_env; cpu_synchronize_state(env); @@ -353,14 +356,15 @@ static int handle_sigp(CPUS390XState *env, struct kvm_run *run, uint8_t ipa1) parameter = env->regs[t] & 0x7ffffe00; cpu_addr = env->regs[ipa1 & 0x0f]; - target_env = s390_cpu_addr2state(cpu_addr); - if (!target_env) { + target_cpu = s390_cpu_addr2state(cpu_addr); + if (target_cpu == NULL) { goto out; } + target_env = &target_cpu->env; switch (order_code) { case SIGP_RESTART: - r = s390_cpu_restart(target_env); + r = s390_cpu_restart(target_cpu); break; case SIGP_STORE_STATUS_ADDR: r = s390_store_status(target_env, parameter); diff --git a/tests/Makefile b/tests/Makefile index 2e754c3..d66ab19 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -13,6 +13,7 @@ check-unit-y += tests/test-qmp-commands$(EXESUF) check-unit-y += tests/test-string-input-visitor$(EXESUF) check-unit-y += tests/test-string-output-visitor$(EXESUF) check-unit-y += tests/test-coroutine$(EXESUF) +check-unit-y += tests/test-visitor-serialization$(EXESUF) check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh @@ -31,7 +32,7 @@ test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \ tests/test-coroutine.o tests/test-string-output-visitor.o \ tests/test-string-input-visitor.o tests/test-qmp-output-visitor.o \ tests/test-qmp-input-visitor.o tests/test-qmp-input-strict.o \ - tests/test-qmp-commands.o + tests/test-qmp-commands.o tests/test-visitor-serialization.o test-qapi-obj-y = $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) test-qapi-obj-y += tests/test-qapi-visit.o tests/test-qapi-types.o @@ -64,6 +65,7 @@ tests/test-qmp-output-visitor$(EXESUF): tests/test-qmp-output-visitor.o $(test-q tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qapi-obj-y) tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y) tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y) +tests/test-visitor-serialization$(EXESUF): tests/test-visitor-serialization.o $(test-qapi-obj-y) tests/rtc-test$(EXESUF): tests/rtc-test.o $(trace-obj-y) tests/m48t59-test$(EXESUF): tests/m48t59-test.o $(trace-obj-y) diff --git a/tests/test-string-output-visitor.c b/tests/test-string-output-visitor.c index 22909b8..608f14a 100644 --- a/tests/test-string-output-visitor.c +++ b/tests/test-string-output-visitor.c @@ -84,7 +84,7 @@ static void test_visitor_out_number(TestOutputVisitorData *data, str = string_output_get_string(data->sov); g_assert(str != NULL); - g_assert_cmpstr(str, ==, "3.14"); + g_assert_cmpstr(str, ==, "3.140000"); g_free(str); } diff --git a/tests/test-visitor-serialization.c b/tests/test-visitor-serialization.c new file mode 100644 index 0000000..b8ad16f --- /dev/null +++ b/tests/test-visitor-serialization.c @@ -0,0 +1,784 @@ +/* + * Unit-tests for visitor-based serialization + * + * Copyright IBM, Corp. 2012 + * + * Authors: + * Michael Roth <mdroth@linux.vnet.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include <glib.h> +#include <stdlib.h> +#include <stdint.h> +#include <float.h> +#include "test-qapi-types.h" +#include "test-qapi-visit.h" +#include "qemu-objects.h" +#include "qapi/qmp-input-visitor.h" +#include "qapi/qmp-output-visitor.h" +#include "qapi/string-input-visitor.h" +#include "qapi/string-output-visitor.h" + +typedef struct PrimitiveType { + union { + const char *string; + bool boolean; + double number; + int64_t integer; + uint8_t u8; + uint16_t u16; + uint32_t u32; + uint64_t u64; + int8_t s8; + int16_t s16; + int32_t s32; + int64_t s64; + intmax_t max; + } value; + enum { + PTYPE_STRING = 0, + PTYPE_BOOLEAN, + PTYPE_NUMBER, + PTYPE_INTEGER, + PTYPE_U8, + PTYPE_U16, + PTYPE_U32, + PTYPE_U64, + PTYPE_S8, + PTYPE_S16, + PTYPE_S32, + PTYPE_S64, + PTYPE_EOL, + } type; + const char *description; +} PrimitiveType; + +/* test helpers */ + +static void visit_primitive_type(Visitor *v, void **native, Error **errp) +{ + PrimitiveType *pt = *native; + switch(pt->type) { + case PTYPE_STRING: + visit_type_str(v, (char **)&pt->value.string, NULL, errp); + break; + case PTYPE_BOOLEAN: + visit_type_bool(v, &pt->value.boolean, NULL, errp); + break; + case PTYPE_NUMBER: + visit_type_number(v, &pt->value.number, NULL, errp); + break; + case PTYPE_INTEGER: + visit_type_int(v, &pt->value.integer, NULL, errp); + break; + case PTYPE_U8: + visit_type_uint8(v, &pt->value.u8, NULL, errp); + break; + case PTYPE_U16: + visit_type_uint16(v, &pt->value.u16, NULL, errp); + break; + case PTYPE_U32: + visit_type_uint32(v, &pt->value.u32, NULL, errp); + break; + case PTYPE_U64: + visit_type_uint64(v, &pt->value.u64, NULL, errp); + break; + case PTYPE_S8: + visit_type_int8(v, &pt->value.s8, NULL, errp); + break; + case PTYPE_S16: + visit_type_int16(v, &pt->value.s16, NULL, errp); + break; + case PTYPE_S32: + visit_type_int32(v, &pt->value.s32, NULL, errp); + break; + case PTYPE_S64: + visit_type_int64(v, &pt->value.s64, NULL, errp); + break; + case PTYPE_EOL: + g_assert(false); + } +} + +typedef struct TestStruct +{ + int64_t integer; + bool boolean; + char *string; +} TestStruct; + +static void visit_type_TestStruct(Visitor *v, TestStruct **obj, + const char *name, Error **errp) +{ + visit_start_struct(v, (void **)obj, NULL, name, sizeof(TestStruct), errp); + + visit_type_int(v, &(*obj)->integer, "integer", errp); + visit_type_bool(v, &(*obj)->boolean, "boolean", errp); + visit_type_str(v, &(*obj)->string, "string", errp); + + visit_end_struct(v, errp); +} + +static TestStruct *struct_create(void) +{ + TestStruct *ts = g_malloc0(sizeof(*ts)); + ts->integer = -42; + ts->boolean = true; + ts->string = strdup("test string"); + return ts; +} + +static void struct_compare(TestStruct *ts1, TestStruct *ts2) +{ + g_assert(ts1); + g_assert(ts2); + g_assert_cmpint(ts1->integer, ==, ts2->integer); + g_assert(ts1->boolean == ts2->boolean); + g_assert_cmpstr(ts1->string, ==, ts2->string); +} + +static void struct_cleanup(TestStruct *ts) +{ + g_free(ts->string); + g_free(ts); +} + +static void visit_struct(Visitor *v, void **native, Error **errp) +{ + visit_type_TestStruct(v, (TestStruct **)native, NULL, errp); +} + +static UserDefNested *nested_struct_create(void) +{ + UserDefNested *udnp = g_malloc0(sizeof(*udnp)); + udnp->string0 = strdup("test_string0"); + udnp->dict1.string1 = strdup("test_string1"); + udnp->dict1.dict2.userdef1 = g_malloc0(sizeof(UserDefOne)); + udnp->dict1.dict2.userdef1->integer = 42; + udnp->dict1.dict2.userdef1->string = strdup("test_string"); + udnp->dict1.dict2.string2 = strdup("test_string2"); + udnp->dict1.has_dict3 = true; + udnp->dict1.dict3.userdef2 = g_malloc0(sizeof(UserDefOne)); + udnp->dict1.dict3.userdef2->integer = 43; + udnp->dict1.dict3.userdef2->string = strdup("test_string"); + udnp->dict1.dict3.string3 = strdup("test_string3"); + return udnp; +} + +static void nested_struct_compare(UserDefNested *udnp1, UserDefNested *udnp2) +{ + g_assert(udnp1); + g_assert(udnp2); + g_assert_cmpstr(udnp1->string0, ==, udnp2->string0); + g_assert_cmpstr(udnp1->dict1.string1, ==, udnp2->dict1.string1); + g_assert_cmpint(udnp1->dict1.dict2.userdef1->integer, ==, + udnp2->dict1.dict2.userdef1->integer); + g_assert_cmpstr(udnp1->dict1.dict2.userdef1->string, ==, + udnp2->dict1.dict2.userdef1->string); + g_assert_cmpstr(udnp1->dict1.dict2.string2, ==, udnp2->dict1.dict2.string2); + g_assert(udnp1->dict1.has_dict3 == udnp2->dict1.has_dict3); + g_assert_cmpint(udnp1->dict1.dict3.userdef2->integer, ==, + udnp2->dict1.dict3.userdef2->integer); + g_assert_cmpstr(udnp1->dict1.dict3.userdef2->string, ==, + udnp2->dict1.dict3.userdef2->string); + g_assert_cmpstr(udnp1->dict1.dict3.string3, ==, udnp2->dict1.dict3.string3); +} + +static void nested_struct_cleanup(UserDefNested *udnp) +{ + qapi_free_UserDefNested(udnp); +} + +static void visit_nested_struct(Visitor *v, void **native, Error **errp) +{ + visit_type_UserDefNested(v, (UserDefNested **)native, NULL, errp); +} + +static void visit_nested_struct_list(Visitor *v, void **native, Error **errp) +{ + visit_type_UserDefNestedList(v, (UserDefNestedList **)native, NULL, errp); +} + +/* test cases */ + +typedef void (*VisitorFunc)(Visitor *v, void **native, Error **errp); + +typedef enum VisitorCapabilities { + VCAP_PRIMITIVES = 1, + VCAP_STRUCTURES = 2, + VCAP_LISTS = 4, +} VisitorCapabilities; + +typedef struct SerializeOps { + void (*serialize)(void *native_in, void **datap, + VisitorFunc visit, Error **errp); + void (*deserialize)(void **native_out, void *datap, + VisitorFunc visit, Error **errp); + void (*cleanup)(void *datap); + const char *type; + VisitorCapabilities caps; +} SerializeOps; + +typedef struct TestArgs { + const SerializeOps *ops; + void *test_data; +} TestArgs; + +#define FLOAT_STRING_PRECISION 6 /* corresponding to n in %.nf formatting */ +static gsize calc_float_string_storage(double value) +{ + int whole_value = value; + gsize i = 0; + do { + i++; + } while (whole_value /= 10); + return i + 2 + FLOAT_STRING_PRECISION; +} + +static void test_primitives(gconstpointer opaque) +{ + TestArgs *args = (TestArgs *) opaque; + const SerializeOps *ops = args->ops; + PrimitiveType *pt = args->test_data; + PrimitiveType *pt_copy = g_malloc0(sizeof(*pt_copy)); + Error *err = NULL; + void *serialize_data; + char *double1, *double2; + + pt_copy->type = pt->type; + ops->serialize(pt, &serialize_data, visit_primitive_type, &err); + ops->deserialize((void **)&pt_copy, serialize_data, visit_primitive_type, &err); + + g_assert(err == NULL); + g_assert(pt_copy != NULL); + if (pt->type == PTYPE_STRING) { + g_assert_cmpstr(pt->value.string, ==, pt_copy->value.string); + } else if (pt->type == PTYPE_NUMBER) { + /* we serialize with %f for our reference visitors, so rather than fuzzy + * floating math to test "equality", just compare the formatted values + */ + double1 = g_malloc0(calc_float_string_storage(pt->value.number)); + double2 = g_malloc0(calc_float_string_storage(pt_copy->value.number)); + g_assert_cmpstr(double1, ==, double2); + g_free(double1); + g_free(double2); + } else if (pt->type == PTYPE_BOOLEAN) { + g_assert_cmpint(!!pt->value.max, ==, !!pt->value.max); + } else { + g_assert_cmpint(pt->value.max, ==, pt_copy->value.max); + } + + ops->cleanup(serialize_data); + g_free(args); +} + +static void test_struct(gconstpointer opaque) +{ + TestArgs *args = (TestArgs *) opaque; + const SerializeOps *ops = args->ops; + TestStruct *ts = struct_create(); + TestStruct *ts_copy = NULL; + Error *err = NULL; + void *serialize_data; + + ops->serialize(ts, &serialize_data, visit_struct, &err); + ops->deserialize((void **)&ts_copy, serialize_data, visit_struct, &err); + + g_assert(err == NULL); + struct_compare(ts, ts_copy); + + struct_cleanup(ts); + struct_cleanup(ts_copy); + + ops->cleanup(serialize_data); + g_free(args); +} + +static void test_nested_struct(gconstpointer opaque) +{ + TestArgs *args = (TestArgs *) opaque; + const SerializeOps *ops = args->ops; + UserDefNested *udnp = nested_struct_create(); + UserDefNested *udnp_copy = NULL; + Error *err = NULL; + void *serialize_data; + + ops->serialize(udnp, &serialize_data, visit_nested_struct, &err); + ops->deserialize((void **)&udnp_copy, serialize_data, visit_nested_struct, &err); + + g_assert(err == NULL); + nested_struct_compare(udnp, udnp_copy); + + nested_struct_cleanup(udnp); + nested_struct_cleanup(udnp_copy); + + ops->cleanup(serialize_data); + g_free(args); +} + +static void test_nested_struct_list(gconstpointer opaque) +{ + TestArgs *args = (TestArgs *) opaque; + const SerializeOps *ops = args->ops; + UserDefNestedList *listp = NULL, *tmp, *tmp_copy, *listp_copy = NULL; + Error *err = NULL; + void *serialize_data; + int i = 0; + + for (i = 0; i < 8; i++) { + tmp = g_malloc0(sizeof(UserDefNestedList)); + tmp->value = nested_struct_create(); + tmp->next = listp; + listp = tmp; + } + + ops->serialize(listp, &serialize_data, visit_nested_struct_list, &err); + ops->deserialize((void **)&listp_copy, serialize_data, + visit_nested_struct_list, &err); + + g_assert(err == NULL); + + tmp = listp; + tmp_copy = listp_copy; + while (listp_copy) { + g_assert(listp); + nested_struct_compare(listp->value, listp_copy->value); + listp = listp->next; + listp_copy = listp_copy->next; + } + + qapi_free_UserDefNestedList(tmp); + qapi_free_UserDefNestedList(tmp_copy); + + ops->cleanup(serialize_data); + g_free(args); +} + +PrimitiveType pt_values[] = { + /* string tests */ + { + .description = "string_empty", + .type = PTYPE_STRING, + .value.string = "", + }, + { + .description = "string_whitespace", + .type = PTYPE_STRING, + .value.string = "a b c\td", + }, + { + .description = "string_newlines", + .type = PTYPE_STRING, + .value.string = "a\nb\n", + }, + { + .description = "string_commas", + .type = PTYPE_STRING, + .value.string = "a,b, c,d", + }, + { + .description = "string_single_quoted", + .type = PTYPE_STRING, + .value.string = "'a b',cd", + }, + { + .description = "string_double_quoted", + .type = PTYPE_STRING, + .value.string = "\"a b\",cd", + }, + /* boolean tests */ + { + .description = "boolean_true1", + .type = PTYPE_BOOLEAN, + .value.boolean = true, + }, + { + .description = "boolean_true2", + .type = PTYPE_BOOLEAN, + .value.boolean = 8, + }, + { + .description = "boolean_true3", + .type = PTYPE_BOOLEAN, + .value.boolean = -1, + }, + { + .description = "boolean_false1", + .type = PTYPE_BOOLEAN, + .value.boolean = false, + }, + { + .description = "boolean_false2", + .type = PTYPE_BOOLEAN, + .value.boolean = 0, + }, + /* number tests (double) */ + /* note: we format these to %.6f before comparing, since that's how + * we serialize them and it doesn't make sense to check precision + * beyond that. + */ + { + .description = "number_sanity1", + .type = PTYPE_NUMBER, + .value.number = -1, + }, + { + .description = "number_sanity2", + .type = PTYPE_NUMBER, + .value.number = 3.14159265, + }, + { + .description = "number_min", + .type = PTYPE_NUMBER, + .value.number = DBL_MIN, + }, + { + .description = "number_max", + .type = PTYPE_NUMBER, + .value.number = DBL_MAX, + }, + /* integer tests (int64) */ + { + .description = "integer_sanity1", + .type = PTYPE_INTEGER, + .value.integer = -1, + }, + { + .description = "integer_sanity2", + .type = PTYPE_INTEGER, + .value.integer = INT64_MAX / 2 + 1, + }, + { + .description = "integer_min", + .type = PTYPE_INTEGER, + .value.integer = INT64_MIN, + }, + { + .description = "integer_max", + .type = PTYPE_INTEGER, + .value.integer = INT64_MAX, + }, + /* uint8 tests */ + { + .description = "uint8_sanity1", + .type = PTYPE_U8, + .value.u8 = 1, + }, + { + .description = "uint8_sanity2", + .type = PTYPE_U8, + .value.u8 = UINT8_MAX / 2 + 1, + }, + { + .description = "uint8_min", + .type = PTYPE_U8, + .value.u8 = 0, + }, + { + .description = "uint8_max", + .type = PTYPE_U8, + .value.u8 = UINT8_MAX, + }, + /* uint16 tests */ + { + .description = "uint16_sanity1", + .type = PTYPE_U16, + .value.u16 = 1, + }, + { + .description = "uint16_sanity2", + .type = PTYPE_U16, + .value.u16 = UINT16_MAX / 2 + 1, + }, + { + .description = "uint16_min", + .type = PTYPE_U16, + .value.u16 = 0, + }, + { + .description = "uint16_max", + .type = PTYPE_U16, + .value.u16 = UINT16_MAX, + }, + /* uint32 tests */ + { + .description = "uint32_sanity1", + .type = PTYPE_U32, + .value.u32 = 1, + }, + { + .description = "uint32_sanity2", + .type = PTYPE_U32, + .value.u32 = UINT32_MAX / 2 + 1, + }, + { + .description = "uint32_min", + .type = PTYPE_U32, + .value.u32 = 0, + }, + { + .description = "uint32_max", + .type = PTYPE_U32, + .value.u32 = UINT32_MAX, + }, + /* uint64 tests */ + { + .description = "uint64_sanity1", + .type = PTYPE_U64, + .value.u64 = 1, + }, + { + .description = "uint64_sanity2", + .type = PTYPE_U64, + .value.u64 = UINT64_MAX / 2 + 1, + }, + { + .description = "uint64_min", + .type = PTYPE_U64, + .value.u64 = 0, + }, + { + .description = "uint64_max", + .type = PTYPE_U64, + .value.u64 = UINT64_MAX, + }, + /* int8 tests */ + { + .description = "int8_sanity1", + .type = PTYPE_S8, + .value.s8 = -1, + }, + { + .description = "int8_sanity2", + .type = PTYPE_S8, + .value.s8 = INT8_MAX / 2 + 1, + }, + { + .description = "int8_min", + .type = PTYPE_S8, + .value.s8 = INT8_MIN, + }, + { + .description = "int8_max", + .type = PTYPE_S8, + .value.s8 = INT8_MAX, + }, + /* int16 tests */ + { + .description = "int16_sanity1", + .type = PTYPE_S16, + .value.s16 = -1, + }, + { + .description = "int16_sanity2", + .type = PTYPE_S16, + .value.s16 = INT16_MAX / 2 + 1, + }, + { + .description = "int16_min", + .type = PTYPE_S16, + .value.s16 = INT16_MIN, + }, + { + .description = "int16_max", + .type = PTYPE_S16, + .value.s16 = INT16_MAX, + }, + /* int32 tests */ + { + .description = "int32_sanity1", + .type = PTYPE_S32, + .value.s32 = -1, + }, + { + .description = "int32_sanity2", + .type = PTYPE_S32, + .value.s32 = INT32_MAX / 2 + 1, + }, + { + .description = "int32_min", + .type = PTYPE_S32, + .value.s32 = INT32_MIN, + }, + { + .description = "int32_max", + .type = PTYPE_S32, + .value.s32 = INT32_MAX, + }, + /* int64 tests */ + { + .description = "int64_sanity1", + .type = PTYPE_S64, + .value.s64 = -1, + }, + { + .description = "int64_sanity2", + .type = PTYPE_S64, + .value.s64 = INT64_MAX / 2 + 1, + }, + { + .description = "int64_min", + .type = PTYPE_S64, + .value.s64 = INT64_MIN, + }, + { + .description = "int64_max", + .type = PTYPE_S64, + .value.s64 = INT64_MAX, + }, + { .type = PTYPE_EOL } +}; + +/* visitor-specific op implementations */ + +typedef struct QmpSerializeData { + QmpOutputVisitor *qov; + QmpInputVisitor *qiv; +} QmpSerializeData; + +static void qmp_serialize(void *native_in, void **datap, + VisitorFunc visit, Error **errp) +{ + QmpSerializeData *d = g_malloc0(sizeof(*d)); + + d->qov = qmp_output_visitor_new(); + visit(qmp_output_get_visitor(d->qov), &native_in, errp); + *datap = d; +} + +static void qmp_deserialize(void **native_out, void *datap, + VisitorFunc visit, Error **errp) +{ + QmpSerializeData *d = datap; + QString *output_json = qobject_to_json(qmp_output_get_qobject(d->qov)); + QObject *obj = qobject_from_json(qstring_get_str(output_json)); + + QDECREF(output_json); + d->qiv = qmp_input_visitor_new(obj); + visit(qmp_input_get_visitor(d->qiv), native_out, errp); +} + +static void qmp_cleanup(void *datap) +{ + QmpSerializeData *d = datap; + qmp_output_visitor_cleanup(d->qov); + qmp_input_visitor_cleanup(d->qiv); +} + +typedef struct StringSerializeData { + StringOutputVisitor *sov; + StringInputVisitor *siv; +} StringSerializeData; + +static void string_serialize(void *native_in, void **datap, + VisitorFunc visit, Error **errp) +{ + StringSerializeData *d = g_malloc0(sizeof(*d)); + + d->sov = string_output_visitor_new(); + visit(string_output_get_visitor(d->sov), &native_in, errp); + *datap = d; +} + +static void string_deserialize(void **native_out, void *datap, + VisitorFunc visit, Error **errp) +{ + StringSerializeData *d = datap; + + d->siv = string_input_visitor_new(string_output_get_string(d->sov)); + visit(string_input_get_visitor(d->siv), native_out, errp); +} + +static void string_cleanup(void *datap) +{ + StringSerializeData *d = datap; + string_output_visitor_cleanup(d->sov); + string_input_visitor_cleanup(d->siv); +} + +/* visitor registration, test harness */ + +/* note: to function interchangeably as a serialization mechanism your + * visitor test implementation should pass the test cases for all visitor + * capabilities: primitives, structures, and lists + */ +static const SerializeOps visitors[] = { + { + .type = "QMP", + .serialize = qmp_serialize, + .deserialize = qmp_deserialize, + .cleanup = qmp_cleanup, + .caps = VCAP_PRIMITIVES | VCAP_STRUCTURES | VCAP_LISTS + }, + { + .type = "String", + .serialize = string_serialize, + .deserialize = string_deserialize, + .cleanup = string_cleanup, + .caps = VCAP_PRIMITIVES + }, + { NULL } +}; + +static void add_visitor_type(const SerializeOps *ops) +{ + char testname_prefix[128]; + char testname[128]; + TestArgs *args; + int i = 0; + + sprintf(testname_prefix, "/visitor/serialization/%s", ops->type); + + if (ops->caps & VCAP_PRIMITIVES) { + while (pt_values[i].type != PTYPE_EOL) { + sprintf(testname, "%s/primitives/%s", testname_prefix, + pt_values[i].description); + args = g_malloc0(sizeof(*args)); + args->ops = ops; + args->test_data = &pt_values[i]; + g_test_add_data_func(testname, args, test_primitives); + i++; + } + } + + if (ops->caps & VCAP_STRUCTURES) { + sprintf(testname, "%s/struct", testname_prefix); + args = g_malloc0(sizeof(*args)); + args->ops = ops; + args->test_data = NULL; + g_test_add_data_func(testname, args, test_struct); + + sprintf(testname, "%s/nested_struct", testname_prefix); + args = g_malloc0(sizeof(*args)); + args->ops = ops; + args->test_data = NULL; + g_test_add_data_func(testname, args, test_nested_struct); + } + + if (ops->caps & VCAP_LISTS) { + sprintf(testname, "%s/nested_struct_list", testname_prefix); + args = g_malloc0(sizeof(*args)); + args->ops = ops; + args->test_data = NULL; + g_test_add_data_func(testname, args, test_nested_struct_list); + } +} + +int main(int argc, char **argv) +{ + int i = 0; + + g_test_init(&argc, &argv, NULL); + + while (visitors[i].type != NULL) { + add_visitor_type(&visitors[i]); + i++; + } + + g_test_run(); + + return 0; +} diff --git a/trace-events b/trace-events index 45c6bc1..f70523c 100644 --- a/trace-events +++ b/trace-events @@ -257,19 +257,20 @@ usb_ehci_port_detach(uint32_t port) "detach port #%d" usb_ehci_port_reset(uint32_t port, int enable) "reset port #%d - %d" usb_ehci_data(int rw, uint32_t cpage, uint32_t offset, uint32_t addr, uint32_t len, uint32_t bufpos) "write %d, cpage %d, offset 0x%03x, addr 0x%08x, len %d, bufpos %d" usb_ehci_queue_action(void *q, const char *action) "q %p: %s" +usb_ehci_packet_action(void *q, void *p, const char *action) "q %p p %p: %s" # hw/usb/hcd-uhci.c usb_uhci_reset(void) "=== RESET ===" usb_uhci_schedule_start(void) "" usb_uhci_schedule_stop(void) "" usb_uhci_frame_start(uint32_t num) "nr %d" +usb_uhci_frame_stop_bandwidth(void) "" usb_uhci_frame_loop_stop_idle(void) "" -usb_uhci_frame_loop_stop_bandwidth(void) "" usb_uhci_frame_loop_continue(void) "" -usb_uhci_mmio_readw(uint32_t addr, uint32_t val) "addr %04x, ret 0x04%x" -usb_uhci_mmio_writew(uint32_t addr, uint32_t val) "addr %04x, val 0x04%x" -usb_uhci_mmio_readl(uint32_t addr, uint32_t val) "addr %04x, ret 0x08%x" -usb_uhci_mmio_writel(uint32_t addr, uint32_t val) "addr %04x, val 0x08%x" +usb_uhci_mmio_readw(uint32_t addr, uint32_t val) "addr 0x%04x, ret 0x%04x" +usb_uhci_mmio_writew(uint32_t addr, uint32_t val) "addr 0x%04x, val 0x%04x" +usb_uhci_mmio_readl(uint32_t addr, uint32_t val) "addr 0x%04x, ret 0x%08x" +usb_uhci_mmio_writel(uint32_t addr, uint32_t val) "addr 0x%04x, val 0x%08x" usb_uhci_queue_add(uint32_t token) "token 0x%x" usb_uhci_queue_del(uint32_t token) "token 0x%x" usb_uhci_packet_add(uint32_t token, uint32_t addr) "token 0x%x, td 0x%x" @@ -289,6 +290,41 @@ usb_uhci_td_nextqh(uint32_t qh, uint32_t td) "qh 0x%x, td 0x%x" usb_uhci_td_async(uint32_t qh, uint32_t td) "qh 0x%x, td 0x%x" usb_uhci_td_complete(uint32_t qh, uint32_t td) "qh 0x%x, td 0x%x" +# hw/usb/hcd-xhci.c +usb_xhci_reset(void) "=== RESET ===" +usb_xhci_run(void) "" +usb_xhci_stop(void) "" +usb_xhci_cap_read(uint32_t off, uint32_t val) "off 0x%04x, ret 0x%08x" +usb_xhci_oper_read(uint32_t off, uint32_t val) "off 0x%04x, ret 0x%08x" +usb_xhci_port_read(uint32_t port, uint32_t off, uint32_t val) "port %d, off 0x%04x, ret 0x%08x" +usb_xhci_runtime_read(uint32_t off, uint32_t val) "off 0x%04x, ret 0x%08x" +usb_xhci_doorbell_read(uint32_t off, uint32_t val) "off 0x%04x, ret 0x%08x" +usb_xhci_oper_write(uint32_t off, uint32_t val) "off 0x%04x, val 0x%08x" +usb_xhci_port_write(uint32_t port, uint32_t off, uint32_t val) "port %d, off 0x%04x, val 0x%08x" +usb_xhci_runtime_write(uint32_t off, uint32_t val) "off 0x%04x, val 0x%08x" +usb_xhci_doorbell_write(uint32_t off, uint32_t val) "off 0x%04x, val 0x%08x" +usb_xhci_irq_intx(uint32_t level) "level %d" +usb_xhci_irq_msi(uint32_t nr) "nr %d" +usb_xhci_queue_event(uint32_t idx, const char *name, uint64_t param, uint32_t status, uint32_t control) "idx %d, %s, p %016" PRIx64 ", s %08x, c 0x%08x" +usb_xhci_fetch_trb(uint64_t addr, const char *name, uint64_t param, uint32_t status, uint32_t control) "addr %016" PRIx64 ", %s, p %016" PRIx64 ", s %08x, c 0x%08x" +usb_xhci_slot_enable(uint32_t slotid) "slotid %d" +usb_xhci_slot_disable(uint32_t slotid) "slotid %d" +usb_xhci_slot_address(uint32_t slotid) "slotid %d" +usb_xhci_slot_configure(uint32_t slotid) "slotid %d" +usb_xhci_slot_evaluate(uint32_t slotid) "slotid %d" +usb_xhci_slot_reset(uint32_t slotid) "slotid %d" +usb_xhci_ep_enable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" +usb_xhci_ep_disable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" +usb_xhci_ep_kick(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" +usb_xhci_ep_stop(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" +usb_xhci_ep_reset(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" +usb_xhci_xfer_start(void *xfer, uint32_t slotid, uint32_t epid, uint32_t length) "%p: slotid %d, epid %d, length %d" +usb_xhci_xfer_async(void *xfer) "%p" +usb_xhci_xfer_nak(void *xfer) "%p" +usb_xhci_xfer_retry(void *xfer) "%p" +usb_xhci_xfer_success(void *xfer, uint32_t bytes) "%p: len %d" +usb_xhci_xfer_error(void *xfer, uint32_t ret) "%p: ret %d" + # hw/usb/desc.c usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d" usb_desc_device_qualifier(int addr, int len, int ret) "dev %d query device qualifier, len %d, ret %d" diff --git a/trace/simple.c b/trace/simple.c index 33ae486..b4a3c6e 100644 --- a/trace/simple.c +++ b/trace/simple.c @@ -161,8 +161,11 @@ static void trace(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, } timestamp = get_clock(); - +#if GLIB_CHECK_VERSION(2, 30, 0) + idx = g_atomic_int_add((gint *)&trace_idx, 1) % TRACE_BUF_LEN; +#else idx = g_atomic_int_exchange_and_add((gint *)&trace_idx, 1) % TRACE_BUF_LEN; +#endif trace_buf[idx] = (TraceRecord){ .event = event, .timestamp_ns = timestamp, |