diff options
Diffstat (limited to 'hw')
102 files changed, 3040 insertions, 1455 deletions
diff --git a/hw/alpha/dp264.c b/hw/alpha/dp264.c index 1351ba55bd..b178a03604 100644 --- a/hw/alpha/dp264.c +++ b/hw/alpha/dp264.c @@ -43,13 +43,13 @@ static int clipper_pci_map_irq(PCIDevice *d, int irq_num) return (slot + 1) * 4 + irq_num; } -static void clipper_init(QEMUMachineInitArgs *args) +static void clipper_init(MachineState *machine) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; AlphaCPU *cpus[4]; PCIBus *pci_bus; ISABus *isa_bus; diff --git a/hw/arm/collie.c b/hw/arm/collie.c index 8878b0ed9a..ed7851fe06 100644 --- a/hw/arm/collie.c +++ b/hw/arm/collie.c @@ -23,12 +23,12 @@ static struct arm_boot_info collie_binfo = { .ram_size = 0x20000000, }; -static void collie_init(QEMUMachineInitArgs *args) +static void collie_init(MachineState *machine) { - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; StrongARMState *s; DriveInfo *dinfo; MemoryRegion *sysmem = get_system_memory(); diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c index 9d158c7248..e2260e379f 100644 --- a/hw/arm/cubieboard.c +++ b/hw/arm/cubieboard.c @@ -30,7 +30,7 @@ typedef struct CubieBoardState { MemoryRegion sdram; } CubieBoardState; -static void cubieboard_init(QEMUMachineInitArgs *args) +static void cubieboard_init(MachineState *machine) { CubieBoardState *s = g_new(CubieBoardState, 1); Error *err = NULL; @@ -63,14 +63,15 @@ static void cubieboard_init(QEMUMachineInitArgs *args) exit(1); } - memory_region_init_ram(&s->sdram, NULL, "cubieboard.ram", args->ram_size); + memory_region_init_ram(&s->sdram, NULL, "cubieboard.ram", + machine->ram_size); vmstate_register_ram_global(&s->sdram); memory_region_add_subregion(get_system_memory(), AW_A10_SDRAM_BASE, &s->sdram); - cubieboard_binfo.ram_size = args->ram_size; - cubieboard_binfo.kernel_filename = args->kernel_filename; - cubieboard_binfo.kernel_cmdline = args->kernel_cmdline; + cubieboard_binfo.ram_size = machine->ram_size; + cubieboard_binfo.kernel_filename = machine->kernel_filename; + cubieboard_binfo.kernel_cmdline = machine->kernel_cmdline; arm_load_kernel(&s->a10->cpu, &cubieboard_binfo); } diff --git a/hw/arm/digic_boards.c b/hw/arm/digic_boards.c index 32fc30a69d..d1424eee20 100644 --- a/hw/arm/digic_boards.c +++ b/hw/arm/digic_boards.c @@ -143,7 +143,7 @@ static DigicBoard digic4_board_canon_a1100 = { .rom1_def_filename = "canon-a1100-rom1.bin", }; -static void canon_a1100_init(QEMUMachineInitArgs *args) +static void canon_a1100_init(MachineState *machine) { digic4_board_init(&digic4_board_canon_a1100); } diff --git a/hw/arm/exynos4_boards.c b/hw/arm/exynos4_boards.c index 26cedecee3..d644db1ef9 100644 --- a/hw/arm/exynos4_boards.c +++ b/hw/arm/exynos4_boards.c @@ -94,7 +94,7 @@ static void lan9215_init(uint32_t base, qemu_irq irq) } } -static Exynos4210State *exynos4_boards_init_common(QEMUMachineInitArgs *args, +static Exynos4210State *exynos4_boards_init_common(MachineState *machine, Exynos4BoardType board_type) { if (smp_cpus != EXYNOS4210_NCPUS && !qtest_enabled()) { @@ -108,9 +108,9 @@ static Exynos4210State *exynos4_boards_init_common(QEMUMachineInitArgs *args, exynos4_board_binfo.board_id = exynos4_board_id[board_type]; exynos4_board_binfo.smp_bootreg_addr = exynos4_board_smp_bootreg_addr[board_type]; - exynos4_board_binfo.kernel_filename = args->kernel_filename; - exynos4_board_binfo.initrd_filename = args->initrd_filename; - exynos4_board_binfo.kernel_cmdline = args->kernel_cmdline; + exynos4_board_binfo.kernel_filename = machine->kernel_filename; + exynos4_board_binfo.initrd_filename = machine->initrd_filename; + exynos4_board_binfo.kernel_cmdline = machine->kernel_cmdline; exynos4_board_binfo.gic_cpu_if_addr = EXYNOS4210_SMP_PRIVATE_BASE_ADDR + 0x100; @@ -120,24 +120,24 @@ static Exynos4210State *exynos4_boards_init_common(QEMUMachineInitArgs *args, " initrd_filename: %s\n", exynos4_board_ram_size[board_type] / 1048576, exynos4_board_ram_size[board_type], - args->kernel_filename, - args->kernel_cmdline, - args->initrd_filename); + machine->kernel_filename, + machine->kernel_cmdline, + machine->initrd_filename); return exynos4210_init(get_system_memory(), exynos4_board_ram_size[board_type]); } -static void nuri_init(QEMUMachineInitArgs *args) +static void nuri_init(MachineState *machine) { - exynos4_boards_init_common(args, EXYNOS4_BOARD_NURI); + exynos4_boards_init_common(machine, EXYNOS4_BOARD_NURI); arm_load_kernel(ARM_CPU(first_cpu), &exynos4_board_binfo); } -static void smdkc210_init(QEMUMachineInitArgs *args) +static void smdkc210_init(MachineState *machine) { - Exynos4210State *s = exynos4_boards_init_common(args, + Exynos4210State *s = exynos4_boards_init_common(machine, EXYNOS4_BOARD_SMDKC210); lan9215_init(SMDK_LAN9118_BASE_ADDR, diff --git a/hw/arm/gumstix.c b/hw/arm/gumstix.c index aeea17295b..3f8465ebc0 100644 --- a/hw/arm/gumstix.c +++ b/hw/arm/gumstix.c @@ -46,7 +46,7 @@ static const int sector_len = 128 * 1024; -static void connex_init(QEMUMachineInitArgs *args) +static void connex_init(MachineState *machine) { PXA2xxState *cpu; DriveInfo *dinfo; @@ -83,9 +83,9 @@ static void connex_init(QEMUMachineInitArgs *args) qdev_get_gpio_in(cpu->gpio, 36)); } -static void verdex_init(QEMUMachineInitArgs *args) +static void verdex_init(MachineState *machine) { - const char *cpu_model = args->cpu_model; + const char *cpu_model = machine->cpu_model; PXA2xxState *cpu; DriveInfo *dinfo; int be; diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c index 24231e5448..8340434210 100644 --- a/hw/arm/highbank.c +++ b/hw/arm/highbank.c @@ -199,13 +199,13 @@ enum cxmachines { * 32-bit host, set the reg value of memory to 0xf7ff00000 in the * device tree and pass -m 2047 to QEMU. */ -static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine) +static void calxeda_init(MachineState *machine, enum cxmachines machine_id) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; DeviceState *dev = NULL; SysBusDevice *busdev; qemu_irq pic[128]; @@ -217,7 +217,7 @@ static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine) char *sysboot_filename; if (!cpu_model) { - switch (machine) { + switch (machine_id) { case CALXEDA_HIGHBANK: cpu_model = "cortex-a9"; break; @@ -274,7 +274,7 @@ static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine) } } - switch (machine) { + switch (machine_id) { case CALXEDA_HIGHBANK: dev = qdev_create(NULL, "l2x0"); qdev_init_nofail(dev); @@ -359,14 +359,14 @@ static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine) arm_load_kernel(ARM_CPU(first_cpu), &highbank_binfo); } -static void highbank_init(QEMUMachineInitArgs *args) +static void highbank_init(MachineState *machine) { - calxeda_init(args, CALXEDA_HIGHBANK); + calxeda_init(machine, CALXEDA_HIGHBANK); } -static void midway_init(QEMUMachineInitArgs *args) +static void midway_init(MachineState *machine) { - calxeda_init(args, CALXEDA_MIDWAY); + calxeda_init(machine, CALXEDA_MIDWAY); } static QEMUMachine highbank_machine = { diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c index 912af96ee6..0e476c3db4 100644 --- a/hw/arm/integratorcp.c +++ b/hw/arm/integratorcp.c @@ -461,13 +461,13 @@ static struct arm_boot_info integrator_binfo = { .board_id = 0x113, }; -static void integratorcp_init(QEMUMachineInitArgs *args) +static void integratorcp_init(MachineState *machine) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; ARMCPU *cpu; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); diff --git a/hw/arm/kzm.c b/hw/arm/kzm.c index 99d33cb9d0..0555d12658 100644 --- a/hw/arm/kzm.c +++ b/hw/arm/kzm.c @@ -70,13 +70,13 @@ static struct arm_boot_info kzm_binfo = { .board_id = 1722, }; -static void kzm_init(QEMUMachineInitArgs *args) +static void kzm_init(MachineState *machine) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; ARMCPU *cpu; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); diff --git a/hw/arm/mainstone.c b/hw/arm/mainstone.c index d8e075e26d..44f1873106 100644 --- a/hw/arm/mainstone.c +++ b/hw/arm/mainstone.c @@ -105,7 +105,7 @@ static struct arm_boot_info mainstone_binfo = { }; static void mainstone_common_init(MemoryRegion *address_space_mem, - QEMUMachineInitArgs *args, + MachineState *machine, enum mainstone_model_e model, int arm_id) { uint32_t sector_len = 256 * 1024; @@ -116,7 +116,7 @@ static void mainstone_common_init(MemoryRegion *address_space_mem, int i; int be; MemoryRegion *rom = g_new(MemoryRegion, 1); - const char *cpu_model = args->cpu_model; + const char *cpu_model = machine->cpu_model; if (!cpu_model) cpu_model = "pxa270-c5"; @@ -175,16 +175,16 @@ static void mainstone_common_init(MemoryRegion *address_space_mem, smc91c111_init(&nd_table[0], MST_ETH_PHYS, qdev_get_gpio_in(mst_irq, ETHERNET_IRQ)); - mainstone_binfo.kernel_filename = args->kernel_filename; - mainstone_binfo.kernel_cmdline = args->kernel_cmdline; - mainstone_binfo.initrd_filename = args->initrd_filename; + mainstone_binfo.kernel_filename = machine->kernel_filename; + mainstone_binfo.kernel_cmdline = machine->kernel_cmdline; + mainstone_binfo.initrd_filename = machine->initrd_filename; mainstone_binfo.board_id = arm_id; arm_load_kernel(mpu->cpu, &mainstone_binfo); } -static void mainstone_init(QEMUMachineInitArgs *args) +static void mainstone_init(MachineState *machine) { - mainstone_common_init(get_system_memory(), args, mainstone, 0x196); + mainstone_common_init(get_system_memory(), machine, mainstone, 0x196); } static QEMUMachine mainstone2_machine = { diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index 2a27a19d76..6a134f23da 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -1569,12 +1569,12 @@ static struct arm_boot_info musicpal_binfo = { .board_id = 0x20e, }; -static void musicpal_init(QEMUMachineInitArgs *args) +static void musicpal_init(MachineState *machine) { - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; ARMCPU *cpu; qemu_irq pic[32]; DeviceState *dev; diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c index c28f895c7a..82772c657e 100644 --- a/hw/arm/nseries.c +++ b/hw/arm/nseries.c @@ -1278,14 +1278,14 @@ static int n810_atag_setup(const struct arm_boot_info *info, void *p) return n8x0_atag_setup(p, 810); } -static void n8x0_init(QEMUMachineInitArgs *args, +static void n8x0_init(MachineState *machine, struct arm_boot_info *binfo, int model) { MemoryRegion *sysmem = get_system_memory(); struct n800_s *s = (struct n800_s *) g_malloc0(sizeof(*s)); int sdram_size = binfo->ram_size; - s->mpu = omap2420_mpu_init(sysmem, sdram_size, args->cpu_model); + s->mpu = omap2420_mpu_init(sysmem, sdram_size, machine->cpu_model); /* Setup peripherals * @@ -1329,18 +1329,18 @@ static void n8x0_init(QEMUMachineInitArgs *args, n8x0_usb_setup(s); } - if (args->kernel_filename) { + if (machine->kernel_filename) { /* Or at the linux loader. */ - binfo->kernel_filename = args->kernel_filename; - binfo->kernel_cmdline = args->kernel_cmdline; - binfo->initrd_filename = args->initrd_filename; + binfo->kernel_filename = machine->kernel_filename; + binfo->kernel_cmdline = machine->kernel_cmdline; + binfo->initrd_filename = machine->initrd_filename; arm_load_kernel(s->mpu->cpu, binfo); qemu_register_reset(n8x0_boot_init, s); } if (option_rom[0].name && - (args->boot_order[0] == 'n' || !args->kernel_filename)) { + (machine->boot_order[0] == 'n' || !machine->kernel_filename)) { uint8_t nolo_tags[0x10000]; /* No, wait, better start at the ROM. */ s->mpu->cpu->env.regs[15] = OMAP2_Q2_BASE + 0x400000; @@ -1382,14 +1382,14 @@ static struct arm_boot_info n810_binfo = { .atag_board = n810_atag_setup, }; -static void n800_init(QEMUMachineInitArgs *args) +static void n800_init(MachineState *machine) { - return n8x0_init(args, &n800_binfo, 800); + return n8x0_init(machine, &n800_binfo, 800); } -static void n810_init(QEMUMachineInitArgs *args) +static void n810_init(MachineState *machine) { - return n8x0_init(args, &n810_binfo, 810); + return n8x0_init(machine, &n810_binfo, 810); } static QEMUMachine n800_machine = { diff --git a/hw/arm/omap_sx1.c b/hw/arm/omap_sx1.c index 3ba263ab4d..b4f6da6063 100644 --- a/hw/arm/omap_sx1.c +++ b/hw/arm/omap_sx1.c @@ -98,7 +98,7 @@ static struct arm_boot_info sx1_binfo = { .board_id = 0x265, }; -static void sx1_init(QEMUMachineInitArgs *args, const int version) +static void sx1_init(MachineState *machine, const int version) { struct omap_mpu_state_s *mpu; MemoryRegion *address_space = get_system_memory(); @@ -118,7 +118,8 @@ static void sx1_init(QEMUMachineInitArgs *args, const int version) flash_size = flash2_size; } - mpu = omap310_mpu_init(address_space, sx1_binfo.ram_size, args->cpu_model); + mpu = omap310_mpu_init(address_space, sx1_binfo.ram_size, + machine->cpu_model); /* External Flash (EMIFS) */ memory_region_init_ram(flash, NULL, "omap_sx1.flash0-0", flash_size); @@ -189,29 +190,29 @@ static void sx1_init(QEMUMachineInitArgs *args, const int version) OMAP_CS1_BASE, &cs[1]); } - if (!args->kernel_filename && !fl_idx && !qtest_enabled()) { + if (!machine->kernel_filename && !fl_idx && !qtest_enabled()) { fprintf(stderr, "Kernel or Flash image must be specified\n"); exit(1); } /* Load the kernel. */ - sx1_binfo.kernel_filename = args->kernel_filename; - sx1_binfo.kernel_cmdline = args->kernel_cmdline; - sx1_binfo.initrd_filename = args->initrd_filename; + sx1_binfo.kernel_filename = machine->kernel_filename; + sx1_binfo.kernel_cmdline = machine->kernel_cmdline; + sx1_binfo.initrd_filename = machine->initrd_filename; arm_load_kernel(mpu->cpu, &sx1_binfo); /* TODO: fix next line */ //~ qemu_console_resize(ds, 640, 480); } -static void sx1_init_v1(QEMUMachineInitArgs *args) +static void sx1_init_v1(MachineState *machine) { - sx1_init(args, 1); + sx1_init(machine, 1); } -static void sx1_init_v2(QEMUMachineInitArgs *args) +static void sx1_init_v2(MachineState *machine) { - sx1_init(args, 2); + sx1_init(machine, 2); } static QEMUMachine sx1_machine_v2 = { diff --git a/hw/arm/palm.c b/hw/arm/palm.c index fac4f69807..e61995f96c 100644 --- a/hw/arm/palm.c +++ b/hw/arm/palm.c @@ -191,12 +191,12 @@ static struct arm_boot_info palmte_binfo = { .board_id = 0x331, }; -static void palmte_init(QEMUMachineInitArgs *args) +static void palmte_init(MachineState *machine) { - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; MemoryRegion *address_space_mem = get_system_memory(); struct omap_mpu_state_s *mpu; int flash_size = 0x00800000; diff --git a/hw/arm/realview.c b/hw/arm/realview.c index 7e04e507f9..64b92518dd 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -45,7 +45,7 @@ static const int realview_board_id[] = { 0x76d }; -static void realview_init(QEMUMachineInitArgs *args, +static void realview_init(MachineState *machine, enum realview_board_type board_type) { ARMCPU *cpu = NULL; @@ -71,7 +71,7 @@ static void realview_init(QEMUMachineInitArgs *args, uint32_t proc_id = 0; uint32_t sys_id; ram_addr_t low_ram_size; - ram_addr_t ram_size = args->ram_size; + ram_addr_t ram_size = machine->ram_size; hwaddr periphbase = 0; switch (board_type) { @@ -91,7 +91,7 @@ static void realview_init(QEMUMachineInitArgs *args, break; } - cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, args->cpu_model); + cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, machine->cpu_model); if (!cpu_oc) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); @@ -342,45 +342,45 @@ static void realview_init(QEMUMachineInitArgs *args, memory_region_add_subregion(sysmem, SMP_BOOT_ADDR, ram_hack); realview_binfo.ram_size = ram_size; - realview_binfo.kernel_filename = args->kernel_filename; - realview_binfo.kernel_cmdline = args->kernel_cmdline; - realview_binfo.initrd_filename = args->initrd_filename; + realview_binfo.kernel_filename = machine->kernel_filename; + realview_binfo.kernel_cmdline = machine->kernel_cmdline; + realview_binfo.initrd_filename = machine->initrd_filename; 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(ARM_CPU(first_cpu), &realview_binfo); } -static void realview_eb_init(QEMUMachineInitArgs *args) +static void realview_eb_init(MachineState *machine) { - if (!args->cpu_model) { - args->cpu_model = "arm926"; + if (!machine->cpu_model) { + machine->cpu_model = "arm926"; } - realview_init(args, BOARD_EB); + realview_init(machine, BOARD_EB); } -static void realview_eb_mpcore_init(QEMUMachineInitArgs *args) +static void realview_eb_mpcore_init(MachineState *machine) { - if (!args->cpu_model) { - args->cpu_model = "arm11mpcore"; + if (!machine->cpu_model) { + machine->cpu_model = "arm11mpcore"; } - realview_init(args, BOARD_EB_MPCORE); + realview_init(machine, BOARD_EB_MPCORE); } -static void realview_pb_a8_init(QEMUMachineInitArgs *args) +static void realview_pb_a8_init(MachineState *machine) { - if (!args->cpu_model) { - args->cpu_model = "cortex-a8"; + if (!machine->cpu_model) { + machine->cpu_model = "cortex-a8"; } - realview_init(args, BOARD_PB_A8); + realview_init(machine, BOARD_PB_A8); } -static void realview_pbx_a9_init(QEMUMachineInitArgs *args) +static void realview_pbx_a9_init(MachineState *machine) { - if (!args->cpu_model) { - args->cpu_model = "cortex-a9"; + if (!machine->cpu_model) { + machine->cpu_model = "cortex-a9"; } - realview_init(args, BOARD_PBX_A9); + realview_init(machine, BOARD_PBX_A9); } static QEMUMachine realview_eb_machine = { diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index a179c1d694..5455dbf326 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -887,14 +887,14 @@ static struct arm_boot_info spitz_binfo = { .ram_size = 0x04000000, }; -static void spitz_common_init(QEMUMachineInitArgs *args, +static void spitz_common_init(MachineState *machine, enum spitz_model_e model, int arm_id) { PXA2xxState *mpu; DeviceState *scp0, *scp1 = NULL; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *rom = g_new(MemoryRegion, 1); - const char *cpu_model = args->cpu_model; + const char *cpu_model = machine->cpu_model; if (!cpu_model) cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0"; @@ -935,32 +935,32 @@ static void spitz_common_init(QEMUMachineInitArgs *args, /* A 4.0 GB microdrive is permanently sitting in CF slot 0. */ spitz_microdrive_attach(mpu, 0); - spitz_binfo.kernel_filename = args->kernel_filename; - spitz_binfo.kernel_cmdline = args->kernel_cmdline; - spitz_binfo.initrd_filename = args->initrd_filename; + spitz_binfo.kernel_filename = machine->kernel_filename; + spitz_binfo.kernel_cmdline = machine->kernel_cmdline; + spitz_binfo.initrd_filename = machine->initrd_filename; spitz_binfo.board_id = arm_id; arm_load_kernel(mpu->cpu, &spitz_binfo); sl_bootparam_write(SL_PXA_PARAM_BASE); } -static void spitz_init(QEMUMachineInitArgs *args) +static void spitz_init(MachineState *machine) { - spitz_common_init(args, spitz, 0x2c9); + spitz_common_init(machine, spitz, 0x2c9); } -static void borzoi_init(QEMUMachineInitArgs *args) +static void borzoi_init(MachineState *machine) { - spitz_common_init(args, borzoi, 0x33f); + spitz_common_init(machine, borzoi, 0x33f); } -static void akita_init(QEMUMachineInitArgs *args) +static void akita_init(MachineState *machine) { - spitz_common_init(args, akita, 0x2e8); + spitz_common_init(machine, akita, 0x2e8); } -static void terrier_init(QEMUMachineInitArgs *args) +static void terrier_init(MachineState *machine) { - spitz_common_init(args, terrier, 0x33f); + spitz_common_init(machine, terrier, 0x33f); } static QEMUMachine akitapda_machine = { diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index a2095c0e84..80028e80cf 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -1290,9 +1290,10 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, sddev = ssi_create_slave(bus, "ssi-sd"); ssddev = ssi_create_slave(bus, "ssd0323"); - gpio_out[GPIO_D][0] = qemu_irq_split(qdev_get_gpio_in(sddev, 0), - qdev_get_gpio_in(ssddev, 0)); - gpio_out[GPIO_C][7] = qdev_get_gpio_in(ssddev, 1); + gpio_out[GPIO_D][0] = qemu_irq_split( + qdev_get_gpio_in_named(sddev, SSI_GPIO_CS, 0), + qdev_get_gpio_in_named(ssddev, SSI_GPIO_CS, 0)); + gpio_out[GPIO_C][7] = qdev_get_gpio_in(ssddev, 0); /* Make sure the select pin is high. */ qemu_irq_raise(gpio_out[GPIO_D][0]); @@ -1333,17 +1334,17 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, } /* FIXME: Figure out how to generate these from stellaris_boards. */ -static void lm3s811evb_init(QEMUMachineInitArgs *args) +static void lm3s811evb_init(MachineState *machine) { - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; stellaris_init(kernel_filename, cpu_model, &stellaris_boards[0]); } -static void lm3s6965evb_init(QEMUMachineInitArgs *args) +static void lm3s6965evb_init(MachineState *machine) { - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; stellaris_init(kernel_filename, cpu_model, &stellaris_boards[1]); } diff --git a/hw/arm/tosa.c b/hw/arm/tosa.c index 2069f55432..abc0f2a96b 100644 --- a/hw/arm/tosa.c +++ b/hw/arm/tosa.c @@ -211,12 +211,12 @@ static struct arm_boot_info tosa_binfo = { .ram_size = 0x04000000, }; -static void tosa_init(QEMUMachineInitArgs *args) +static void tosa_init(MachineState *machine) { - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *rom = g_new(MemoryRegion, 1); PXA2xxState *mpu; diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c index e5493b428f..dea5fc7a95 100644 --- a/hw/arm/versatilepb.c +++ b/hw/arm/versatilepb.c @@ -173,7 +173,7 @@ static int vpb_sic_init(SysBusDevice *sbd) static struct arm_boot_info versatile_binfo; -static void versatile_init(QEMUMachineInitArgs *args, int board_id) +static void versatile_init(MachineState *machine, int board_id) { ARMCPU *cpu; MemoryRegion *sysmem = get_system_memory(); @@ -190,15 +190,15 @@ static void versatile_init(QEMUMachineInitArgs *args, int board_id) int done_smc = 0; DriveInfo *dinfo; - if (!args->cpu_model) { - args->cpu_model = "arm926"; + if (!machine->cpu_model) { + machine->cpu_model = "arm926"; } - cpu = cpu_arm_init(args->cpu_model); + cpu = cpu_arm_init(machine->cpu_model); if (!cpu) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - memory_region_init_ram(ram, NULL, "versatile.ram", args->ram_size); + memory_region_init_ram(ram, NULL, "versatile.ram", machine->ram_size); vmstate_register_ram_global(ram); /* ??? RAM should repeat to fill physical memory space. */ /* SDRAM at address zero. */ @@ -344,22 +344,22 @@ static void versatile_init(QEMUMachineInitArgs *args, int board_id) fprintf(stderr, "qemu: Error registering flash memory.\n"); } - versatile_binfo.ram_size = args->ram_size; - versatile_binfo.kernel_filename = args->kernel_filename; - versatile_binfo.kernel_cmdline = args->kernel_cmdline; - versatile_binfo.initrd_filename = args->initrd_filename; + versatile_binfo.ram_size = machine->ram_size; + versatile_binfo.kernel_filename = machine->kernel_filename; + versatile_binfo.kernel_cmdline = machine->kernel_cmdline; + versatile_binfo.initrd_filename = machine->initrd_filename; versatile_binfo.board_id = board_id; arm_load_kernel(cpu, &versatile_binfo); } -static void vpb_init(QEMUMachineInitArgs *args) +static void vpb_init(MachineState *machine) { - versatile_init(args, 0x183); + versatile_init(machine, 0x183); } -static void vab_init(QEMUMachineInitArgs *args) +static void vab_init(MachineState *machine) { - versatile_init(args, 0x25e); + versatile_init(machine, 0x25e); } static QEMUMachine versatilepb_machine = { diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index 169eb061a3..33ff422542 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -509,7 +509,7 @@ static pflash_t *ve_pflash_cfi01_register(hwaddr base, const char *name, } static void vexpress_common_init(VEDBoardInfo *daughterboard, - QEMUMachineInitArgs *args) + MachineState *machine) { DeviceState *dev, *sysctl, *pl041; qemu_irq pic[64]; @@ -525,7 +525,8 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard, const hwaddr *map = daughterboard->motherboard_map; int i; - daughterboard->init(daughterboard, args->ram_size, args->cpu_model, pic); + daughterboard->init(daughterboard, machine->ram_size, machine->cpu_model, + pic); /* Motherboard peripherals: the wiring is the same but the * addresses vary between the legacy and A-Series memory maps. @@ -639,10 +640,10 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard, pic[40 + i]); } - daughterboard->bootinfo.ram_size = args->ram_size; - daughterboard->bootinfo.kernel_filename = args->kernel_filename; - daughterboard->bootinfo.kernel_cmdline = args->kernel_cmdline; - daughterboard->bootinfo.initrd_filename = args->initrd_filename; + daughterboard->bootinfo.ram_size = machine->ram_size; + daughterboard->bootinfo.kernel_filename = machine->kernel_filename; + daughterboard->bootinfo.kernel_cmdline = machine->kernel_cmdline; + daughterboard->bootinfo.initrd_filename = machine->initrd_filename; daughterboard->bootinfo.nb_cpus = smp_cpus; daughterboard->bootinfo.board_id = VEXPRESS_BOARD_ID; daughterboard->bootinfo.loader_start = daughterboard->loader_start; @@ -653,14 +654,14 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard, arm_load_kernel(ARM_CPU(first_cpu), &daughterboard->bootinfo); } -static void vexpress_a9_init(QEMUMachineInitArgs *args) +static void vexpress_a9_init(MachineState *machine) { - vexpress_common_init(&a9_daughterboard, args); + vexpress_common_init(&a9_daughterboard, machine); } -static void vexpress_a15_init(QEMUMachineInitArgs *args) +static void vexpress_a15_init(MachineState *machine) { - vexpress_common_init(&a15_daughterboard, args); + vexpress_common_init(&a15_daughterboard, machine); } static QEMUMachine vexpress_a9_machine = { diff --git a/hw/arm/virt.c b/hw/arm/virt.c index ea4f02d32e..3b55a4bf7d 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -383,13 +383,13 @@ static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size) return board->fdt; } -static void machvirt_init(QEMUMachineInitArgs *args) +static void machvirt_init(MachineState *machine) { qemu_irq pic[NUM_IRQS]; MemoryRegion *sysmem = get_system_memory(); int n; MemoryRegion *ram = g_new(MemoryRegion, 1); - const char *cpu_model = args->cpu_model; + const char *cpu_model = machine->cpu_model; VirtBoardInfo *vbi; if (!cpu_model) { @@ -415,7 +415,7 @@ static void machvirt_init(QEMUMachineInitArgs *args) exit(1); } - if (args->ram_size > vbi->memmap[VIRT_MEM].size) { + if (machine->ram_size > vbi->memmap[VIRT_MEM].size) { error_report("mach-virt: cannot model more than 30GB RAM"); exit(1); } @@ -447,7 +447,7 @@ static void machvirt_init(QEMUMachineInitArgs *args) } fdt_add_cpu_nodes(vbi); - memory_region_init_ram(ram, NULL, "mach-virt.ram", args->ram_size); + memory_region_init_ram(ram, NULL, "mach-virt.ram", machine->ram_size); vmstate_register_ram_global(ram); memory_region_add_subregion(sysmem, vbi->memmap[VIRT_MEM].base, ram); @@ -461,10 +461,10 @@ static void machvirt_init(QEMUMachineInitArgs *args) */ create_virtio_devices(vbi, pic); - vbi->bootinfo.ram_size = args->ram_size; - vbi->bootinfo.kernel_filename = args->kernel_filename; - vbi->bootinfo.kernel_cmdline = args->kernel_cmdline; - vbi->bootinfo.initrd_filename = args->initrd_filename; + vbi->bootinfo.ram_size = machine->ram_size; + vbi->bootinfo.kernel_filename = machine->kernel_filename; + vbi->bootinfo.kernel_cmdline = machine->kernel_cmdline; + vbi->bootinfo.initrd_filename = machine->initrd_filename; vbi->bootinfo.nb_cpus = smp_cpus; vbi->bootinfo.board_id = -1; vbi->bootinfo.loader_start = vbi->memmap[VIRT_MEM].base; diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 9ee21e726a..ba5aa82cd5 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -94,20 +94,20 @@ static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq, for (j = 0; j < num_ss; ++j) { flash_dev = ssi_create_slave(spi, "n25q128"); - cs_line = qdev_get_gpio_in(flash_dev, 0); + cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); sysbus_connect_irq(busdev, i * num_ss + j + 1, cs_line); } } } -static void zynq_init(QEMUMachineInitArgs *args) +static void zynq_init(MachineState *machine) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; ObjectClass *cpu_oc; ARMCPU *cpu; MemoryRegion *address_space_mem = get_system_memory(); diff --git a/hw/arm/z2.c b/hw/arm/z2.c index 5df014b15e..ab9e4c9e79 100644 --- a/hw/arm/z2.c +++ b/hw/arm/z2.c @@ -300,12 +300,12 @@ static const TypeInfo aer915_info = { .class_init = aer915_class_init, }; -static void z2_init(QEMUMachineInitArgs *args) +static void z2_init(MachineState *machine) { - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; MemoryRegion *address_space_mem = get_system_memory(); uint32_t sector_len = 0x10000; PXA2xxState *mpu; diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c index d41f82cec4..3cfb66c5d8 100644 --- a/hw/audio/intel-hda.c +++ b/hw/audio/intel-hda.c @@ -245,7 +245,7 @@ static void intel_hda_update_int_sts(IntelHDAState *d) /* update global status */ if (sts & d->int_ctl) { - sts |= (1 << 31); + sts |= (1U << 31); } d->int_sts = sts; @@ -257,7 +257,7 @@ static void intel_hda_update_irq(IntelHDAState *d) int level; intel_hda_update_int_sts(d); - if (d->int_sts & (1 << 31) && d->int_ctl & (1 << 31)) { + if (d->int_sts & (1U << 31) && d->int_ctl & (1U << 31)) { level = 1; } else { level = 0; @@ -574,7 +574,7 @@ static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint3 if (st->ctl & 0x01) { /* reset */ dprint(d, 1, "st #%d: reset\n", reg->stream); - st->ctl = 0; + st->ctl = SD_STS_FIFO_READY << 24; } if ((st->ctl & 0x02) != (old & 0x02)) { uint32_t stnr = (st->ctl >> 20) & 0x0f; @@ -829,6 +829,7 @@ static const struct IntelHDAReg regtab[] = { .wclear = 0x1c000000, \ .offset = offsetof(IntelHDAState, st[_i].ctl), \ .whandler = intel_hda_set_st_ctl, \ + .reset = SD_STS_FIFO_READY << 24 \ }, \ [ ST_REG(_i, ICH6_REG_SD_LPIB) ] = { \ .stream = _i, \ diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index 70b8a5ab75..e49c2536b1 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -70,6 +70,9 @@ struct VirtIOBlockDataPlane { queue */ unsigned int num_reqs; + + /* Operation blocker on BDS */ + Error *blocker; }; /* Raise an interrupt to signal guest, if necessary */ @@ -350,6 +353,7 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk, { VirtIOBlockDataPlane *s; int fd; + Error *local_err = NULL; *dataplane = NULL; @@ -372,9 +376,10 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk, /* If dataplane is (re-)enabled while the guest is running there could be * block jobs that can conflict. */ - if (bdrv_in_use(blk->conf.bs)) { - error_setg(errp, - "cannot start dataplane thread while device is in use"); + if (bdrv_op_is_blocked(blk->conf.bs, BLOCK_OP_TYPE_DATAPLANE, &local_err)) { + error_report("cannot start dataplane thread: %s", + error_get_pretty(local_err)); + error_free(local_err); return; } @@ -406,8 +411,8 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk, } s->ctx = iothread_get_aio_context(s->iothread); - /* Prevent block operations that conflict with data plane thread */ - bdrv_set_in_use(blk->conf.bs, 1); + error_setg(&s->blocker, "block device is in use by data plane"); + bdrv_op_block_all(blk->conf.bs, s->blocker); *dataplane = s; } @@ -420,7 +425,8 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s) } virtio_blk_data_plane_stop(s); - bdrv_set_in_use(s->blk->conf.bs, 0); + bdrv_op_unblock_all(s->blk->conf.bs, s->blocker); + error_free(s->blocker); object_unref(OBJECT(s->iothread)); g_free(s); } diff --git a/hw/char/escc.c b/hw/char/escc.c index 6397f6f282..d9a20aa931 100644 --- a/hw/char/escc.c +++ b/hw/char/escc.c @@ -27,6 +27,7 @@ #include "hw/char/escc.h" #include "sysemu/char.h" #include "ui/console.h" +#include "ui/input.h" #include "trace.h" /* @@ -94,6 +95,7 @@ typedef struct ChannelState { ChnID chn; // this channel, A (base+4) or B (base+0) ChnType type; uint8_t rx, tx; + QemuInputHandlerState *hs; } ChannelState; #define ESCC(obj) OBJECT_CHECK(ESCCState, (obj), TYPE_ESCC) @@ -714,71 +716,181 @@ MemoryRegion *escc_init(hwaddr base, qemu_irq irqA, qemu_irq irqB, return &d->mmio; } -static const uint8_t keycodes[128] = { - 127, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 53, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 89, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 42, 99, 88, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 47, 19, 121, 119, 5, 6, 8, 10, 12, - 14, 16, 17, 18, 7, 98, 23, 68, 69, 70, 71, 91, 92, 93, 125, 112, - 113, 114, 94, 50, 0, 0, 124, 9, 11, 0, 0, 0, 0, 0, 0, 0, - 90, 0, 46, 22, 13, 111, 52, 20, 96, 24, 28, 74, 27, 123, 44, 66, - 0, 45, 2, 4, 48, 0, 0, 21, 0, 0, 0, 0, 0, 120, 122, 67, +static const uint8_t qcode_to_keycode[Q_KEY_CODE_MAX] = { + [Q_KEY_CODE_SHIFT] = 99, + [Q_KEY_CODE_SHIFT_R] = 110, + [Q_KEY_CODE_ALT] = 19, + [Q_KEY_CODE_ALT_R] = 13, + [Q_KEY_CODE_ALTGR] = 13, + [Q_KEY_CODE_CTRL] = 76, + [Q_KEY_CODE_CTRL_R] = 76, + [Q_KEY_CODE_ESC] = 29, + [Q_KEY_CODE_1] = 30, + [Q_KEY_CODE_2] = 31, + [Q_KEY_CODE_3] = 32, + [Q_KEY_CODE_4] = 33, + [Q_KEY_CODE_5] = 34, + [Q_KEY_CODE_6] = 35, + [Q_KEY_CODE_7] = 36, + [Q_KEY_CODE_8] = 37, + [Q_KEY_CODE_9] = 38, + [Q_KEY_CODE_0] = 39, + [Q_KEY_CODE_MINUS] = 40, + [Q_KEY_CODE_EQUAL] = 41, + [Q_KEY_CODE_BACKSPACE] = 43, + [Q_KEY_CODE_TAB] = 53, + [Q_KEY_CODE_Q] = 54, + [Q_KEY_CODE_W] = 55, + [Q_KEY_CODE_E] = 56, + [Q_KEY_CODE_R] = 57, + [Q_KEY_CODE_T] = 58, + [Q_KEY_CODE_Y] = 59, + [Q_KEY_CODE_U] = 60, + [Q_KEY_CODE_I] = 61, + [Q_KEY_CODE_O] = 62, + [Q_KEY_CODE_P] = 63, + [Q_KEY_CODE_BRACKET_LEFT] = 64, + [Q_KEY_CODE_BRACKET_RIGHT] = 65, + [Q_KEY_CODE_RET] = 89, + [Q_KEY_CODE_A] = 77, + [Q_KEY_CODE_S] = 78, + [Q_KEY_CODE_D] = 79, + [Q_KEY_CODE_F] = 80, + [Q_KEY_CODE_G] = 81, + [Q_KEY_CODE_H] = 82, + [Q_KEY_CODE_J] = 83, + [Q_KEY_CODE_K] = 84, + [Q_KEY_CODE_L] = 85, + [Q_KEY_CODE_SEMICOLON] = 86, + [Q_KEY_CODE_APOSTROPHE] = 87, + [Q_KEY_CODE_GRAVE_ACCENT] = 42, + [Q_KEY_CODE_BACKSLASH] = 88, + [Q_KEY_CODE_Z] = 100, + [Q_KEY_CODE_X] = 101, + [Q_KEY_CODE_C] = 102, + [Q_KEY_CODE_V] = 103, + [Q_KEY_CODE_B] = 104, + [Q_KEY_CODE_N] = 105, + [Q_KEY_CODE_M] = 106, + [Q_KEY_CODE_COMMA] = 107, + [Q_KEY_CODE_DOT] = 108, + [Q_KEY_CODE_SLASH] = 109, + [Q_KEY_CODE_ASTERISK] = 47, + [Q_KEY_CODE_SPC] = 121, + [Q_KEY_CODE_CAPS_LOCK] = 119, + [Q_KEY_CODE_F1] = 5, + [Q_KEY_CODE_F2] = 6, + [Q_KEY_CODE_F3] = 8, + [Q_KEY_CODE_F4] = 10, + [Q_KEY_CODE_F5] = 12, + [Q_KEY_CODE_F6] = 14, + [Q_KEY_CODE_F7] = 16, + [Q_KEY_CODE_F8] = 17, + [Q_KEY_CODE_F9] = 18, + [Q_KEY_CODE_F10] = 7, + [Q_KEY_CODE_NUM_LOCK] = 98, + [Q_KEY_CODE_SCROLL_LOCK] = 23, + [Q_KEY_CODE_KP_DIVIDE] = 46, + [Q_KEY_CODE_KP_MULTIPLY] = 47, + [Q_KEY_CODE_KP_SUBTRACT] = 71, + [Q_KEY_CODE_KP_ADD] = 125, + [Q_KEY_CODE_KP_ENTER] = 90, + [Q_KEY_CODE_KP_DECIMAL] = 50, + [Q_KEY_CODE_KP_0] = 94, + [Q_KEY_CODE_KP_1] = 112, + [Q_KEY_CODE_KP_2] = 113, + [Q_KEY_CODE_KP_3] = 114, + [Q_KEY_CODE_KP_4] = 91, + [Q_KEY_CODE_KP_5] = 92, + [Q_KEY_CODE_KP_6] = 93, + [Q_KEY_CODE_KP_7] = 68, + [Q_KEY_CODE_KP_8] = 69, + [Q_KEY_CODE_KP_9] = 70, + [Q_KEY_CODE_LESS] = 124, + [Q_KEY_CODE_F11] = 9, + [Q_KEY_CODE_F12] = 11, + [Q_KEY_CODE_HOME] = 52, + [Q_KEY_CODE_PGUP] = 96, + [Q_KEY_CODE_PGDN] = 123, + [Q_KEY_CODE_END] = 74, + [Q_KEY_CODE_LEFT] = 24, + [Q_KEY_CODE_UP] = 20, + [Q_KEY_CODE_DOWN] = 27, + [Q_KEY_CODE_RIGHT] = 28, + [Q_KEY_CODE_INSERT] = 44, + [Q_KEY_CODE_DELETE] = 66, + [Q_KEY_CODE_STOP] = 1, + [Q_KEY_CODE_AGAIN] = 3, + [Q_KEY_CODE_PROPS] = 25, + [Q_KEY_CODE_UNDO] = 26, + [Q_KEY_CODE_FRONT] = 49, + [Q_KEY_CODE_COPY] = 51, + [Q_KEY_CODE_OPEN] = 72, + [Q_KEY_CODE_PASTE] = 73, + [Q_KEY_CODE_FIND] = 95, + [Q_KEY_CODE_CUT] = 97, + [Q_KEY_CODE_LF] = 111, + [Q_KEY_CODE_HELP] = 118, + [Q_KEY_CODE_META_L] = 120, + [Q_KEY_CODE_META_R] = 122, + [Q_KEY_CODE_COMPOSE] = 67, + [Q_KEY_CODE_PRINT] = 22, + [Q_KEY_CODE_SYSRQ] = 21, }; -static const uint8_t e0_keycodes[128] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 76, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 109, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 68, 69, 70, 0, 91, 0, 93, 0, 112, - 113, 114, 94, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 3, 25, 26, 49, 52, 72, 73, 97, 99, 111, 118, 120, 122, 67, 0, -}; - -static void sunkbd_event(void *opaque, int ch) +static void sunkbd_handle_event(DeviceState *dev, QemuConsole *src, + InputEvent *evt) { - ChannelState *s = opaque; - int release = ch & 0x80; - - trace_escc_sunkbd_event_in(ch); - switch (ch) { - case 58: // Caps lock press - s->caps_lock_mode ^= 1; - if (s->caps_lock_mode == 2) - return; // Drop second press - break; - case 69: // Num lock press - s->num_lock_mode ^= 1; - if (s->num_lock_mode == 2) - return; // Drop second press - break; - case 186: // Caps lock release - s->caps_lock_mode ^= 2; - if (s->caps_lock_mode == 3) - return; // Drop first release - break; - case 197: // Num lock release - s->num_lock_mode ^= 2; - if (s->num_lock_mode == 3) - return; // Drop first release - break; - case 0xe0: - s->e0_mode = 1; - return; - default: - break; + ChannelState *s = (ChannelState *)dev; + int qcode, keycode; + + assert(evt->kind == INPUT_EVENT_KIND_KEY); + qcode = qemu_input_key_value_to_qcode(evt->key->key); + trace_escc_sunkbd_event_in(qcode, QKeyCode_lookup[qcode], + evt->key->down); + + if (qcode == Q_KEY_CODE_CAPS_LOCK) { + if (evt->key->down) { + s->caps_lock_mode ^= 1; + if (s->caps_lock_mode == 2) { + return; /* Drop second press */ + } + } else { + s->caps_lock_mode ^= 2; + if (s->caps_lock_mode == 3) { + return; /* Drop first release */ + } + } } - if (s->e0_mode) { - s->e0_mode = 0; - ch = e0_keycodes[ch & 0x7f]; - } else { - ch = keycodes[ch & 0x7f]; + + if (qcode == Q_KEY_CODE_NUM_LOCK) { + if (evt->key->down) { + s->num_lock_mode ^= 1; + if (s->num_lock_mode == 2) { + return; /* Drop second press */ + } + } else { + s->num_lock_mode ^= 2; + if (s->num_lock_mode == 3) { + return; /* Drop first release */ + } + } + } + + keycode = qcode_to_keycode[qcode]; + if (!evt->key->down) { + keycode |= 0x80; } - trace_escc_sunkbd_event_out(ch); - put_queue(s, ch | release); + trace_escc_sunkbd_event_out(keycode); + put_queue(s, keycode); } +static QemuInputHandler sunkbd_handler = { + .name = "sun keyboard", + .mask = INPUT_EVENT_MASK_KEY, + .event = sunkbd_handle_event, +}; + static void handle_kbd_command(ChannelState *s, int val) { trace_escc_kbd_command(val); @@ -800,7 +912,7 @@ static void handle_kbd_command(ChannelState *s, int val) case 0xf: clear_queue(s); put_queue(s, 0xfe); - put_queue(s, 0); // XXX, layout? + put_queue(s, 0x21); /* en-us layout */ break; default: break; @@ -898,7 +1010,8 @@ static int escc_init1(SysBusDevice *dev) "QEMU Sun Mouse"); } if (s->chn[1].type == kbd) { - qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]); + s->chn[1].hs = qemu_input_handler_register((DeviceState *)(&s->chn[1]), + &sunkbd_handler); } return 0; diff --git a/hw/core/machine.c b/hw/core/machine.c index d3ffef7e07..cbba6791d2 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -11,6 +11,284 @@ */ #include "hw/boards.h" +#include "qapi/visitor.h" + +static char *machine_get_accel(Object *obj, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + return g_strdup(ms->accel); +} + +static void machine_set_accel(Object *obj, const char *value, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + ms->accel = g_strdup(value); +} + +static bool machine_get_kernel_irqchip(Object *obj, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + return ms->kernel_irqchip; +} + +static void machine_set_kernel_irqchip(Object *obj, bool value, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + ms->kernel_irqchip = value; +} + +static void machine_get_kvm_shadow_mem(Object *obj, Visitor *v, + void *opaque, const char *name, + Error **errp) +{ + MachineState *ms = MACHINE(obj); + int64_t value = ms->kvm_shadow_mem; + + visit_type_int(v, &value, name, errp); +} + +static void machine_set_kvm_shadow_mem(Object *obj, Visitor *v, + void *opaque, const char *name, + Error **errp) +{ + MachineState *ms = MACHINE(obj); + Error *error = NULL; + int64_t value; + + visit_type_int(v, &value, name, &error); + if (error) { + error_propagate(errp, error); + return; + } + + ms->kvm_shadow_mem = value; +} + +static char *machine_get_kernel(Object *obj, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + return g_strdup(ms->kernel_filename); +} + +static void machine_set_kernel(Object *obj, const char *value, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + ms->kernel_filename = g_strdup(value); +} + +static char *machine_get_initrd(Object *obj, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + return g_strdup(ms->initrd_filename); +} + +static void machine_set_initrd(Object *obj, const char *value, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + ms->initrd_filename = g_strdup(value); +} + +static char *machine_get_append(Object *obj, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + return g_strdup(ms->kernel_cmdline); +} + +static void machine_set_append(Object *obj, const char *value, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + ms->kernel_cmdline = g_strdup(value); +} + +static char *machine_get_dtb(Object *obj, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + return g_strdup(ms->dtb); +} + +static void machine_set_dtb(Object *obj, const char *value, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + ms->dtb = g_strdup(value); +} + +static char *machine_get_dumpdtb(Object *obj, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + return g_strdup(ms->dumpdtb); +} + +static void machine_set_dumpdtb(Object *obj, const char *value, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + ms->dumpdtb = g_strdup(value); +} + +static void machine_get_phandle_start(Object *obj, Visitor *v, + void *opaque, const char *name, + Error **errp) +{ + MachineState *ms = MACHINE(obj); + int64_t value = ms->phandle_start; + + visit_type_int(v, &value, name, errp); +} + +static void machine_set_phandle_start(Object *obj, Visitor *v, + void *opaque, const char *name, + Error **errp) +{ + MachineState *ms = MACHINE(obj); + Error *error = NULL; + int64_t value; + + visit_type_int(v, &value, name, &error); + if (error) { + error_propagate(errp, error); + return; + } + + ms->phandle_start = value; +} + +static char *machine_get_dt_compatible(Object *obj, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + return g_strdup(ms->dt_compatible); +} + +static void machine_set_dt_compatible(Object *obj, const char *value, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + ms->dt_compatible = g_strdup(value); +} + +static bool machine_get_dump_guest_core(Object *obj, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + return ms->dump_guest_core; +} + +static void machine_set_dump_guest_core(Object *obj, bool value, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + ms->dump_guest_core = value; +} + +static bool machine_get_mem_merge(Object *obj, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + return ms->mem_merge; +} + +static void machine_set_mem_merge(Object *obj, bool value, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + ms->mem_merge = value; +} + +static bool machine_get_usb(Object *obj, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + return ms->usb; +} + +static void machine_set_usb(Object *obj, bool value, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + ms->usb = value; +} + +static char *machine_get_firmware(Object *obj, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + return g_strdup(ms->firmware); +} + +static void machine_set_firmware(Object *obj, const char *value, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + ms->firmware = g_strdup(value); +} + +static void machine_initfn(Object *obj) +{ + object_property_add_str(obj, "accel", + machine_get_accel, machine_set_accel, NULL); + object_property_add_bool(obj, "kernel_irqchip", + machine_get_kernel_irqchip, + machine_set_kernel_irqchip, + NULL); + object_property_add(obj, "kvm_shadow_mem", "int", + machine_get_kvm_shadow_mem, + machine_set_kvm_shadow_mem, + NULL, NULL, NULL); + object_property_add_str(obj, "kernel", + machine_get_kernel, machine_set_kernel, NULL); + object_property_add_str(obj, "initrd", + machine_get_initrd, machine_set_initrd, NULL); + object_property_add_str(obj, "append", + machine_get_append, machine_set_append, NULL); + object_property_add_str(obj, "dtb", + machine_get_dtb, machine_set_dtb, NULL); + object_property_add_str(obj, "dumpdtb", + machine_get_dumpdtb, machine_set_dumpdtb, NULL); + object_property_add(obj, "phandle_start", "int", + machine_get_phandle_start, + machine_set_phandle_start, + NULL, NULL, NULL); + object_property_add_str(obj, "dt_compatible", + machine_get_dt_compatible, + machine_set_dt_compatible, + NULL); + object_property_add_bool(obj, "dump-guest-core", + machine_get_dump_guest_core, + machine_set_dump_guest_core, + NULL); + object_property_add_bool(obj, "mem-merge", + machine_get_mem_merge, machine_set_mem_merge, NULL); + object_property_add_bool(obj, "usb", machine_get_usb, machine_set_usb, NULL); + object_property_add_str(obj, "firmware", + machine_get_firmware, machine_set_firmware, NULL); +} + +static void machine_finalize(Object *obj) +{ + MachineState *ms = MACHINE(obj); + + g_free(ms->accel); + g_free(ms->kernel_filename); + g_free(ms->initrd_filename); + g_free(ms->kernel_cmdline); + g_free(ms->dtb); + g_free(ms->dumpdtb); + g_free(ms->dt_compatible); + g_free(ms->firmware); +} static const TypeInfo machine_info = { .name = TYPE_MACHINE, @@ -18,6 +296,8 @@ static const TypeInfo machine_info = { .abstract = true, .class_size = sizeof(MachineClass), .instance_size = sizeof(MachineState), + .instance_init = machine_initfn, + .instance_finalize = machine_finalize, }; static void machine_register_types(void) diff --git a/hw/core/null-machine.c b/hw/core/null-machine.c index d813c089e7..1ec7c3bbe0 100644 --- a/hw/core/null-machine.c +++ b/hw/core/null-machine.c @@ -15,7 +15,7 @@ #include "hw/hw.h" #include "hw/boards.h" -static void machine_none_init(QEMUMachineInitArgs *args) +static void machine_none_init(MachineState *machine) { } diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 936eae6412..e65a5aa3a8 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -312,30 +312,82 @@ BusState *qdev_get_parent_bus(DeviceState *dev) return dev->parent_bus; } +static NamedGPIOList *qdev_get_named_gpio_list(DeviceState *dev, + const char *name) +{ + NamedGPIOList *ngl; + + QLIST_FOREACH(ngl, &dev->gpios, node) { + /* NULL is a valid and matchable name, otherwise do a normal + * strcmp match. + */ + if ((!ngl->name && !name) || + (name && ngl->name && strcmp(name, ngl->name) == 0)) { + return ngl; + } + } + + ngl = g_malloc0(sizeof(*ngl)); + ngl->name = g_strdup(name); + QLIST_INSERT_HEAD(&dev->gpios, ngl, node); + return ngl; +} + +void qdev_init_gpio_in_named(DeviceState *dev, qemu_irq_handler handler, + const char *name, int n) +{ + NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name); + + gpio_list->in = qemu_extend_irqs(gpio_list->in, gpio_list->num_in, handler, + dev, n); + gpio_list->num_in += n; +} + void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n) { - dev->gpio_in = qemu_extend_irqs(dev->gpio_in, dev->num_gpio_in, handler, - dev, n); - dev->num_gpio_in += n; + qdev_init_gpio_in_named(dev, handler, NULL, n); +} + +void qdev_init_gpio_out_named(DeviceState *dev, qemu_irq *pins, + const char *name, int n) +{ + NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name); + + assert(gpio_list->num_out == 0); + gpio_list->num_out = n; + gpio_list->out = pins; } void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n) { - assert(dev->num_gpio_out == 0); - dev->num_gpio_out = n; - dev->gpio_out = pins; + qdev_init_gpio_out_named(dev, pins, NULL, n); +} + +qemu_irq qdev_get_gpio_in_named(DeviceState *dev, const char *name, int n) +{ + NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name); + + assert(n >= 0 && n < gpio_list->num_in); + return gpio_list->in[n]; } qemu_irq qdev_get_gpio_in(DeviceState *dev, int n) { - assert(n >= 0 && n < dev->num_gpio_in); - return dev->gpio_in[n]; + return qdev_get_gpio_in_named(dev, NULL, n); +} + +void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n, + qemu_irq pin) +{ + NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name); + + assert(n >= 0 && n < gpio_list->num_out); + gpio_list->out[n] = pin; } void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin) { - assert(n >= 0 && n < dev->num_gpio_out); - dev->gpio_out[n] = pin; + qdev_connect_gpio_out_named(dev, NULL, n, pin); } BusState *qdev_get_child_bus(DeviceState *dev, const char *name) @@ -844,6 +896,7 @@ static void device_initfn(Object *obj) object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS, (Object **)&dev->parent_bus, NULL, 0, &error_abort); + QLIST_INIT(&dev->gpios); } static void device_post_init(Object *obj) @@ -854,10 +907,22 @@ static void device_post_init(Object *obj) /* Unlink device from bus and free the structure. */ static void device_finalize(Object *obj) { + NamedGPIOList *ngl, *next; + DeviceState *dev = DEVICE(obj); if (dev->opts) { qemu_opts_del(dev->opts); } + + QLIST_FOREACH_SAFE(ngl, &dev->gpios, node, next) { + QLIST_REMOVE(ngl, node); + qemu_free_irqs(ngl->in); + g_free(ngl->name); + g_free(ngl); + /* ngl->out irqs are owned by the other end and should not be freed + * here + */ + } } static void device_class_base_init(ObjectClass *class, void *data) diff --git a/hw/cris/axis_dev88.c b/hw/cris/axis_dev88.c index 645e45ccdf..1849338013 100644 --- a/hw/cris/axis_dev88.c +++ b/hw/cris/axis_dev88.c @@ -243,12 +243,12 @@ static const MemoryRegionOps gpio_ops = { static struct cris_load_info li; static -void axisdev88_init(QEMUMachineInitArgs *args) +void axisdev88_init(MachineState *machine) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; CRISCPU *cpu; CPUCRISState *env; DeviceState *dev; diff --git a/hw/display/jazz_led.c b/hw/display/jazz_led.c index e9bb005413..12b1707cb2 100644 --- a/hw/display/jazz_led.c +++ b/hw/display/jazz_led.c @@ -173,6 +173,7 @@ static void jazz_led_update_display(void *opaque) case 16: color_segment = rgb_to_pixel16(0xaa, 0xaa, 0xaa); color_led = rgb_to_pixel16(0x00, 0xff, 0x00); + break; case 24: color_segment = rgb_to_pixel24(0xaa, 0xaa, 0xaa); color_led = rgb_to_pixel24(0x00, 0xff, 0x00); diff --git a/hw/display/pxa2xx_lcd.c b/hw/display/pxa2xx_lcd.c index 80edb70676..611fb174cd 100644 --- a/hw/display/pxa2xx_lcd.c +++ b/hw/display/pxa2xx_lcd.c @@ -620,24 +620,24 @@ static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp) src += 2; break; case 1: /* 16 bpp plus transparency */ - alpha = *(uint16_t *) src & (1 << 24); + alpha = *(uint32_t *) src & (1 << 24); if (s->control[0] & LCCR0_CMS) - r = g = b = *(uint16_t *) src & 0xff; + r = g = b = *(uint32_t *) src & 0xff; else { - r = (*(uint16_t *) src & 0xf800) >> 8; - g = (*(uint16_t *) src & 0x07e0) >> 3; - b = (*(uint16_t *) src & 0x001f) << 3; + r = (*(uint32_t *) src & 0xf80000) >> 16; + g = (*(uint32_t *) src & 0x00fc00) >> 8; + b = (*(uint32_t *) src & 0x0000f8); } - src += 2; + src += 4; break; case 2: /* 18 bpp plus transparency */ alpha = *(uint32_t *) src & (1 << 24); if (s->control[0] & LCCR0_CMS) r = g = b = *(uint32_t *) src & 0xff; else { - r = (*(uint32_t *) src & 0xf80000) >> 16; + r = (*(uint32_t *) src & 0xfc0000) >> 16; g = (*(uint32_t *) src & 0x00fc00) >> 8; - b = (*(uint32_t *) src & 0x0000f8); + b = (*(uint32_t *) src & 0x0000fc); } src += 4; break; diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index eaf3e61994..a48e26367d 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -69,7 +69,7 @@ static bool smbios_legacy_mode; static bool gigabyte_align = true; /* PC hardware initialisation */ -static void pc_init1(QEMUMachineInitArgs *args, +static void pc_init1(MachineState *machine, int pci_enabled, int kvmclock_enabled) { @@ -106,7 +106,7 @@ static void pc_init1(QEMUMachineInitArgs *args, object_property_add_child(qdev_get_machine(), "icc-bridge", OBJECT(icc_bridge), NULL); - pc_cpus_init(args->cpu_model, icc_bridge); + pc_cpus_init(machine->cpu_model, icc_bridge); if (kvm_enabled() && kvmclock_enabled) { kvmclock_create(); @@ -119,13 +119,13 @@ static void pc_init1(QEMUMachineInitArgs *args, * For old machine types, use whatever split we used historically to avoid * breaking migration. */ - if (args->ram_size >= 0xe0000000) { + if (machine->ram_size >= 0xe0000000) { ram_addr_t lowmem = gigabyte_align ? 0xc0000000 : 0xe0000000; - above_4g_mem_size = args->ram_size - lowmem; + above_4g_mem_size = machine->ram_size - lowmem; below_4g_mem_size = lowmem; } else { above_4g_mem_size = 0; - below_4g_mem_size = args->ram_size; + below_4g_mem_size = machine->ram_size; } if (pci_enabled) { @@ -145,16 +145,17 @@ static void pc_init1(QEMUMachineInitArgs *args, guest_info->isapc_ram_fw = !pci_enabled; if (smbios_defaults) { + MachineClass *mc = MACHINE_GET_CLASS(machine); /* These values are guest ABI, do not change */ smbios_set_defaults("QEMU", "Standard PC (i440FX + PIIX, 1996)", - args->machine->name, smbios_legacy_mode); + mc->name, smbios_legacy_mode); } /* allocate ram and load rom/bios */ if (!xen_enabled()) { fw_cfg = pc_memory_init(system_memory, - args->kernel_filename, args->kernel_cmdline, - args->initrd_filename, + machine->kernel_filename, machine->kernel_cmdline, + machine->initrd_filename, below_4g_mem_size, above_4g_mem_size, rom_memory, &ram_memory, guest_info); } @@ -170,7 +171,7 @@ static void pc_init1(QEMUMachineInitArgs *args, if (pci_enabled) { pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi, - system_memory, system_io, args->ram_size, + system_memory, system_io, machine->ram_size, below_4g_mem_size, above_4g_mem_size, pci_memory, ram_memory); @@ -235,7 +236,7 @@ static void pc_init1(QEMUMachineInitArgs *args, } } - pc_cmos_init(below_4g_mem_size, above_4g_mem_size, args->boot_order, + pc_cmos_init(below_4g_mem_size, above_4g_mem_size, machine->boot_order, floppy, idebus[0], idebus[1], rtc_state); if (pci_enabled && usb_enabled(false)) { @@ -258,131 +259,131 @@ static void pc_init1(QEMUMachineInitArgs *args, } } -static void pc_init_pci(QEMUMachineInitArgs *args) +static void pc_init_pci(MachineState *machine) { - pc_init1(args, 1, 1); + pc_init1(machine, 1, 1); } -static void pc_compat_2_0(QEMUMachineInitArgs *args) +static void pc_compat_2_0(MachineState *machine) { smbios_legacy_mode = true; } -static void pc_compat_1_7(QEMUMachineInitArgs *args) +static void pc_compat_1_7(MachineState *machine) { - pc_compat_2_0(args); + pc_compat_2_0(machine); smbios_defaults = false; gigabyte_align = false; option_rom_has_mr = true; x86_cpu_compat_disable_kvm_features(FEAT_1_ECX, CPUID_EXT_X2APIC); } -static void pc_compat_1_6(QEMUMachineInitArgs *args) +static void pc_compat_1_6(MachineState *machine) { - pc_compat_1_7(args); + pc_compat_1_7(machine); has_pci_info = false; rom_file_has_mr = false; has_acpi_build = false; } -static void pc_compat_1_5(QEMUMachineInitArgs *args) +static void pc_compat_1_5(MachineState *machine) { - pc_compat_1_6(args); + pc_compat_1_6(machine); } -static void pc_compat_1_4(QEMUMachineInitArgs *args) +static void pc_compat_1_4(MachineState *machine) { - pc_compat_1_5(args); + pc_compat_1_5(machine); x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE); x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ); } -static void pc_compat_1_3(QEMUMachineInitArgs *args) +static void pc_compat_1_3(MachineState *machine) { - pc_compat_1_4(args); + pc_compat_1_4(machine); enable_compat_apic_id_mode(); } /* PC compat function for pc-0.14 to pc-1.2 */ -static void pc_compat_1_2(QEMUMachineInitArgs *args) +static void pc_compat_1_2(MachineState *machine) { - pc_compat_1_3(args); + pc_compat_1_3(machine); x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI); } -static void pc_init_pci_2_0(QEMUMachineInitArgs *args) +static void pc_init_pci_2_0(MachineState *machine) { - pc_compat_2_0(args); - pc_init_pci(args); + pc_compat_2_0(machine); + pc_init_pci(machine); } -static void pc_init_pci_1_7(QEMUMachineInitArgs *args) +static void pc_init_pci_1_7(MachineState *machine) { - pc_compat_1_7(args); - pc_init_pci(args); + pc_compat_1_7(machine); + pc_init_pci(machine); } -static void pc_init_pci_1_6(QEMUMachineInitArgs *args) +static void pc_init_pci_1_6(MachineState *machine) { - pc_compat_1_6(args); - pc_init_pci(args); + pc_compat_1_6(machine); + pc_init_pci(machine); } -static void pc_init_pci_1_5(QEMUMachineInitArgs *args) +static void pc_init_pci_1_5(MachineState *machine) { - pc_compat_1_5(args); - pc_init_pci(args); + pc_compat_1_5(machine); + pc_init_pci(machine); } -static void pc_init_pci_1_4(QEMUMachineInitArgs *args) +static void pc_init_pci_1_4(MachineState *machine) { - pc_compat_1_4(args); - pc_init_pci(args); + pc_compat_1_4(machine); + pc_init_pci(machine); } -static void pc_init_pci_1_3(QEMUMachineInitArgs *args) +static void pc_init_pci_1_3(MachineState *machine) { - pc_compat_1_3(args); - pc_init_pci(args); + pc_compat_1_3(machine); + pc_init_pci(machine); } /* PC machine init function for pc-0.14 to pc-1.2 */ -static void pc_init_pci_1_2(QEMUMachineInitArgs *args) +static void pc_init_pci_1_2(MachineState *machine) { - pc_compat_1_2(args); - pc_init_pci(args); + pc_compat_1_2(machine); + pc_init_pci(machine); } /* PC init function for pc-0.10 to pc-0.13, and reused by xenfv */ -static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args) +static void pc_init_pci_no_kvmclock(MachineState *machine) { has_pci_info = false; has_acpi_build = false; smbios_defaults = false; x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI); enable_compat_apic_id_mode(); - pc_init1(args, 1, 0); + pc_init1(machine, 1, 0); } -static void pc_init_isa(QEMUMachineInitArgs *args) +static void pc_init_isa(MachineState *machine) { has_pci_info = false; has_acpi_build = false; smbios_defaults = false; - if (!args->cpu_model) { - args->cpu_model = "486"; + if (!machine->cpu_model) { + machine->cpu_model = "486"; } x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI); enable_compat_apic_id_mode(); - pc_init1(args, 0, 1); + pc_init1(machine, 0, 1); } #ifdef CONFIG_XEN -static void pc_xen_hvm_init(QEMUMachineInitArgs *args) +static void pc_xen_hvm_init(MachineState *machine) { PCIBus *bus; - pc_init_pci(args); + pc_init_pci(machine); bus = pci_find_primary_bus(); if (bus != NULL) { diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 9517ec653f..b3c02c163d 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -59,7 +59,7 @@ static bool smbios_legacy_mode; static bool gigabyte_align = true; /* PC hardware initialisation */ -static void pc_q35_init(QEMUMachineInitArgs *args) +static void pc_q35_init(MachineState *machine) { ram_addr_t below_4g_mem_size, above_4g_mem_size; Q35PCIHost *q35_host; @@ -93,7 +93,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args) object_property_add_child(qdev_get_machine(), "icc-bridge", OBJECT(icc_bridge), NULL); - pc_cpus_init(args->cpu_model, icc_bridge); + pc_cpus_init(machine->cpu_model, icc_bridge); pc_acpi_init("q35-acpi-dsdt.aml"); kvmclock_create(); @@ -107,13 +107,13 @@ static void pc_q35_init(QEMUMachineInitArgs *args) * For old machine types, use whatever split we used historically to avoid * breaking migration. */ - if (args->ram_size >= 0xb0000000) { + if (machine->ram_size >= 0xb0000000) { ram_addr_t lowmem = gigabyte_align ? 0x80000000 : 0xb0000000; - above_4g_mem_size = args->ram_size - lowmem; + above_4g_mem_size = machine->ram_size - lowmem; below_4g_mem_size = lowmem; } else { above_4g_mem_size = 0; - below_4g_mem_size = args->ram_size; + below_4g_mem_size = machine->ram_size; } /* pci enabled */ @@ -132,16 +132,17 @@ static void pc_q35_init(QEMUMachineInitArgs *args) guest_info->has_acpi_build = has_acpi_build; if (smbios_defaults) { + MachineClass *mc = MACHINE_GET_CLASS(machine); /* These values are guest ABI, do not change */ smbios_set_defaults("QEMU", "Standard PC (Q35 + ICH9, 2009)", - args->machine->name, smbios_legacy_mode); + mc->name, smbios_legacy_mode); } /* allocate ram and load rom/bios */ if (!xen_enabled()) { pc_memory_init(get_system_memory(), - args->kernel_filename, args->kernel_cmdline, - args->initrd_filename, + machine->kernel_filename, machine->kernel_cmdline, + machine->initrd_filename, below_4g_mem_size, above_4g_mem_size, rom_memory, &ram_memory, guest_info); } @@ -230,7 +231,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args) 0xb100), 8, NULL, 0); - pc_cmos_init(below_4g_mem_size, above_4g_mem_size, args->boot_order, + pc_cmos_init(below_4g_mem_size, above_4g_mem_size, machine->boot_order, floppy, idebus[0], idebus[1], rtc_state); /* the rest devices to which pci devfn is automatically assigned */ @@ -241,68 +242,68 @@ static void pc_q35_init(QEMUMachineInitArgs *args) } } -static void pc_compat_2_0(QEMUMachineInitArgs *args) +static void pc_compat_2_0(MachineState *machine) { smbios_legacy_mode = true; } -static void pc_compat_1_7(QEMUMachineInitArgs *args) +static void pc_compat_1_7(MachineState *machine) { - pc_compat_2_0(args); + pc_compat_2_0(machine); smbios_defaults = false; gigabyte_align = false; option_rom_has_mr = true; x86_cpu_compat_disable_kvm_features(FEAT_1_ECX, CPUID_EXT_X2APIC); } -static void pc_compat_1_6(QEMUMachineInitArgs *args) +static void pc_compat_1_6(MachineState *machine) { - pc_compat_1_7(args); + pc_compat_1_7(machine); has_pci_info = false; rom_file_has_mr = false; has_acpi_build = false; } -static void pc_compat_1_5(QEMUMachineInitArgs *args) +static void pc_compat_1_5(MachineState *machine) { - pc_compat_1_6(args); + pc_compat_1_6(machine); } -static void pc_compat_1_4(QEMUMachineInitArgs *args) +static void pc_compat_1_4(MachineState *machine) { - pc_compat_1_5(args); + pc_compat_1_5(machine); x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE); x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ); } -static void pc_q35_init_2_0(QEMUMachineInitArgs *args) +static void pc_q35_init_2_0(MachineState *machine) { - pc_compat_2_0(args); - pc_q35_init(args); + pc_compat_2_0(machine); + pc_q35_init(machine); } -static void pc_q35_init_1_7(QEMUMachineInitArgs *args) +static void pc_q35_init_1_7(MachineState *machine) { - pc_compat_1_7(args); - pc_q35_init(args); + pc_compat_1_7(machine); + pc_q35_init(machine); } -static void pc_q35_init_1_6(QEMUMachineInitArgs *args) +static void pc_q35_init_1_6(MachineState *machine) { - pc_compat_1_6(args); - pc_q35_init(args); + pc_compat_1_6(machine); + pc_q35_init(machine); } -static void pc_q35_init_1_5(QEMUMachineInitArgs *args) +static void pc_q35_init_1_5(MachineState *machine) { - pc_compat_1_5(args); - pc_q35_init(args); + pc_compat_1_5(machine); + pc_q35_init(machine); } -static void pc_q35_init_1_4(QEMUMachineInitArgs *args) +static void pc_q35_init_1_4(MachineState *machine) { - pc_compat_1_4(args); - pc_q35_init(args); + pc_compat_1_4(machine); + pc_q35_init(machine); } #define PC_Q35_MACHINE_OPTIONS \ diff --git a/hw/input/hid.c b/hw/input/hid.c index bb0fa6a619..295bdab652 100644 --- a/hw/input/hid.c +++ b/hw/input/hid.c @@ -105,70 +105,135 @@ void hid_set_next_idle(HIDState *hs) } } -static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons) +static void hid_pointer_event(DeviceState *dev, QemuConsole *src, + InputEvent *evt) { - e->xdx = e->ydy = e->dz = 0; - e->buttons_state = buttons; -} + static const int bmap[INPUT_BUTTON_MAX] = { + [INPUT_BUTTON_LEFT] = 0x01, + [INPUT_BUTTON_RIGHT] = 0x02, + [INPUT_BUTTON_MIDDLE] = 0x04, + }; + HIDState *hs = (HIDState *)dev; + HIDPointerEvent *e; -static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel, - int x1, int y1, int z1) { - if (xyrel) { - e->xdx += x1; - e->ydy += y1; - } else { - e->xdx = x1; - e->ydy = y1; - /* Windows drivers do not like the 0/0 position and ignore such - * events. */ - if (!(x1 | y1)) { - e->xdx = 1; + assert(hs->n < QUEUE_LENGTH); + e = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK]; + + switch (evt->kind) { + case INPUT_EVENT_KIND_REL: + if (evt->rel->axis == INPUT_AXIS_X) { + e->xdx += evt->rel->value; + } else if (evt->rel->axis == INPUT_AXIS_Y) { + e->ydy -= evt->rel->value; + } + break; + + case INPUT_EVENT_KIND_ABS: + if (evt->rel->axis == INPUT_AXIS_X) { + e->xdx = evt->rel->value; + } else if (evt->rel->axis == INPUT_AXIS_Y) { + e->ydy = evt->rel->value; } + break; + + case INPUT_EVENT_KIND_BTN: + if (evt->btn->down) { + e->buttons_state |= bmap[evt->btn->button]; + if (evt->btn->button == INPUT_BUTTON_WHEEL_UP) { + e->dz--; + } else if (evt->btn->button == INPUT_BUTTON_WHEEL_DOWN) { + e->dz++; + } + } else { + e->buttons_state &= ~bmap[evt->btn->button]; + } + break; + + default: + /* keep gcc happy */ + break; } - e->dz += z1; + } -static void hid_pointer_event(void *opaque, - int x1, int y1, int z1, int buttons_state) +static void hid_pointer_sync(DeviceState *dev) { - HIDState *hs = opaque; - unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK; - unsigned previous_slot = (use_slot - 1) & QUEUE_MASK; - - /* We combine events where feasible to keep the queue small. We shouldn't - * combine anything with the first event of a particular button state, as - * that would change the location of the button state change. When the - * queue is empty, a second event is needed because we don't know if - * the first event changed the button state. */ - if (hs->n == QUEUE_LENGTH) { - /* Queue full. Discard old button state, combine motion normally. */ - hs->ptr.queue[use_slot].buttons_state = buttons_state; - } else if (hs->n < 2 || - hs->ptr.queue[use_slot].buttons_state != buttons_state || - hs->ptr.queue[previous_slot].buttons_state != - hs->ptr.queue[use_slot].buttons_state) { - /* Cannot or should not combine, so add an empty item to the queue. */ - QUEUE_INCR(use_slot); + HIDState *hs = (HIDState *)dev; + HIDPointerEvent *prev, *curr, *next; + bool event_compression = false; + + if (hs->n == QUEUE_LENGTH-1) { + /* + * Queue full. We are loosing information, but we at least + * keep track of most recent button state. + */ + return; + } + + prev = &hs->ptr.queue[(hs->head + hs->n - 1) & QUEUE_MASK]; + curr = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK]; + next = &hs->ptr.queue[(hs->head + hs->n + 1) & QUEUE_MASK]; + + if (hs->n > 0) { + /* + * No button state change between previous and current event + * (and previous wasn't seen by the guest yet), so there is + * motion information only and we can combine the two event + * into one. + */ + if (curr->buttons_state == prev->buttons_state) { + event_compression = true; + } + } + + if (event_compression) { + /* add current motion to previous, clear current */ + if (hs->kind == HID_MOUSE) { + prev->xdx += curr->xdx; + curr->xdx = 0; + prev->ydy -= curr->ydy; + curr->ydy = 0; + } else { + prev->xdx = curr->xdx; + prev->ydy = curr->ydy; + } + prev->dz += curr->dz; + curr->dz = 0; + } else { + /* prepate next (clear rel, copy abs + btns) */ + if (hs->kind == HID_MOUSE) { + next->xdx = 0; + next->ydy = 0; + } else { + next->xdx = curr->xdx; + next->ydy = curr->ydy; + } + next->dz = 0; + next->buttons_state = curr->buttons_state; + /* make current guest visible, notify guest */ hs->n++; - hid_pointer_event_clear(&hs->ptr.queue[use_slot], buttons_state); + hs->event(hs); } - hid_pointer_event_combine(&hs->ptr.queue[use_slot], - hs->kind == HID_MOUSE, - x1, y1, z1); - hs->event(hs); } -static void hid_keyboard_event(void *opaque, int keycode) +static void hid_keyboard_event(DeviceState *dev, QemuConsole *src, + InputEvent *evt) { - HIDState *hs = opaque; + HIDState *hs = (HIDState *)dev; + int scancodes[3], i, count; int slot; - if (hs->n == QUEUE_LENGTH) { + count = qemu_input_key_value_to_scancode(evt->key->key, + evt->key->down, + scancodes); + if (hs->n + count > QUEUE_LENGTH) { fprintf(stderr, "usb-kbd: warning: key event queue full\n"); return; } - slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++; - hs->kbd.keycodes[slot] = keycode; + for (i = 0; i < count; i++) { + slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++; + hs->kbd.keycodes[slot] = scancodes[i]; + } hs->event(hs); } @@ -247,14 +312,14 @@ static inline int int_clamp(int val, int vmin, int vmax) void hid_pointer_activate(HIDState *hs) { if (!hs->ptr.mouse_grabbed) { - qemu_activate_mouse_event_handler(hs->ptr.eh_entry); + qemu_input_handler_activate(hs->s); hs->ptr.mouse_grabbed = 1; } } int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) { - int dx, dy, dz, b, l; + int dx, dy, dz, l; int index; HIDPointerEvent *e; @@ -279,17 +344,6 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) dz = int_clamp(e->dz, -127, 127); e->dz -= dz; - b = 0; - if (e->buttons_state & MOUSE_EVENT_LBUTTON) { - b |= 0x01; - } - if (e->buttons_state & MOUSE_EVENT_RBUTTON) { - b |= 0x02; - } - if (e->buttons_state & MOUSE_EVENT_MBUTTON) { - b |= 0x04; - } - if (hs->n && !e->dz && (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) { @@ -304,7 +358,7 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) switch (hs->kind) { case HID_MOUSE: if (len > l) { - buf[l++] = b; + buf[l++] = e->buttons_state; } if (len > l) { buf[l++] = dx; @@ -319,7 +373,7 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) case HID_TABLET: if (len > l) { - buf[l++] = b; + buf[l++] = e->buttons_state; } if (len > l) { buf[l++] = dx & 0xff; @@ -413,31 +467,45 @@ void hid_reset(HIDState *hs) void hid_free(HIDState *hs) { - switch (hs->kind) { - case HID_KEYBOARD: - qemu_remove_kbd_event_handler(hs->kbd.eh_entry); - break; - case HID_MOUSE: - case HID_TABLET: - qemu_remove_mouse_event_handler(hs->ptr.eh_entry); - break; - } + qemu_input_handler_unregister(hs->s); hid_del_idle_timer(hs); } +static QemuInputHandler hid_keyboard_handler = { + .name = "QEMU HID Keyboard", + .mask = INPUT_EVENT_MASK_KEY, + .event = hid_keyboard_event, +}; + +static QemuInputHandler hid_mouse_handler = { + .name = "QEMU HID Mouse", + .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, + .event = hid_pointer_event, + .sync = hid_pointer_sync, +}; + +static QemuInputHandler hid_tablet_handler = { + .name = "QEMU HID Tablet", + .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS, + .event = hid_pointer_event, + .sync = hid_pointer_sync, +}; + void hid_init(HIDState *hs, int kind, HIDEventFunc event) { hs->kind = kind; hs->event = event; if (hs->kind == HID_KEYBOARD) { - hs->kbd.eh_entry = qemu_add_kbd_event_handler(hid_keyboard_event, hs); + hs->s = qemu_input_handler_register((DeviceState *)hs, + &hid_keyboard_handler); + qemu_input_handler_activate(hs->s); } else if (hs->kind == HID_MOUSE) { - hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs, - 0, "QEMU HID Mouse"); + hs->s = qemu_input_handler_register((DeviceState *)hs, + &hid_mouse_handler); } else if (hs->kind == HID_TABLET) { - hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs, - 1, "QEMU HID Tablet"); + hs->s = qemu_input_handler_register((DeviceState *)hs, + &hid_tablet_handler); } } diff --git a/hw/input/ps2.c b/hw/input/ps2.c index 34120796b1..22b77dfe5c 100644 --- a/hw/input/ps2.c +++ b/hw/input/ps2.c @@ -24,6 +24,7 @@ #include "hw/hw.h" #include "hw/input/ps2.h" #include "ui/console.h" +#include "ui/input.h" #include "sysemu/sysemu.h" /* debug PC keyboard */ @@ -71,10 +72,12 @@ #define MOUSE_STATUS_ENABLED 0x20 #define MOUSE_STATUS_SCALE21 0x10 -#define PS2_QUEUE_SIZE 256 +#define PS2_QUEUE_SIZE 16 /* Buffer size required by PS/2 protocol */ typedef struct { - uint8_t data[PS2_QUEUE_SIZE]; + /* Keep the data array 256 bytes long, which compatibility + with older qemu versions. */ + uint8_t data[256]; int rptr, wptr, count; } PS2Queue; @@ -137,7 +140,7 @@ void ps2_queue(void *opaque, int b) PS2State *s = (PS2State *)opaque; PS2Queue *q = &s->queue; - if (q->count >= PS2_QUEUE_SIZE) + if (q->count >= PS2_QUEUE_SIZE - 1) return; q->data[q->wptr] = b; if (++q->wptr == PS2_QUEUE_SIZE) @@ -170,6 +173,21 @@ static void ps2_put_keycode(void *opaque, int keycode) ps2_queue(&s->common, keycode); } +static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src, + InputEvent *evt) +{ + PS2KbdState *s = (PS2KbdState *)dev; + int scancodes[3], i, count; + + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); + count = qemu_input_key_value_to_scancode(evt->key->key, + evt->key->down, + scancodes); + for (i = 0; i < count; i++) { + ps2_put_keycode(s, scancodes[i]); + } +} + uint32_t ps2_read_data(void *opaque) { PS2State *s = (PS2State *)opaque; @@ -352,31 +370,57 @@ static void ps2_mouse_send_packet(PS2MouseState *s) s->mouse_dz -= dz1; } -static void ps2_mouse_event(void *opaque, - int dx, int dy, int dz, int buttons_state) +static void ps2_mouse_event(DeviceState *dev, QemuConsole *src, + InputEvent *evt) { - PS2MouseState *s = opaque; + static const int bmap[INPUT_BUTTON_MAX] = { + [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON, + [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON, + [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON, + }; + PS2MouseState *s = (PS2MouseState *)dev; /* check if deltas are recorded when disabled */ if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) return; - s->mouse_dx += dx; - s->mouse_dy -= dy; - s->mouse_dz += dz; - /* XXX: SDL sometimes generates nul events: we delete them */ - if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 && - s->mouse_buttons == buttons_state) - return; - s->mouse_buttons = buttons_state; + switch (evt->kind) { + case INPUT_EVENT_KIND_REL: + if (evt->rel->axis == INPUT_AXIS_X) { + s->mouse_dx += evt->rel->value; + } else if (evt->rel->axis == INPUT_AXIS_Y) { + s->mouse_dy -= evt->rel->value; + } + break; - if (buttons_state) { - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); + case INPUT_EVENT_KIND_BTN: + if (evt->btn->down) { + s->mouse_buttons |= bmap[evt->btn->button]; + if (evt->btn->button == INPUT_BUTTON_WHEEL_UP) { + s->mouse_dz--; + } else if (evt->btn->button == INPUT_BUTTON_WHEEL_DOWN) { + s->mouse_dz++; + } + } else { + s->mouse_buttons &= ~bmap[evt->btn->button]; + } + break; + + default: + /* keep gcc happy */ + break; } +} - if (!(s->mouse_status & MOUSE_STATUS_REMOTE) && - (s->common.queue.count < (PS2_QUEUE_SIZE - 16))) { - for(;;) { +static void ps2_mouse_sync(DeviceState *dev) +{ + PS2MouseState *s = (PS2MouseState *)dev; + + if (s->mouse_buttons) { + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); + } + if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) { + while (s->common.queue.count < PS2_QUEUE_SIZE - 4) { /* if not remote, send event. Multiple events are sent if too big deltas */ ps2_mouse_send_packet(s); @@ -388,7 +432,9 @@ static void ps2_mouse_event(void *opaque, void ps2_mouse_fake_event(void *opaque) { - ps2_mouse_event(opaque, 1, 0, 0, 0); + PS2MouseState *s = opaque; + s->mouse_dx++; + ps2_mouse_sync(opaque); } void ps2_write_mouse(void *opaque, int val) @@ -528,6 +574,34 @@ static void ps2_common_reset(PS2State *s) s->update_irq(s->update_arg, 0); } +static void ps2_common_post_load(PS2State *s) +{ + PS2Queue *q = &s->queue; + int size; + int i; + int tmp_data[PS2_QUEUE_SIZE]; + + /* set the useful data buffer queue size, < PS2_QUEUE_SIZE */ + size = q->count > PS2_QUEUE_SIZE ? 0 : q->count; + + /* move the queue elements to the start of data array */ + if (size > 0) { + for (i = 0; i < size; i++) { + /* move the queue elements to the temporary buffer */ + tmp_data[i] = q->data[q->rptr]; + if (++q->rptr == 256) { + q->rptr = 0; + } + } + memcpy(q->data, tmp_data, size); + } + /* reset rptr/wptr/count */ + q->rptr = 0; + q->wptr = size; + q->count = size; + s->update_irq(s->update_arg, q->count != 0); +} + static void ps2_kbd_reset(void *opaque) { PS2KbdState *s = (PS2KbdState *) opaque; @@ -600,18 +674,31 @@ static const VMStateDescription vmstate_ps2_keyboard_ledstate = { static int ps2_kbd_post_load(void* opaque, int version_id) { PS2KbdState *s = (PS2KbdState*)opaque; + PS2State *ps2 = &s->common; if (version_id == 2) s->scancode_set=2; + + ps2_common_post_load(ps2); + return 0; } +static void ps2_kbd_pre_save(void *opaque) +{ + PS2KbdState *s = (PS2KbdState *)opaque; + PS2State *ps2 = &s->common; + + ps2_common_post_load(ps2); +} + static const VMStateDescription vmstate_ps2_keyboard = { .name = "ps2kbd", .version_id = 3, .minimum_version_id = 2, .minimum_version_id_old = 2, .post_load = ps2_kbd_post_load, + .pre_save = ps2_kbd_pre_save, .fields = (VMStateField []) { VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State), VMSTATE_INT32(scan_enabled, PS2KbdState), @@ -629,11 +716,31 @@ static const VMStateDescription vmstate_ps2_keyboard = { } }; +static int ps2_mouse_post_load(void *opaque, int version_id) +{ + PS2MouseState *s = (PS2MouseState *)opaque; + PS2State *ps2 = &s->common; + + ps2_common_post_load(ps2); + + return 0; +} + +static void ps2_mouse_pre_save(void *opaque) +{ + PS2MouseState *s = (PS2MouseState *)opaque; + PS2State *ps2 = &s->common; + + ps2_common_post_load(ps2); +} + static const VMStateDescription vmstate_ps2_mouse = { .name = "ps2mouse", .version_id = 2, .minimum_version_id = 2, .minimum_version_id_old = 2, + .post_load = ps2_mouse_post_load, + .pre_save = ps2_mouse_pre_save, .fields = (VMStateField []) { VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State), VMSTATE_UINT8(mouse_status, PS2MouseState), @@ -650,6 +757,12 @@ static const VMStateDescription vmstate_ps2_mouse = { } }; +static QemuInputHandler ps2_keyboard_handler = { + .name = "QEMU PS/2 Keyboard", + .mask = INPUT_EVENT_MASK_KEY, + .event = ps2_keyboard_event, +}; + void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg) { PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState)); @@ -658,11 +771,19 @@ void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg) s->common.update_arg = update_arg; s->scancode_set = 2; vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s); - qemu_add_kbd_event_handler(ps2_put_keycode, s); + qemu_input_handler_register((DeviceState *)s, + &ps2_keyboard_handler); qemu_register_reset(ps2_kbd_reset, s); return s; } +static QemuInputHandler ps2_mouse_handler = { + .name = "QEMU PS/2 Mouse", + .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, + .event = ps2_mouse_event, + .sync = ps2_mouse_sync, +}; + void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg) { PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState)); @@ -670,7 +791,8 @@ void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg) s->common.update_irq = update_irq; s->common.update_arg = update_arg; vmstate_register(NULL, 0, &vmstate_ps2_mouse, s); - qemu_add_mouse_event_handler(ps2_mouse_event, s, 0, "QEMU PS/2 Mouse"); + qemu_input_handler_register((DeviceState *)s, + &ps2_mouse_handler); qemu_register_reset(ps2_mouse_reset, s); return s; } diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs index c8a2318d56..843864a3ef 100644 --- a/hw/intc/Makefile.objs +++ b/hw/intc/Makefile.objs @@ -26,3 +26,4 @@ obj-$(CONFIG_XICS) += xics.o obj-$(CONFIG_XICS_KVM) += xics_kvm.o obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o obj-$(CONFIG_S390_FLIC) += s390_flic.o +obj-$(CONFIG_S390_FLIC_KVM) += s390_flic_kvm.o diff --git a/hw/intc/s390_flic.c b/hw/intc/s390_flic.c index b2ef3e3f8e..03c5e89f4e 100644 --- a/hw/intc/s390_flic.c +++ b/hw/intc/s390_flic.c @@ -1,322 +1,103 @@ /* - * QEMU S390x KVM floating interrupt controller (flic) + * QEMU S390x floating interrupt controller (flic) * * Copyright 2014 IBM Corp. * Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com> + * Cornelia Huck <cornelia.huck@de.ibm.com> * * This work is licensed under the terms of the GNU GPL, version 2 or (at * your option) any later version. See the COPYING file in the top-level * directory. */ -#include <sys/ioctl.h> #include "qemu/error-report.h" #include "hw/sysbus.h" -#include "sysemu/kvm.h" #include "migration/qemu-file.h" #include "hw/s390x/s390_flic.h" #include "trace.h" -#define FLIC_SAVE_INITIAL_SIZE getpagesize() -#define FLIC_FAILED (-1UL) -#define FLIC_SAVEVM_VERSION 1 - -void s390_flic_init(void) -{ - DeviceState *dev; - int r; - - if (kvm_enabled()) { - dev = qdev_create(NULL, "s390-flic"); - object_property_add_child(qdev_get_machine(), "s390-flic", - OBJECT(dev), NULL); - r = qdev_init(dev); - if (r) { - error_report("flic: couldn't create qdev"); - } - } -} - -/** - * flic_get_all_irqs - store all pending irqs in buffer - * @buf: pointer to buffer which is passed to kernel - * @len: length of buffer - * @flic: pointer to flic device state - * - * Returns: -ENOMEM if buffer is too small, - * -EINVAL if attr.group is invalid, - * -EFAULT if copying to userspace failed, - * on success return number of stored interrupts - */ -static int flic_get_all_irqs(KVMS390FLICState *flic, - void *buf, int len) +S390FLICState *s390_get_flic(void) { - struct kvm_device_attr attr = { - .group = KVM_DEV_FLIC_GET_ALL_IRQS, - .addr = (uint64_t) buf, - .attr = len, - }; - int rc; - - rc = ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr); - - return rc == -1 ? -errno : rc; -} + S390FLICState *fs; -static void flic_enable_pfault(KVMS390FLICState *flic) -{ - struct kvm_device_attr attr = { - .group = KVM_DEV_FLIC_APF_ENABLE, - }; - int rc; - - rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr); - - if (rc) { - fprintf(stderr, "flic: couldn't enable pfault\n"); + fs = S390_FLIC_COMMON(object_resolve_path(TYPE_KVM_S390_FLIC, NULL)); + if (!fs) { + fs = S390_FLIC_COMMON(object_resolve_path(TYPE_QEMU_S390_FLIC, NULL)); } + return fs; } -static void flic_disable_wait_pfault(KVMS390FLICState *flic) -{ - struct kvm_device_attr attr = { - .group = KVM_DEV_FLIC_APF_DISABLE_WAIT, - }; - int rc; - - rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr); - - if (rc) { - fprintf(stderr, "flic: couldn't disable pfault\n"); - } -} - -/** flic_enqueue_irqs - returns 0 on success - * @buf: pointer to buffer which is passed to kernel - * @len: length of buffer - * @flic: pointer to flic device state - * - * Returns: -EINVAL if attr.group is unknown - */ -static int flic_enqueue_irqs(void *buf, uint64_t len, - KVMS390FLICState *flic) -{ - int rc; - struct kvm_device_attr attr = { - .group = KVM_DEV_FLIC_ENQUEUE, - .addr = (uint64_t) buf, - .attr = len, - }; - - rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr); - - return rc ? -errno : 0; -} - -/** - * __get_all_irqs - store all pending irqs in buffer - * @flic: pointer to flic device state - * @buf: pointer to pointer to a buffer - * @len: length of buffer - * - * Returns: return value of flic_get_all_irqs - * Note: Retry and increase buffer size until flic_get_all_irqs - * either returns a value >= 0 or a negative error code. - * -ENOMEM is an exception, which means the buffer is too small - * and we should try again. Other negative error codes can be - * -EFAULT and -EINVAL which we ignore at this point - */ -static int __get_all_irqs(KVMS390FLICState *flic, - void **buf, int len) +void s390_flic_init(void) { + DeviceState *dev; int r; - do { - /* returns -ENOMEM if buffer is too small and number - * of queued interrupts on success */ - r = flic_get_all_irqs(flic, *buf, len); - if (r >= 0) { - break; - } - len *= 2; - *buf = g_try_realloc(*buf, len); - if (!buf) { - return -ENOMEM; - } - } while (r == -ENOMEM && len <= KVM_S390_FLIC_MAX_BUFFER); - - return r; -} - -/** - * kvm_flic_save - Save pending floating interrupts - * @f: QEMUFile containing migration state - * @opaque: pointer to flic device state - * - * Note: Pass buf and len to kernel. Start with one page and - * increase until buffer is sufficient or maxium size is - * reached - */ -static void kvm_flic_save(QEMUFile *f, void *opaque) -{ - KVMS390FLICState *flic = opaque; - int len = FLIC_SAVE_INITIAL_SIZE; - void *buf; - int count; - - flic_disable_wait_pfault((struct KVMS390FLICState *) opaque); - - buf = g_try_malloc0(len); - if (!buf) { - /* Storing FLIC_FAILED into the count field here will cause the - * target system to fail when attempting to load irqs from the - * migration state */ - error_report("flic: couldn't allocate memory"); - qemu_put_be64(f, FLIC_FAILED); - return; + dev = s390_flic_kvm_create(); + if (!dev) { + dev = qdev_create(NULL, TYPE_QEMU_S390_FLIC); + object_property_add_child(qdev_get_machine(), TYPE_QEMU_S390_FLIC, + OBJECT(dev), NULL); } - - count = __get_all_irqs(flic, &buf, len); - if (count < 0) { - error_report("flic: couldn't retrieve irqs from kernel, rc %d", - count); - /* Storing FLIC_FAILED into the count field here will cause the - * target system to fail when attempting to load irqs from the - * migration state */ - qemu_put_be64(f, FLIC_FAILED); - } else { - qemu_put_be64(f, count); - qemu_put_buffer(f, (uint8_t *) buf, - count * sizeof(struct kvm_s390_irq)); + r = qdev_init(dev); + if (r) { + error_report("flic: couldn't create qdev"); } - g_free(buf); } -/** - * kvm_flic_load - Load pending floating interrupts - * @f: QEMUFile containing migration state - * @opaque: pointer to flic device state - * @version_id: version id for migration - * - * Returns: value of flic_enqueue_irqs, -EINVAL on error - * Note: Do nothing when no interrupts where stored - * in QEMUFile - */ -static int kvm_flic_load(QEMUFile *f, void *opaque, int version_id) +static int qemu_s390_register_io_adapter(S390FLICState *fs, uint32_t id, + uint8_t isc, bool swap, + bool is_maskable) { - uint64_t len = 0; - uint64_t count = 0; - void *buf = NULL; - int r = 0; - - if (version_id != FLIC_SAVEVM_VERSION) { - r = -EINVAL; - goto out; - } - - flic_enable_pfault((struct KVMS390FLICState *) opaque); - - count = qemu_get_be64(f); - len = count * sizeof(struct kvm_s390_irq); - if (count == FLIC_FAILED) { - r = -EINVAL; - goto out; - } - if (count == 0) { - r = 0; - goto out; - } - buf = g_try_malloc0(len); - if (!buf) { - r = -ENOMEM; - goto out; - } - - if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) { - r = -EINVAL; - goto out_free; - } - r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque); - -out_free: - g_free(buf); -out: - return r; + /* nothing to do */ + return 0; } -static void kvm_s390_flic_realize(DeviceState *dev, Error **errp) +static int qemu_s390_io_adapter_map(S390FLICState *fs, uint32_t id, + uint64_t map_addr, bool do_map) { - KVMS390FLICState *flic_state = KVM_S390_FLIC(dev); - struct kvm_create_device cd = {0}; - int ret; - - flic_state->fd = -1; - if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) { - trace_flic_no_device_api(errno); - return; - } - - cd.type = KVM_DEV_TYPE_FLIC; - ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd); - if (ret < 0) { - trace_flic_create_device(errno); - return; - } - flic_state->fd = cd.fd; - - /* Register savevm handler for floating interrupts */ - register_savevm(NULL, "s390-flic", 0, 1, kvm_flic_save, - kvm_flic_load, (void *) flic_state); + /* nothing to do */ + return 0; } -static void kvm_s390_flic_unrealize(DeviceState *dev, Error **errp) +static int qemu_s390_add_adapter_routes(S390FLICState *fs, + AdapterRoutes *routes) { - KVMS390FLICState *flic_state = KVM_S390_FLIC(dev); - - unregister_savevm(DEVICE(flic_state), "s390-flic", flic_state); + return -ENOSYS; } -static void kvm_s390_flic_reset(DeviceState *dev) +static void qemu_s390_release_adapter_routes(S390FLICState *fs, + AdapterRoutes *routes) { - KVMS390FLICState *flic = KVM_S390_FLIC(dev); - struct kvm_device_attr attr = { - .group = KVM_DEV_FLIC_CLEAR_IRQS, - }; - int rc = 0; - - if (flic->fd == -1) { - return; - } - - flic_disable_wait_pfault(flic); - - rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr); - if (rc) { - trace_flic_reset_failed(errno); - } - - flic_enable_pfault(flic); } -static void kvm_s390_flic_class_init(ObjectClass *oc, void *data) +static void qemu_s390_flic_class_init(ObjectClass *oc, void *data) { - DeviceClass *dc = DEVICE_CLASS(oc); + S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc); - dc->realize = kvm_s390_flic_realize; - dc->unrealize = kvm_s390_flic_unrealize; - dc->reset = kvm_s390_flic_reset; + fsc->register_io_adapter = qemu_s390_register_io_adapter; + fsc->io_adapter_map = qemu_s390_io_adapter_map; + fsc->add_adapter_routes = qemu_s390_add_adapter_routes; + fsc->release_adapter_routes = qemu_s390_release_adapter_routes; } -static const TypeInfo kvm_s390_flic_info = { - .name = TYPE_KVM_S390_FLIC, +static const TypeInfo qemu_s390_flic_info = { + .name = TYPE_QEMU_S390_FLIC, + .parent = TYPE_S390_FLIC_COMMON, + .instance_size = sizeof(QEMUS390FLICState), + .class_init = qemu_s390_flic_class_init, +}; + +static const TypeInfo s390_flic_common_info = { + .name = TYPE_S390_FLIC_COMMON, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(KVMS390FLICState), - .class_init = kvm_s390_flic_class_init, + .instance_size = sizeof(S390FLICState), + .class_size = sizeof(S390FLICStateClass), }; -static void kvm_s390_flic_register_types(void) +static void qemu_s390_flic_register_types(void) { - type_register_static(&kvm_s390_flic_info); + type_register_static(&s390_flic_common_info); + type_register_static(&qemu_s390_flic_info); } -type_init(kvm_s390_flic_register_types) +type_init(qemu_s390_flic_register_types) diff --git a/hw/intc/s390_flic_kvm.c b/hw/intc/s390_flic_kvm.c new file mode 100644 index 0000000000..46c9e612d1 --- /dev/null +++ b/hw/intc/s390_flic_kvm.c @@ -0,0 +1,420 @@ +/* + * QEMU S390x KVM floating interrupt controller (flic) + * + * Copyright 2014 IBM Corp. + * Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com> + * Cornelia Huck <cornelia.huck@de.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#include <sys/ioctl.h> +#include "qemu/error-report.h" +#include "hw/sysbus.h" +#include "sysemu/kvm.h" +#include "migration/qemu-file.h" +#include "hw/s390x/s390_flic.h" +#include "hw/s390x/adapter.h" +#include "trace.h" + +#define FLIC_SAVE_INITIAL_SIZE getpagesize() +#define FLIC_FAILED (-1UL) +#define FLIC_SAVEVM_VERSION 1 + +typedef struct KVMS390FLICState { + S390FLICState parent_obj; + + uint32_t fd; +} KVMS390FLICState; + +DeviceState *s390_flic_kvm_create(void) +{ + DeviceState *dev = NULL; + + if (kvm_enabled()) { + dev = qdev_create(NULL, TYPE_KVM_S390_FLIC); + object_property_add_child(qdev_get_machine(), TYPE_KVM_S390_FLIC, + OBJECT(dev), NULL); + } + return dev; +} + +/** + * flic_get_all_irqs - store all pending irqs in buffer + * @buf: pointer to buffer which is passed to kernel + * @len: length of buffer + * @flic: pointer to flic device state + * + * Returns: -ENOMEM if buffer is too small, + * -EINVAL if attr.group is invalid, + * -EFAULT if copying to userspace failed, + * on success return number of stored interrupts + */ +static int flic_get_all_irqs(KVMS390FLICState *flic, + void *buf, int len) +{ + struct kvm_device_attr attr = { + .group = KVM_DEV_FLIC_GET_ALL_IRQS, + .addr = (uint64_t) buf, + .attr = len, + }; + int rc; + + rc = ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr); + + return rc == -1 ? -errno : rc; +} + +static void flic_enable_pfault(KVMS390FLICState *flic) +{ + struct kvm_device_attr attr = { + .group = KVM_DEV_FLIC_APF_ENABLE, + }; + int rc; + + rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr); + + if (rc) { + fprintf(stderr, "flic: couldn't enable pfault\n"); + } +} + +static void flic_disable_wait_pfault(KVMS390FLICState *flic) +{ + struct kvm_device_attr attr = { + .group = KVM_DEV_FLIC_APF_DISABLE_WAIT, + }; + int rc; + + rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr); + + if (rc) { + fprintf(stderr, "flic: couldn't disable pfault\n"); + } +} + +/** flic_enqueue_irqs - returns 0 on success + * @buf: pointer to buffer which is passed to kernel + * @len: length of buffer + * @flic: pointer to flic device state + * + * Returns: -EINVAL if attr.group is unknown + */ +static int flic_enqueue_irqs(void *buf, uint64_t len, + KVMS390FLICState *flic) +{ + int rc; + struct kvm_device_attr attr = { + .group = KVM_DEV_FLIC_ENQUEUE, + .addr = (uint64_t) buf, + .attr = len, + }; + + rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr); + + return rc ? -errno : 0; +} + +/** + * __get_all_irqs - store all pending irqs in buffer + * @flic: pointer to flic device state + * @buf: pointer to pointer to a buffer + * @len: length of buffer + * + * Returns: return value of flic_get_all_irqs + * Note: Retry and increase buffer size until flic_get_all_irqs + * either returns a value >= 0 or a negative error code. + * -ENOMEM is an exception, which means the buffer is too small + * and we should try again. Other negative error codes can be + * -EFAULT and -EINVAL which we ignore at this point + */ +static int __get_all_irqs(KVMS390FLICState *flic, + void **buf, int len) +{ + int r; + + do { + /* returns -ENOMEM if buffer is too small and number + * of queued interrupts on success */ + r = flic_get_all_irqs(flic, *buf, len); + if (r >= 0) { + break; + } + len *= 2; + *buf = g_try_realloc(*buf, len); + if (!buf) { + return -ENOMEM; + } + } while (r == -ENOMEM && len <= KVM_S390_FLIC_MAX_BUFFER); + + return r; +} + +static int kvm_s390_register_io_adapter(S390FLICState *fs, uint32_t id, + uint8_t isc, bool swap, + bool is_maskable) +{ + struct kvm_s390_io_adapter adapter = { + .id = id, + .isc = isc, + .maskable = is_maskable, + .swap = swap, + }; + KVMS390FLICState *flic = KVM_S390_FLIC(fs); + int r, ret; + struct kvm_device_attr attr = { + .group = KVM_DEV_FLIC_ADAPTER_REGISTER, + .addr = (uint64_t)&adapter, + }; + + if (!kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING)) { + return -ENOSYS; + } + + r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr); + + ret = r ? -errno : 0; + return ret; +} + +static int kvm_s390_io_adapter_map(S390FLICState *fs, uint32_t id, + uint64_t map_addr, bool do_map) +{ + struct kvm_s390_io_adapter_req req = { + .id = id, + .type = do_map ? KVM_S390_IO_ADAPTER_MAP : KVM_S390_IO_ADAPTER_UNMAP, + .addr = map_addr, + }; + struct kvm_device_attr attr = { + .group = KVM_DEV_FLIC_ADAPTER_MODIFY, + .addr = (uint64_t)&req, + }; + KVMS390FLICState *flic = KVM_S390_FLIC(fs); + int r; + + if (!kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING)) { + return -ENOSYS; + } + + r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr); + return r ? -errno : 0; +} + +static int kvm_s390_add_adapter_routes(S390FLICState *fs, + AdapterRoutes *routes) +{ + int ret, i; + uint64_t ind_offset = routes->adapter.ind_offset; + + for (i = 0; i < routes->num_routes; i++) { + ret = kvm_irqchip_add_adapter_route(kvm_state, &routes->adapter); + if (ret < 0) { + goto out_undo; + } + routes->gsi[i] = ret; + routes->adapter.ind_offset++; + } + /* Restore passed-in structure to original state. */ + routes->adapter.ind_offset = ind_offset; + return 0; +out_undo: + while (--i >= 0) { + kvm_irqchip_release_virq(kvm_state, routes->gsi[i]); + routes->gsi[i] = -1; + } + routes->adapter.ind_offset = ind_offset; + return ret; +} + +static void kvm_s390_release_adapter_routes(S390FLICState *fs, + AdapterRoutes *routes) +{ + int i; + + for (i = 0; i < routes->num_routes; i++) { + if (routes->gsi[i] >= 0) { + kvm_irqchip_release_virq(kvm_state, routes->gsi[i]); + routes->gsi[i] = -1; + } + } +} + +/** + * kvm_flic_save - Save pending floating interrupts + * @f: QEMUFile containing migration state + * @opaque: pointer to flic device state + * + * Note: Pass buf and len to kernel. Start with one page and + * increase until buffer is sufficient or maxium size is + * reached + */ +static void kvm_flic_save(QEMUFile *f, void *opaque) +{ + KVMS390FLICState *flic = opaque; + int len = FLIC_SAVE_INITIAL_SIZE; + void *buf; + int count; + + flic_disable_wait_pfault((struct KVMS390FLICState *) opaque); + + buf = g_try_malloc0(len); + if (!buf) { + /* Storing FLIC_FAILED into the count field here will cause the + * target system to fail when attempting to load irqs from the + * migration state */ + error_report("flic: couldn't allocate memory"); + qemu_put_be64(f, FLIC_FAILED); + return; + } + + count = __get_all_irqs(flic, &buf, len); + if (count < 0) { + error_report("flic: couldn't retrieve irqs from kernel, rc %d", + count); + /* Storing FLIC_FAILED into the count field here will cause the + * target system to fail when attempting to load irqs from the + * migration state */ + qemu_put_be64(f, FLIC_FAILED); + } else { + qemu_put_be64(f, count); + qemu_put_buffer(f, (uint8_t *) buf, + count * sizeof(struct kvm_s390_irq)); + } + g_free(buf); +} + +/** + * kvm_flic_load - Load pending floating interrupts + * @f: QEMUFile containing migration state + * @opaque: pointer to flic device state + * @version_id: version id for migration + * + * Returns: value of flic_enqueue_irqs, -EINVAL on error + * Note: Do nothing when no interrupts where stored + * in QEMUFile + */ +static int kvm_flic_load(QEMUFile *f, void *opaque, int version_id) +{ + uint64_t len = 0; + uint64_t count = 0; + void *buf = NULL; + int r = 0; + + if (version_id != FLIC_SAVEVM_VERSION) { + r = -EINVAL; + goto out; + } + + flic_enable_pfault((struct KVMS390FLICState *) opaque); + + count = qemu_get_be64(f); + len = count * sizeof(struct kvm_s390_irq); + if (count == FLIC_FAILED) { + r = -EINVAL; + goto out; + } + if (count == 0) { + r = 0; + goto out; + } + buf = g_try_malloc0(len); + if (!buf) { + r = -ENOMEM; + goto out; + } + + if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) { + r = -EINVAL; + goto out_free; + } + r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque); + +out_free: + g_free(buf); +out: + return r; +} + +static void kvm_s390_flic_realize(DeviceState *dev, Error **errp) +{ + KVMS390FLICState *flic_state = KVM_S390_FLIC(dev); + struct kvm_create_device cd = {0}; + int ret; + + flic_state->fd = -1; + if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) { + trace_flic_no_device_api(errno); + return; + } + + cd.type = KVM_DEV_TYPE_FLIC; + ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd); + if (ret < 0) { + trace_flic_create_device(errno); + return; + } + flic_state->fd = cd.fd; + + /* Register savevm handler for floating interrupts */ + register_savevm(NULL, "s390-flic", 0, 1, kvm_flic_save, + kvm_flic_load, (void *) flic_state); +} + +static void kvm_s390_flic_unrealize(DeviceState *dev, Error **errp) +{ + KVMS390FLICState *flic_state = KVM_S390_FLIC(dev); + + unregister_savevm(DEVICE(flic_state), "s390-flic", flic_state); +} + +static void kvm_s390_flic_reset(DeviceState *dev) +{ + KVMS390FLICState *flic = KVM_S390_FLIC(dev); + struct kvm_device_attr attr = { + .group = KVM_DEV_FLIC_CLEAR_IRQS, + }; + int rc = 0; + + if (flic->fd == -1) { + return; + } + + flic_disable_wait_pfault(flic); + + rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr); + if (rc) { + trace_flic_reset_failed(errno); + } + + flic_enable_pfault(flic); +} + +static void kvm_s390_flic_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc); + + dc->realize = kvm_s390_flic_realize; + dc->unrealize = kvm_s390_flic_unrealize; + dc->reset = kvm_s390_flic_reset; + fsc->register_io_adapter = kvm_s390_register_io_adapter; + fsc->io_adapter_map = kvm_s390_io_adapter_map; + fsc->add_adapter_routes = kvm_s390_add_adapter_routes; + fsc->release_adapter_routes = kvm_s390_release_adapter_routes; +} + +static const TypeInfo kvm_s390_flic_info = { + .name = TYPE_KVM_S390_FLIC, + .parent = TYPE_S390_FLIC_COMMON, + .instance_size = sizeof(KVMS390FLICState), + .class_init = kvm_s390_flic_class_init, +}; + +static void kvm_s390_flic_register_types(void) +{ + type_register_static(&kvm_s390_flic_info); +} + +type_init(kvm_s390_flic_register_types) diff --git a/hw/lm32/lm32_boards.c b/hw/lm32/lm32_boards.c index 5e22e9b4d7..0e013408f1 100644 --- a/hw/lm32/lm32_boards.c +++ b/hw/lm32/lm32_boards.c @@ -69,10 +69,10 @@ static void main_cpu_reset(void *opaque) env->deba = reset_info->flash_base; } -static void lm32_evr_init(QEMUMachineInitArgs *args) +static void lm32_evr_init(MachineState *machine) { - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; LM32CPU *cpu; CPULM32State *env; DriveInfo *dinfo; @@ -162,12 +162,12 @@ static void lm32_evr_init(QEMUMachineInitArgs *args) qemu_register_reset(main_cpu_reset, reset_info); } -static void lm32_uclinux_init(QEMUMachineInitArgs *args) +static void lm32_uclinux_init(MachineState *machine) { - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; LM32CPU *cpu; CPULM32State *env; DriveInfo *dinfo; diff --git a/hw/lm32/milkymist.c b/hw/lm32/milkymist.c index baf234ce04..81c3933e63 100644 --- a/hw/lm32/milkymist.c +++ b/hw/lm32/milkymist.c @@ -74,12 +74,12 @@ static void main_cpu_reset(void *opaque) } static void -milkymist_init(QEMUMachineInitArgs *args) +milkymist_init(MachineState *machine) { - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; LM32CPU *cpu; CPULM32State *env; int kernel_size; diff --git a/hw/m68k/an5206.c b/hw/m68k/an5206.c index 24f2068559..684496a946 100644 --- a/hw/m68k/an5206.c +++ b/hw/m68k/an5206.c @@ -20,11 +20,11 @@ /* Board init. */ -static void an5206_init(QEMUMachineInitArgs *args) +static void an5206_init(MachineState *machine) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; M68kCPU *cpu; CPUM68KState *env; int kernel_size; diff --git a/hw/m68k/dummy_m68k.c b/hw/m68k/dummy_m68k.c index 86e2e6e065..6db1b7164e 100644 --- a/hw/m68k/dummy_m68k.c +++ b/hw/m68k/dummy_m68k.c @@ -16,11 +16,11 @@ /* Board init. */ -static void dummy_m68k_init(QEMUMachineInitArgs *args) +static void dummy_m68k_init(MachineState *machine) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; CPUM68KState *env; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); diff --git a/hw/m68k/mcf5208.c b/hw/m68k/mcf5208.c index 6e30c0b393..2ef617f2b7 100644 --- a/hw/m68k/mcf5208.c +++ b/hw/m68k/mcf5208.c @@ -188,11 +188,11 @@ static void mcf5208_sys_init(MemoryRegion *address_space, qemu_irq *pic) } } -static void mcf5208evb_init(QEMUMachineInitArgs *args) +static void mcf5208evb_init(MachineState *machine) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; M68kCPU *cpu; CPUM68KState *env; int kernel_size; diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c index 40a9f5ccdb..aea9c5b49f 100644 --- a/hw/microblaze/petalogix_ml605_mmu.c +++ b/hw/microblaze/petalogix_ml605_mmu.c @@ -79,9 +79,9 @@ static void machine_cpu_reset(MicroBlazeCPU *cpu) } static void -petalogix_ml605_init(QEMUMachineInitArgs *args) +petalogix_ml605_init(MachineState *machine) { - ram_addr_t ram_size = args->ram_size; + ram_addr_t ram_size = machine->ram_size; MemoryRegion *address_space_mem = get_system_memory(); DeviceState *dev, *dma, *eth0; Object *ds, *cs; @@ -196,13 +196,13 @@ petalogix_ml605_init(QEMUMachineInitArgs *args) qemu_irq cs_line; dev = ssi_create_slave(spi, "n25q128"); - cs_line = qdev_get_gpio_in(dev, 0); + cs_line = qdev_get_gpio_in_named(dev, SSI_GPIO_CS, 0); sysbus_connect_irq(busdev, i+1, cs_line); } } microblaze_load_kernel(cpu, ddr_base, ram_size, - args->initrd_filename, + machine->initrd_filename, BINARY_DEVICE_TREE_FILE, machine_cpu_reset); diff --git a/hw/microblaze/petalogix_s3adsp1800_mmu.c b/hw/microblaze/petalogix_s3adsp1800_mmu.c index 6c45e206ec..49dc6d1949 100644 --- a/hw/microblaze/petalogix_s3adsp1800_mmu.c +++ b/hw/microblaze/petalogix_s3adsp1800_mmu.c @@ -59,10 +59,10 @@ static void machine_cpu_reset(MicroBlazeCPU *cpu) } static void -petalogix_s3adsp1800_init(QEMUMachineInitArgs *args) +petalogix_s3adsp1800_init(MachineState *machine) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; DeviceState *dev; MicroBlazeCPU *cpu; DriveInfo *dinfo; @@ -128,7 +128,7 @@ petalogix_s3adsp1800_init(QEMUMachineInitArgs *args) sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[ETHLITE_IRQ]); microblaze_load_kernel(cpu, ddr_base, ram_size, - args->initrd_filename, + machine->initrd_filename, BINARY_DEVICE_TREE_FILE, machine_cpu_reset); } diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index 30d9f19df7..5ad7a410a9 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -259,13 +259,13 @@ static void cpu_request_exit(void *opaque, int irq, int level) } } -static void mips_fulong2e_init(QEMUMachineInitArgs *args) +static void mips_fulong2e_init(MachineState *machine) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; char *filename; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c index 5f6dd9f588..c113a8082b 100644 --- a/hw/mips/mips_jazz.c +++ b/hw/mips/mips_jazz.c @@ -329,19 +329,19 @@ static void mips_jazz_init(MemoryRegion *address_space, } static -void mips_magnum_init(QEMUMachineInitArgs *args) +void mips_magnum_init(MachineState *machine) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; mips_jazz_init(get_system_memory(), get_system_io(), ram_size, cpu_model, JAZZ_MAGNUM); } static -void mips_pica61_init(QEMUMachineInitArgs *args) +void mips_pica61_init(MachineState *machine) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; mips_jazz_init(get_system_memory(), get_system_io(), ram_size, cpu_model, JAZZ_PICA61); } diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index ac5ec44db0..9fe775ea88 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -875,13 +875,13 @@ static void cpu_request_exit(void *opaque, int irq, int level) } static -void mips_malta_init(QEMUMachineInitArgs *args) +void mips_malta_init(MachineState *machine) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; char *filename; pflash_t *fl; MemoryRegion *system_memory = get_system_memory(); diff --git a/hw/mips/mips_mipssim.c b/hw/mips/mips_mipssim.c index 239aa6ac8c..413e64d16b 100644 --- a/hw/mips/mips_mipssim.c +++ b/hw/mips/mips_mipssim.c @@ -133,13 +133,13 @@ static void mipsnet_init(int base, qemu_irq irq, NICInfo *nd) } static void -mips_mipssim_init(QEMUMachineInitArgs *args) +mips_mipssim_init(MachineState *machine) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; char *filename; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *isa = g_new(MemoryRegion, 1); diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c index e94b543e80..71202931bf 100644 --- a/hw/mips/mips_r4k.c +++ b/hw/mips/mips_r4k.c @@ -153,13 +153,13 @@ static void main_cpu_reset(void *opaque) static const int sector_len = 32 * 1024; static -void mips_r4k_init(QEMUMachineInitArgs *args) +void mips_r4k_init(MachineState *machine) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; char *filename; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index f6743659f7..979e532fdf 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -29,7 +29,6 @@ obj-$(CONFIG_NSERIES) += cbus.o obj-$(CONFIG_ECCMEMCTL) += eccmemctl.o obj-$(CONFIG_EXYNOS4) += exynos4210_pmu.o obj-$(CONFIG_IMX) += imx_ccm.o -obj-$(CONFIG_LM32) += lm32_sys.o obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o obj-$(CONFIG_MAINSTONE) += mst_fpga.o diff --git a/hw/misc/lm32_sys.c b/hw/misc/lm32_sys.c deleted file mode 100644 index 778eb6e042..0000000000 --- a/hw/misc/lm32_sys.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - * QEMU model of the LatticeMico32 system control block. - * - * Copyright (c) 2010 Michael Walle <michael@walle.cc> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -/* - * This model is mainly intended for testing purposes and doesn't fit to any - * real hardware. On the one hand it provides a control register (R_CTRL) on - * the other hand it supports the lm32 tests. - * - * A write to the control register causes a system shutdown. - * Tests first write the pointer to a test name to the test name register - * (R_TESTNAME) and then write a zero to the pass/fail register (R_PASSFAIL) if - * the test is passed or any non-zero value to it if the test is failed. - */ - -#include "hw/hw.h" -#include "hw/sysbus.h" -#include "trace.h" -#include "qemu/log.h" -#include "qemu/error-report.h" -#include "sysemu/sysemu.h" - -enum { - R_CTRL = 0, - R_PASSFAIL, - R_TESTNAME, - R_MAX -}; - -#define MAX_TESTNAME_LEN 32 - -#define TYPE_LM32_SYS "lm32-sys" -#define LM32_SYS(obj) OBJECT_CHECK(LM32SysState, (obj), TYPE_LM32_SYS) - -struct LM32SysState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - uint32_t base; - uint32_t regs[R_MAX]; - uint8_t testname[MAX_TESTNAME_LEN]; -}; -typedef struct LM32SysState LM32SysState; - -static void copy_testname(LM32SysState *s) -{ - cpu_physical_memory_read(s->regs[R_TESTNAME], s->testname, - MAX_TESTNAME_LEN); - s->testname[MAX_TESTNAME_LEN - 1] = '\0'; -} - -static void sys_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - LM32SysState *s = opaque; - char *testname; - - trace_lm32_sys_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_CTRL: - qemu_system_shutdown_request(); - break; - case R_PASSFAIL: - s->regs[addr] = value; - testname = (char *)s->testname; - fprintf(stderr, "TC %-*s %s\n", MAX_TESTNAME_LEN, - testname, (value) ? "FAILED" : "OK"); - if (value) { - cpu_dump_state(qemu_get_cpu(0), stderr, fprintf, 0); - } - break; - case R_TESTNAME: - s->regs[addr] = value; - copy_testname(s); - break; - - default: - error_report("lm32_sys: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } -} - -static bool sys_ops_accepts(void *opaque, hwaddr addr, - unsigned size, bool is_write) -{ - return is_write && size == 4; -} - -static const MemoryRegionOps sys_ops = { - .write = sys_write, - .valid.accepts = sys_ops_accepts, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void sys_reset(DeviceState *d) -{ - LM32SysState *s = LM32_SYS(d); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - memset(s->testname, 0, MAX_TESTNAME_LEN); -} - -static int lm32_sys_init(SysBusDevice *dev) -{ - LM32SysState *s = LM32_SYS(dev); - - memory_region_init_io(&s->iomem, OBJECT(dev), &sys_ops , s, - "sys", R_MAX * 4); - sysbus_init_mmio(dev, &s->iomem); - - /* Note: This device is not created in the board initialization, - * instead it has to be added with the -device parameter. Therefore, - * the device maps itself. */ - sysbus_mmio_map(dev, 0, s->base); - - return 0; -} - -static const VMStateDescription vmstate_lm32_sys = { - .name = "lm32-sys", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, LM32SysState, R_MAX), - VMSTATE_BUFFER(testname, LM32SysState), - VMSTATE_END_OF_LIST() - } -}; - -static Property lm32_sys_properties[] = { - DEFINE_PROP_UINT32("base", LM32SysState, base, 0xffff0000), - DEFINE_PROP_END_OF_LIST(), -}; - -static void lm32_sys_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = lm32_sys_init; - dc->reset = sys_reset; - dc->vmsd = &vmstate_lm32_sys; - dc->props = lm32_sys_properties; -} - -static const TypeInfo lm32_sys_info = { - .name = TYPE_LM32_SYS, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(LM32SysState), - .class_init = lm32_sys_class_init, -}; - -static void lm32_sys_register_types(void) -{ - type_register_static(&lm32_sys_info); -} - -type_init(lm32_sys_register_types) diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c index 9cf5b84045..7437c2e3c3 100644 --- a/hw/misc/vfio.c +++ b/hw/misc/vfio.c @@ -133,6 +133,15 @@ enum { VFIO_INT_MSIX = 3, }; +typedef struct VFIOAddressSpace { + AddressSpace *as; + QLIST_HEAD(, VFIOContainer) containers; + QLIST_ENTRY(VFIOAddressSpace) list; +} VFIOAddressSpace; + +static QLIST_HEAD(, VFIOAddressSpace) vfio_address_spaces = + QLIST_HEAD_INITIALIZER(vfio_address_spaces); + struct VFIOGroup; typedef struct VFIOType1 { @@ -142,6 +151,7 @@ typedef struct VFIOType1 { } VFIOType1; typedef struct VFIOContainer { + VFIOAddressSpace *space; int fd; /* /dev/vfio/vfio, empowered by the attached groups */ struct { /* enable abstraction to support various iommu backends */ @@ -150,10 +160,18 @@ typedef struct VFIOContainer { }; void (*release)(struct VFIOContainer *); } iommu_data; + QLIST_HEAD(, VFIOGuestIOMMU) giommu_list; QLIST_HEAD(, VFIOGroup) group_list; QLIST_ENTRY(VFIOContainer) next; } VFIOContainer; +typedef struct VFIOGuestIOMMU { + VFIOContainer *container; + MemoryRegion *iommu; + Notifier n; + QLIST_ENTRY(VFIOGuestIOMMU) giommu_next; +} VFIOGuestIOMMU; + /* Cache of MSI-X setup plus extra mmap and memory region for split BAR map */ typedef struct VFIOMSIXInfo { uint8_t table_bar; @@ -234,9 +252,6 @@ static const VFIORomBlacklistEntry romblacklist[] = { #define MSIX_CAP_LENGTH 12 -static QLIST_HEAD(, VFIOContainer) - container_list = QLIST_HEAD_INITIALIZER(container_list); - static QLIST_HEAD(, VFIOGroup) group_list = QLIST_HEAD_INITIALIZER(group_list); @@ -1668,6 +1683,149 @@ static void vfio_probe_ati_bar4_window_quirk(VFIODevice *vdev, int nr) vdev->host.function); } +#define PCI_VENDOR_ID_REALTEK 0x10ec + +/* + * RTL8168 devices have a backdoor that can access the MSI-X table. At BAR2 + * offset 0x70 there is a dword data register, offset 0x74 is a dword address + * register. According to the Linux r8169 driver, the MSI-X table is addressed + * when the "type" portion of the address register is set to 0x1. This appears + * to be bits 16:30. Bit 31 is both a write indicator and some sort of + * "address latched" indicator. Bits 12:15 are a mask field, which we can + * ignore because the MSI-X table should always be accessed as a dword (full + * mask). Bits 0:11 is offset within the type. + * + * Example trace: + * + * Read from MSI-X table offset 0 + * vfio: vfio_bar_write(0000:05:00.0:BAR2+0x74, 0x1f000, 4) // store read addr + * vfio: vfio_bar_read(0000:05:00.0:BAR2+0x74, 4) = 0x8001f000 // latch + * vfio: vfio_bar_read(0000:05:00.0:BAR2+0x70, 4) = 0xfee00398 // read data + * + * Write 0xfee00000 to MSI-X table offset 0 + * vfio: vfio_bar_write(0000:05:00.0:BAR2+0x70, 0xfee00000, 4) // write data + * vfio: vfio_bar_write(0000:05:00.0:BAR2+0x74, 0x8001f000, 4) // do write + * vfio: vfio_bar_read(0000:05:00.0:BAR2+0x74, 4) = 0x1f000 // complete + */ + +static uint64_t vfio_rtl8168_window_quirk_read(void *opaque, + hwaddr addr, unsigned size) +{ + VFIOQuirk *quirk = opaque; + VFIODevice *vdev = quirk->vdev; + + switch (addr) { + case 4: /* address */ + if (quirk->data.flags) { + DPRINTF("%s fake read(%04x:%02x:%02x.%d)\n", + memory_region_name(&quirk->mem), vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function); + + return quirk->data.address_match ^ 0x10000000U; + } + break; + case 0: /* data */ + if (quirk->data.flags) { + uint64_t val; + + DPRINTF("%s MSI-X table read(%04x:%02x:%02x.%d)\n", + memory_region_name(&quirk->mem), vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function); + + if (!(vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX)) { + return 0; + } + + io_mem_read(&vdev->pdev.msix_table_mmio, + (hwaddr)(quirk->data.address_match & 0xfff), + &val, size); + return val; + } + } + + DPRINTF("%s direct read(%04x:%02x:%02x.%d)\n", + memory_region_name(&quirk->mem), vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function); + + return vfio_bar_read(&vdev->bars[quirk->data.bar], addr + 0x70, size); +} + +static void vfio_rtl8168_window_quirk_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) +{ + VFIOQuirk *quirk = opaque; + VFIODevice *vdev = quirk->vdev; + + switch (addr) { + case 4: /* address */ + if ((data & 0x7fff0000) == 0x10000) { + if (data & 0x10000000U && + vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX) { + + DPRINTF("%s MSI-X table write(%04x:%02x:%02x.%d)\n", + memory_region_name(&quirk->mem), vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function); + + io_mem_write(&vdev->pdev.msix_table_mmio, + (hwaddr)(quirk->data.address_match & 0xfff), + data, size); + } + + quirk->data.flags = 1; + quirk->data.address_match = data; + + return; + } + quirk->data.flags = 0; + break; + case 0: /* data */ + quirk->data.address_mask = data; + break; + } + + DPRINTF("%s direct write(%04x:%02x:%02x.%d)\n", + memory_region_name(&quirk->mem), vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function); + + vfio_bar_write(&vdev->bars[quirk->data.bar], addr + 0x70, data, size); +} + +static const MemoryRegionOps vfio_rtl8168_window_quirk = { + .read = vfio_rtl8168_window_quirk_read, + .write = vfio_rtl8168_window_quirk_write, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void vfio_probe_rtl8168_bar2_window_quirk(VFIODevice *vdev, int nr) +{ + PCIDevice *pdev = &vdev->pdev; + VFIOQuirk *quirk; + + if (pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_REALTEK || + pci_get_word(pdev->config + PCI_DEVICE_ID) != 0x8168 || nr != 2) { + return; + } + + quirk = g_malloc0(sizeof(*quirk)); + quirk->vdev = vdev; + quirk->data.bar = nr; + + memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_rtl8168_window_quirk, + quirk, "vfio-rtl8168-window-quirk", 8); + memory_region_add_subregion_overlap(&vdev->bars[nr].mem, + 0x70, &quirk->mem, 1); + + QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); + + DPRINTF("Enabled RTL8168 BAR2 window quirk for device %04x:%02x:%02x.%x\n", + vdev->host.domain, vdev->host.bus, vdev->host.slot, + vdev->host.function); +} /* * Trap the BAR2 MMIO window to config space as well. */ @@ -2071,6 +2229,7 @@ static void vfio_bar_quirk_setup(VFIODevice *vdev, int nr) vfio_probe_nvidia_bar5_window_quirk(vdev, nr); vfio_probe_nvidia_bar0_88000_quirk(vdev, nr); vfio_probe_nvidia_bar0_1800_quirk(vdev, nr); + vfio_probe_rtl8168_bar2_window_quirk(vdev, nr); } static void vfio_bar_quirk_teardown(VFIODevice *vdev, int nr) @@ -2232,7 +2391,8 @@ static int vfio_dma_map(VFIOContainer *container, hwaddr iova, static bool vfio_listener_skipped_section(MemoryRegionSection *section) { - return !memory_region_is_ram(section->mr) || + return (!memory_region_is_ram(section->mr) && + !memory_region_is_iommu(section->mr)) || /* * Sizing an enabled 64-bit BAR can cause spurious mappings to * addresses in the upper part of the 64-bit address space. These @@ -2242,17 +2402,75 @@ static bool vfio_listener_skipped_section(MemoryRegionSection *section) section->offset_within_address_space & (1ULL << 63); } +static void vfio_iommu_map_notify(Notifier *n, void *data) +{ + VFIOGuestIOMMU *giommu = container_of(n, VFIOGuestIOMMU, n); + VFIOContainer *container = giommu->container; + IOMMUTLBEntry *iotlb = data; + MemoryRegion *mr; + hwaddr xlat; + hwaddr len = iotlb->addr_mask + 1; + void *vaddr; + int ret; + + DPRINTF("iommu map @ %"HWADDR_PRIx" - %"HWADDR_PRIx"\n", + iotlb->iova, iotlb->iova + iotlb->addr_mask); + + /* + * The IOMMU TLB entry we have just covers translation through + * this IOMMU to its immediate target. We need to translate + * it the rest of the way through to memory. + */ + mr = address_space_translate(&address_space_memory, + iotlb->translated_addr, + &xlat, &len, iotlb->perm & IOMMU_WO); + if (!memory_region_is_ram(mr)) { + DPRINTF("iommu map to non memory area %"HWADDR_PRIx"\n", + xlat); + return; + } + /* + * Translation truncates length to the IOMMU page size, + * check that it did not truncate too much. + */ + if (len & iotlb->addr_mask) { + DPRINTF("iommu has granularity incompatible with target AS\n"); + return; + } + + if (iotlb->perm != IOMMU_NONE) { + vaddr = memory_region_get_ram_ptr(mr) + xlat; + + ret = vfio_dma_map(container, iotlb->iova, + iotlb->addr_mask + 1, vaddr, + !(iotlb->perm & IOMMU_WO) || mr->readonly); + if (ret) { + error_report("vfio_dma_map(%p, 0x%"HWADDR_PRIx", " + "0x%"HWADDR_PRIx", %p) = %d (%m)", + container, iotlb->iova, + iotlb->addr_mask + 1, vaddr, ret); + } + } else { + ret = vfio_dma_unmap(container, iotlb->iova, iotlb->addr_mask + 1); + if (ret) { + error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", " + "0x%"HWADDR_PRIx") = %d (%m)", + container, iotlb->iova, + iotlb->addr_mask + 1, ret); + } + } +} + static void vfio_listener_region_add(MemoryListener *listener, MemoryRegionSection *section) { VFIOContainer *container = container_of(listener, VFIOContainer, iommu_data.type1.listener); hwaddr iova, end; + Int128 llend; void *vaddr; int ret; - assert(!memory_region_is_iommu(section->mr)); - if (vfio_listener_skipped_section(section)) { DPRINTF("SKIPPING region_add %"HWADDR_PRIx" - %"PRIx64"\n", section->offset_within_address_space, @@ -2268,21 +2486,65 @@ static void vfio_listener_region_add(MemoryListener *listener, } iova = TARGET_PAGE_ALIGN(section->offset_within_address_space); - end = (section->offset_within_address_space + int128_get64(section->size)) & - TARGET_PAGE_MASK; + llend = int128_make64(section->offset_within_address_space); + llend = int128_add(llend, section->size); + llend = int128_and(llend, int128_exts64(TARGET_PAGE_MASK)); - if (iova >= end) { + if (int128_ge(int128_make64(iova), llend)) { return; } + memory_region_ref(section->mr); + + if (memory_region_is_iommu(section->mr)) { + VFIOGuestIOMMU *giommu; + + DPRINTF("region_add [iommu] %"HWADDR_PRIx" - %"HWADDR_PRIx"\n", + iova, int128_get64(int128_sub(llend, int128_one()))); + /* + * FIXME: We should do some checking to see if the + * capabilities of the host VFIO IOMMU are adequate to model + * the guest IOMMU + * + * FIXME: For VFIO iommu types which have KVM acceleration to + * avoid bouncing all map/unmaps through qemu this way, this + * would be the right place to wire that up (tell the KVM + * device emulation the VFIO iommu handles to use). + */ + /* + * This assumes that the guest IOMMU is empty of + * mappings at this point. + * + * One way of doing this is: + * 1. Avoid sharing IOMMUs between emulated devices or different + * IOMMU groups. + * 2. Implement VFIO_IOMMU_ENABLE in the host kernel to fail if + * there are some mappings in IOMMU. + * + * VFIO on SPAPR does that. Other IOMMU models may do that different, + * they must make sure there are no existing mappings or + * loop through existing mappings to map them into VFIO. + */ + giommu = g_malloc0(sizeof(*giommu)); + giommu->iommu = section->mr; + giommu->container = container; + giommu->n.notify = vfio_iommu_map_notify; + QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next); + memory_region_register_iommu_notifier(giommu->iommu, &giommu->n); + + return; + } + + /* Here we assume that memory_region_is_ram(section->mr)==true */ + + end = int128_get64(llend); vaddr = memory_region_get_ram_ptr(section->mr) + section->offset_within_region + (iova - section->offset_within_address_space); - DPRINTF("region_add %"HWADDR_PRIx" - %"HWADDR_PRIx" [%p]\n", + DPRINTF("region_add [ram] %"HWADDR_PRIx" - %"HWADDR_PRIx" [%p]\n", iova, end - 1, vaddr); - memory_region_ref(section->mr); ret = vfio_dma_map(container, iova, end - iova, vaddr, section->readonly); if (ret) { error_report("vfio_dma_map(%p, 0x%"HWADDR_PRIx", " @@ -2326,6 +2588,27 @@ static void vfio_listener_region_del(MemoryListener *listener, return; } + if (memory_region_is_iommu(section->mr)) { + VFIOGuestIOMMU *giommu; + + QLIST_FOREACH(giommu, &container->giommu_list, giommu_next) { + if (giommu->iommu == section->mr) { + memory_region_unregister_iommu_notifier(&giommu->n); + QLIST_REMOVE(giommu, giommu_next); + g_free(giommu); + break; + } + } + + /* + * FIXME: We assume the one big unmap below is adequate to + * remove any individual page mappings in the IOMMU which + * might have been copied into VFIO. This works for a page table + * based IOMMU where a big unmap flattens a large range of IO-PTEs. + * That may not be true for all IOMMU types. + */ + } + iova = TARGET_PAGE_ALIGN(section->offset_within_address_space); end = (section->offset_within_address_space + int128_get64(section->size)) & TARGET_PAGE_MASK; @@ -3274,16 +3557,43 @@ static void vfio_kvm_device_del_group(VFIOGroup *group) #endif } -static int vfio_connect_container(VFIOGroup *group) +static VFIOAddressSpace *vfio_get_address_space(AddressSpace *as) +{ + VFIOAddressSpace *space; + + QLIST_FOREACH(space, &vfio_address_spaces, list) { + if (space->as == as) { + return space; + } + } + + /* No suitable VFIOAddressSpace, create a new one */ + space = g_malloc0(sizeof(*space)); + space->as = as; + QLIST_INIT(&space->containers); + + QLIST_INSERT_HEAD(&vfio_address_spaces, space, list); + + return space; +} + +static void vfio_put_address_space(VFIOAddressSpace *space) +{ + if (QLIST_EMPTY(&space->containers)) { + QLIST_REMOVE(space, list); + g_free(space); + } +} + +static int vfio_connect_container(VFIOGroup *group, AddressSpace *as) { VFIOContainer *container; int ret, fd; + VFIOAddressSpace *space; - if (group->container) { - return 0; - } + space = vfio_get_address_space(as); - QLIST_FOREACH(container, &container_list, next) { + QLIST_FOREACH(container, &space->containers, next) { if (!ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &container->fd)) { group->container = container; QLIST_INSERT_HEAD(&container->group_list, group, container_next); @@ -3294,35 +3604,35 @@ static int vfio_connect_container(VFIOGroup *group) fd = qemu_open("/dev/vfio/vfio", O_RDWR); if (fd < 0) { error_report("vfio: failed to open /dev/vfio/vfio: %m"); - return -errno; + ret = -errno; + goto put_space_exit; } ret = ioctl(fd, VFIO_GET_API_VERSION); if (ret != VFIO_API_VERSION) { error_report("vfio: supported vfio version: %d, " "reported version: %d", VFIO_API_VERSION, ret); - close(fd); - return -EINVAL; + ret = -EINVAL; + goto close_fd_exit; } container = g_malloc0(sizeof(*container)); + container->space = space; container->fd = fd; if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU)) { ret = ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &fd); if (ret) { error_report("vfio: failed to set group container: %m"); - g_free(container); - close(fd); - return -errno; + ret = -errno; + goto free_container_exit; } ret = ioctl(fd, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU); if (ret) { error_report("vfio: failed to set iommu for container: %m"); - g_free(container); - close(fd); - return -errno; + ret = -errno; + goto free_container_exit; } container->iommu_data.type1.listener = vfio_memory_listener; @@ -3333,29 +3643,39 @@ static int vfio_connect_container(VFIOGroup *group) if (container->iommu_data.type1.error) { ret = container->iommu_data.type1.error; - vfio_listener_release(container); - g_free(container); - close(fd); error_report("vfio: memory listener initialization failed for container"); - return ret; + goto listener_release_exit; } container->iommu_data.type1.initialized = true; } else { error_report("vfio: No available IOMMU models"); - g_free(container); - close(fd); - return -EINVAL; + ret = -EINVAL; + goto free_container_exit; } QLIST_INIT(&container->group_list); - QLIST_INSERT_HEAD(&container_list, container, next); + QLIST_INSERT_HEAD(&space->containers, container, next); group->container = container; QLIST_INSERT_HEAD(&container->group_list, group, container_next); return 0; + +listener_release_exit: + vfio_listener_release(container); + +free_container_exit: + g_free(container); + +close_fd_exit: + close(fd); + +put_space_exit: + vfio_put_address_space(space); + + return ret; } static void vfio_disconnect_container(VFIOGroup *group) @@ -3371,6 +3691,8 @@ static void vfio_disconnect_container(VFIOGroup *group) group->container = NULL; if (QLIST_EMPTY(&container->group_list)) { + VFIOAddressSpace *space = container->space; + if (container->iommu_data.release) { container->iommu_data.release(container); } @@ -3378,10 +3700,12 @@ static void vfio_disconnect_container(VFIOGroup *group) DPRINTF("vfio_disconnect_container: close container->fd\n"); close(container->fd); g_free(container); + + vfio_put_address_space(space); } } -static VFIOGroup *vfio_get_group(int groupid) +static VFIOGroup *vfio_get_group(int groupid, AddressSpace *as) { VFIOGroup *group; char path[32]; @@ -3389,7 +3713,14 @@ static VFIOGroup *vfio_get_group(int groupid) QLIST_FOREACH(group, &group_list, next) { if (group->groupid == groupid) { - return group; + /* Found it. Now is it already in the right context? */ + if (group->container->space->as == as) { + return group; + } else { + error_report("vfio: group %d used in multiple address spaces", + group->groupid); + return NULL; + } } } @@ -3399,34 +3730,27 @@ static VFIOGroup *vfio_get_group(int groupid) group->fd = qemu_open(path, O_RDWR); if (group->fd < 0) { error_report("vfio: error opening %s: %m", path); - g_free(group); - return NULL; + goto free_group_exit; } if (ioctl(group->fd, VFIO_GROUP_GET_STATUS, &status)) { error_report("vfio: error getting group status: %m"); - close(group->fd); - g_free(group); - return NULL; + goto close_fd_exit; } if (!(status.flags & VFIO_GROUP_FLAGS_VIABLE)) { error_report("vfio: error, group %d is not viable, please ensure " "all devices within the iommu_group are bound to their " "vfio bus driver.", groupid); - close(group->fd); - g_free(group); - return NULL; + goto close_fd_exit; } group->groupid = groupid; QLIST_INIT(&group->device_list); - if (vfio_connect_container(group)) { + if (vfio_connect_container(group, as)) { error_report("vfio: failed to setup container for group %d", groupid); - close(group->fd); - g_free(group); - return NULL; + goto close_fd_exit; } if (QLIST_EMPTY(&group_list)) { @@ -3438,6 +3762,14 @@ static VFIOGroup *vfio_get_group(int groupid) vfio_kvm_device_add_group(group); return group; + +close_fd_exit: + close(group->fd); + +free_group_exit: + g_free(group); + + return NULL; } static void vfio_put_group(VFIOGroup *group) @@ -3768,7 +4100,7 @@ static int vfio_initfn(PCIDevice *pdev) DPRINTF("%s(%04x:%02x:%02x.%x) group %d\n", __func__, vdev->host.domain, vdev->host.bus, vdev->host.slot, vdev->host.function, groupid); - group = vfio_get_group(groupid); + group = vfio_get_group(groupid, pci_device_iommu_address_space(pdev)); if (!group) { error_report("vfio: failed to get group %d", groupid); return -ENOENT; diff --git a/hw/moxie/moxiesim.c b/hw/moxie/moxiesim.c index a87ca6ddcc..f4357cf0d8 100644 --- a/hw/moxie/moxiesim.c +++ b/hw/moxie/moxiesim.c @@ -107,14 +107,14 @@ moxie_intc_create(hwaddr base, qemu_irq irq, int kind_of_intr) return dev; } -static void moxiesim_init(QEMUMachineInitArgs *args) +static void moxiesim_init(MachineState *machine) { MoxieCPU *cpu = NULL; - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; CPUMoxieState *env; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index 47e70381fe..a26861e2ae 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -1,5 +1,5 @@ /* - * QEMU Xilinx GEM emulation + * QEMU Cadence GEM emulation * * Copyright (c) 2011 Xilinx, Inc. * diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 8e1af8bf2e..b2b4f9b860 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -90,11 +90,11 @@ static void cpu_openrisc_load_kernel(ram_addr_t ram_size, } } -static void openrisc_sim_init(QEMUMachineInitArgs *args) +static void openrisc_sim_init(MachineState *machine) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; OpenRISCCPU *cpu = NULL; MemoryRegion *ram; int n; diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 22fe5eec36..8d6a8d4e74 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -605,13 +605,13 @@ PCIBus *pci_get_bus_devfn(int *devfnp, PCIBus *root, const char *devaddr) int dom, bus; unsigned slot; - assert(!root->parent_dev); - if (!root) { fprintf(stderr, "No primary PCI bus\n"); return NULL; } + assert(!root->parent_dev); + if (!devaddr) { *devfnp = -1; return pci_find_bus_nr(root, 0); diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index f984b3e9a9..223bab9eea 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -123,7 +123,7 @@ static void dt_serial_create(void *fdt, unsigned long long offset, } } -static int ppce500_load_device_tree(QEMUMachineInitArgs *args, +static int ppce500_load_device_tree(MachineState *machine, PPCE500Params *params, hwaddr addr, hwaddr initrd_base, @@ -132,7 +132,7 @@ static int ppce500_load_device_tree(QEMUMachineInitArgs *args, { CPUPPCState *env = first_cpu->env_ptr; int ret = -1; - uint64_t mem_reg_property[] = { 0, cpu_to_be64(args->ram_size) }; + uint64_t mem_reg_property[] = { 0, cpu_to_be64(machine->ram_size) }; int fdt_size; void *fdt; uint8_t hypercall[16]; @@ -207,7 +207,7 @@ static int ppce500_load_device_tree(QEMUMachineInitArgs *args, } ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", - args->kernel_cmdline); + machine->kernel_cmdline); if (ret < 0) fprintf(stderr, "couldn't set /chosen/bootargs\n"); @@ -387,7 +387,7 @@ out: } typedef struct DeviceTreeParams { - QEMUMachineInitArgs args; + MachineState *machine; PPCE500Params params; hwaddr addr; hwaddr initrd_base; @@ -397,18 +397,18 @@ typedef struct DeviceTreeParams { static void ppce500_reset_device_tree(void *opaque) { DeviceTreeParams *p = opaque; - ppce500_load_device_tree(&p->args, &p->params, p->addr, p->initrd_base, + ppce500_load_device_tree(p->machine, &p->params, p->addr, p->initrd_base, p->initrd_size, false); } -static int ppce500_prep_device_tree(QEMUMachineInitArgs *args, +static int ppce500_prep_device_tree(MachineState *machine, PPCE500Params *params, hwaddr addr, hwaddr initrd_base, hwaddr initrd_size) { DeviceTreeParams *p = g_new(DeviceTreeParams, 1); - p->args = *args; + p->machine = machine; p->params = *params; p->addr = addr; p->initrd_base = initrd_base; @@ -417,7 +417,7 @@ static int ppce500_prep_device_tree(QEMUMachineInitArgs *args, qemu_register_reset(ppce500_reset_device_tree, p); /* Issue the device tree loader once, so that we get the size of the blob */ - return ppce500_load_device_tree(args, params, addr, initrd_base, + return ppce500_load_device_tree(machine, params, addr, initrd_base, initrd_size, true); } @@ -597,7 +597,7 @@ static qemu_irq *ppce500_init_mpic(PPCE500Params *params, MemoryRegion *ccsr, return mpic; } -void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params) +void ppce500_init(MachineState *machine, PPCE500Params *params) { MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); @@ -622,8 +622,8 @@ void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params) PPCE500CCSRState *ccsr; /* Setup CPUs */ - if (args->cpu_model == NULL) { - args->cpu_model = "e500v2_v30"; + if (machine->cpu_model == NULL) { + machine->cpu_model = "e500v2_v30"; } irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *)); @@ -633,7 +633,7 @@ void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params) CPUState *cs; qemu_irq *input; - cpu = cpu_ppc_init(args->cpu_model); + cpu = cpu_ppc_init(machine->cpu_model); if (cpu == NULL) { fprintf(stderr, "Unable to initialize CPU!\n"); exit(1); @@ -672,7 +672,7 @@ void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params) /* Fixup Memory size on a alignment boundary */ ram_size &= ~(RAM_SIZES_ALIGN - 1); - args->ram_size = ram_size; + machine->ram_size = ram_size; /* Register Memory */ memory_region_init_ram(ram, NULL, "mpc8544ds.ram", ram_size); @@ -739,11 +739,11 @@ void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params) sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL); /* Load kernel. */ - if (args->kernel_filename) { - kernel_size = load_uimage(args->kernel_filename, &entry, + if (machine->kernel_filename) { + kernel_size = load_uimage(machine->kernel_filename, &entry, &loadaddr, NULL); if (kernel_size < 0) { - kernel_size = load_elf(args->kernel_filename, NULL, NULL, + kernel_size = load_elf(machine->kernel_filename, NULL, NULL, &elf_entry, &elf_lowaddr, NULL, 1, ELF_MACHINE, 0); entry = elf_entry; @@ -752,7 +752,7 @@ void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params) /* XXX try again as binary */ if (kernel_size < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", - args->kernel_filename); + machine->kernel_filename); exit(1); } @@ -764,14 +764,14 @@ void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params) } /* Load initrd. */ - if (args->initrd_filename) { + if (machine->initrd_filename) { initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK; - initrd_size = load_image_targphys(args->initrd_filename, initrd_base, + initrd_size = load_image_targphys(machine->initrd_filename, initrd_base, ram_size - initrd_base); if (initrd_size < 0) { fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - args->initrd_filename); + machine->initrd_filename); exit(1); } @@ -779,11 +779,11 @@ void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params) } /* If we're loading a kernel directly, we must load the device tree too. */ - if (args->kernel_filename) { + if (machine->kernel_filename) { struct boot_info *boot_info; int dt_size; - dt_size = ppce500_prep_device_tree(args, params, dt_base, + dt_size = ppce500_prep_device_tree(machine, params, dt_base, initrd_base, initrd_size); if (dt_size < 0) { fprintf(stderr, "couldn't load device tree\n"); diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h index 52726a2ec0..08b25fab49 100644 --- a/hw/ppc/e500.h +++ b/hw/ppc/e500.h @@ -13,6 +13,6 @@ typedef struct PPCE500Params { int mpic_version; } PPCE500Params; -void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params); +void ppce500_init(MachineState *machine, PPCE500Params *params); #endif diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c index 7d5357e83b..27df31ddb0 100644 --- a/hw/ppc/e500plat.c +++ b/hw/ppc/e500plat.c @@ -28,7 +28,7 @@ static void e500plat_fixup_devtree(PPCE500Params *params, void *fdt) sizeof(compatible)); } -static void e500plat_init(QEMUMachineInitArgs *args) +static void e500plat_init(MachineState *machine) { PPCE500Params params = { .pci_first_slot = 0x1, @@ -43,7 +43,7 @@ static void e500plat_init(QEMUMachineInitArgs *args) params.mpic_version = OPENPIC_MODEL_FSL_MPIC_20; } - ppce500_init(args, ¶ms); + ppce500_init(machine, ¶ms); } static QEMUMachine e500plat_machine = { diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 5e79575165..4bdaa8d398 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -140,14 +140,14 @@ static void ppc_core99_reset(void *opaque) } /* PowerPC Mac99 hardware initialisation */ -static void ppc_core99_init(QEMUMachineInitArgs *args) +static void ppc_core99_init(MachineState *machine) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_order; + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; + const char *boot_device = machine->boot_order; PowerPCCPU *cpu = NULL; CPUPPCState *env = NULL; char *filename; diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 2f27754c6c..77598e44cc 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -71,14 +71,14 @@ static void ppc_heathrow_reset(void *opaque) cpu_reset(CPU(cpu)); } -static void ppc_heathrow_init(QEMUMachineInitArgs *args) +static void ppc_heathrow_init(MachineState *machine) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_order; + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; + const char *boot_device = machine->boot_order; MemoryRegion *sysmem = get_system_memory(); PowerPCCPU *cpu = NULL; CPUPPCState *env = NULL; diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c index 292c70953b..b99f74af75 100644 --- a/hw/ppc/mpc8544ds.c +++ b/hw/ppc/mpc8544ds.c @@ -26,7 +26,7 @@ static void mpc8544ds_fixup_devtree(PPCE500Params *params, void *fdt) sizeof(compatible)); } -static void mpc8544ds_init(QEMUMachineInitArgs *args) +static void mpc8544ds_init(MachineState *machine) { PPCE500Params params = { .pci_first_slot = 0x11, @@ -35,7 +35,7 @@ static void mpc8544ds_init(QEMUMachineInitArgs *args) .mpic_version = OPENPIC_MODEL_FSL_MPIC_20, }; - ppce500_init(args, ¶ms); + ppce500_init(machine, ¶ms); } diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c index f1a8f6734a..98ad2d75e7 100644 --- a/hw/ppc/ppc405_boards.c +++ b/hw/ppc/ppc405_boards.c @@ -172,12 +172,12 @@ static void ref405ep_fpga_init(MemoryRegion *sysmem, uint32_t base) qemu_register_reset(&ref405ep_fpga_reset, fpga); } -static void ref405ep_init(QEMUMachineInitArgs *args) +static void ref405ep_init(MachineState *machine) { - ram_addr_t ram_size = args->ram_size; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; + ram_addr_t ram_size = machine->ram_size; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; char *filename; ppc4xx_bd_info_t bd; CPUPPCState *env; @@ -499,11 +499,11 @@ static void taihu_cpld_init(MemoryRegion *sysmem, uint32_t base) qemu_register_reset(&taihu_cpld_reset, cpld); } -static void taihu_405ep_init(QEMUMachineInitArgs *args) +static void taihu_405ep_init(MachineState *machine) { - ram_addr_t ram_size = args->ram_size; - const char *kernel_filename = args->kernel_filename; - const char *initrd_filename = args->initrd_filename; + ram_addr_t ram_size = machine->ram_size; + const char *kernel_filename = machine->kernel_filename; + const char *initrd_filename = machine->initrd_filename; char *filename; qemu_irq *pic; MemoryRegion *sysmem = get_system_memory(); diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c index 2ddc2ed4b9..81a06d310d 100644 --- a/hw/ppc/ppc440_bamboo.c +++ b/hw/ppc/ppc440_bamboo.c @@ -156,13 +156,13 @@ static void main_cpu_reset(void *opaque) mmubooke_create_initial_mapping(env, 0, 0); } -static void bamboo_init(QEMUMachineInitArgs *args) +static void bamboo_init(MachineState *machine) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 }; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *isa = g_new(MemoryRegion, 1); diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index 585937321f..2383254f49 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -364,14 +364,14 @@ static const MemoryRegionPortio prep_portio_list[] = { static PortioList prep_port_list; /* PowerPC PREP hardware initialisation */ -static void ppc_prep_init(QEMUMachineInitArgs *args) +static void ppc_prep_init(MachineState *machine) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_order; + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; + const char *boot_device = machine->boot_order; MemoryRegion *sysmem = get_system_memory(); PowerPCCPU *cpu = NULL; CPUPPCState *env = NULL; diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index b4ce950bbd..57e95780c8 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1140,14 +1140,14 @@ static SaveVMHandlers savevm_htab_handlers = { }; /* pSeries LPAR / sPAPR hardware init */ -static void ppc_spapr_init(QEMUMachineInitArgs *args) +static void ppc_spapr_init(MachineState *machine) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; - const char *boot_device = args->boot_order; + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; + const char *boot_device = machine->boot_order; PowerPCCPU *cpu; CPUPPCState *env; PCIHostState *phb; diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c index 3e3569d4b8..02b4f828d3 100644 --- a/hw/ppc/virtex_ml507.c +++ b/hw/ppc/virtex_ml507.c @@ -194,12 +194,12 @@ static int xilinx_load_device_tree(hwaddr addr, return fdt_size; } -static void virtex_init(QEMUMachineInitArgs *args) +static void virtex_init(MachineState *machine) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; hwaddr initrd_base = 0; int initrd_size = 0; MemoryRegion *address_space_mem = get_system_memory(); @@ -275,14 +275,14 @@ static void virtex_init(QEMUMachineInitArgs *args) boot_info.ima_size = kernel_size; /* Load initrd. */ - if (args->initrd_filename) { + if (machine->initrd_filename) { initrd_base = high = ROUND_UP(high, 4); - initrd_size = load_image_targphys(args->initrd_filename, + initrd_size = load_image_targphys(machine->initrd_filename, high, ram_size - high); if (initrd_size < 0) { error_report("couldn't load ram disk '%s'", - args->initrd_filename); + machine->initrd_filename); exit(1); } high = ROUND_UP(high + initrd_size, 4); diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 122cc7e66f..2678e4432c 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -16,6 +16,7 @@ #include "ioinst.h" #include "css.h" #include "trace.h" +#include "hw/s390x/s390_flic.h" typedef struct CrwContainer { CRW crw; @@ -39,6 +40,13 @@ typedef struct CssImage { ChpInfo chpids[MAX_CHPID + 1]; } CssImage; +typedef struct IoAdapter { + uint32_t id; + uint8_t type; + uint8_t isc; + QTAILQ_ENTRY(IoAdapter) sibling; +} IoAdapter; + typedef struct ChannelSubSys { QTAILQ_HEAD(, CrwContainer) pending_crws; bool do_crw_mchk; @@ -49,6 +57,7 @@ typedef struct ChannelSubSys { uint64_t chnmon_area; CssImage *css[MAX_CSSID + 1]; uint8_t default_cssid; + QTAILQ_HEAD(, IoAdapter) io_adapters; } ChannelSubSys; static ChannelSubSys *channel_subsys; @@ -69,6 +78,46 @@ int css_create_css_image(uint8_t cssid, bool default_image) return 0; } +int css_register_io_adapter(uint8_t type, uint8_t isc, bool swap, + bool maskable, uint32_t *id) +{ + IoAdapter *adapter; + bool found = false; + int ret; + S390FLICState *fs = s390_get_flic(); + S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs); + + *id = 0; + QTAILQ_FOREACH(adapter, &channel_subsys->io_adapters, sibling) { + if ((adapter->type == type) && (adapter->isc == isc)) { + *id = adapter->id; + found = true; + ret = 0; + break; + } + if (adapter->id >= *id) { + *id = adapter->id + 1; + } + } + if (found) { + goto out; + } + adapter = g_new0(IoAdapter, 1); + ret = fsc->register_io_adapter(fs, *id, isc, swap, maskable); + if (ret == 0) { + adapter->id = *id; + adapter->isc = isc; + adapter->type = type; + QTAILQ_INSERT_TAIL(&channel_subsys->io_adapters, adapter, sibling); + } else { + g_free(adapter); + fprintf(stderr, "Unexpected error %d when registering adapter %d\n", + ret, *id); + } +out: + return ret; +} + uint16_t css_build_subchannel_id(SubchDev *sch) { if (channel_subsys->max_cssid > 0) { @@ -1235,6 +1284,7 @@ static void css_init(void) channel_subsys->do_crw_mchk = true; channel_subsys->crws_lost = false; channel_subsys->chnmon_active = false; + QTAILQ_INIT(&channel_subsys->io_adapters); } machine_init(css_init); diff --git a/hw/s390x/css.h b/hw/s390x/css.h index 220169e7c3..6586106fa7 100644 --- a/hw/s390x/css.h +++ b/hw/s390x/css.h @@ -98,4 +98,8 @@ void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid, int hotplugged, int add); void css_generate_chp_crws(uint8_t cssid, uint8_t chpid); void css_adapter_interrupt(uint8_t isc); + +#define CSS_IO_ADAPTER_VIRTIO 1 +int css_register_io_adapter(uint8_t type, uint8_t isc, bool swap, + bool maskable, uint32_t *id); #endif diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 0d4f6ae2f3..42f5cec4c1 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -79,9 +79,9 @@ static void virtio_ccw_register_hcalls(void) virtio_ccw_hcall_early_printk); } -static void ccw_init(QEMUMachineInitArgs *args) +static void ccw_init(MachineState *machine) { - ram_addr_t my_ram_size = args->ram_size; + ram_addr_t my_ram_size = machine->ram_size; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); int shift = 0; @@ -102,8 +102,8 @@ static void ccw_init(QEMUMachineInitArgs *args) /* get a BUS */ css_bus = virtual_css_bus_init(); s390_sclp_init(); - s390_init_ipl_dev(args->kernel_filename, args->kernel_cmdline, - args->initrd_filename, "s390-ccw.img"); + s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline, + machine->initrd_filename, "s390-ccw.img"); s390_flic_init(); /* register hypercalls */ @@ -118,7 +118,7 @@ static void ccw_init(QEMUMachineInitArgs *args) storage_keys = g_malloc0(my_ram_size / TARGET_PAGE_SIZE); /* init CPUs */ - s390_init_cpus(args->cpu_model, storage_keys); + s390_init_cpus(machine->cpu_model, storage_keys); if (kvm_enabled()) { kvm_s390_enable_css_support(s390_cpu_addr2state(0)); diff --git a/hw/s390x/s390-virtio.c b/hw/s390x/s390-virtio.c index aef200310c..93c7acea72 100644 --- a/hw/s390x/s390-virtio.c +++ b/hw/s390x/s390-virtio.c @@ -224,9 +224,9 @@ void s390_create_virtio_net(BusState *bus, const char *name) } /* PC hardware initialisation */ -static void s390_init(QEMUMachineInitArgs *args) +static void s390_init(MachineState *machine) { - ram_addr_t my_ram_size = args->ram_size; + ram_addr_t my_ram_size = machine->ram_size; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); int shift = 0; @@ -248,8 +248,8 @@ static void s390_init(QEMUMachineInitArgs *args) /* get a BUS */ s390_bus = s390_virtio_bus_init(&my_ram_size); s390_sclp_init(); - s390_init_ipl_dev(args->kernel_filename, args->kernel_cmdline, - args->initrd_filename, ZIPL_FILENAME); + s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline, + machine->initrd_filename, ZIPL_FILENAME); s390_flic_init(); /* register hypercalls */ @@ -273,7 +273,7 @@ static void s390_init(QEMUMachineInitArgs *args) storage_keys = g_malloc0(my_ram_size / TARGET_PAGE_SIZE); /* init CPUs */ - s390_init_cpus(args->cpu_model, storage_keys); + s390_init_cpus(machine->cpu_model, storage_keys); /* Create VirtIO network adapters */ s390_create_virtio_net((BusState *)s390_bus, "virtio-net-s390"); diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 1cb4e2c2f8..c4f21d3816 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -21,12 +21,77 @@ #include "hw/sysbus.h" #include "qemu/bitops.h" #include "hw/virtio/virtio-bus.h" +#include "hw/s390x/adapter.h" +#include "hw/s390x/s390_flic.h" #include "ioinst.h" #include "css.h" #include "virtio-ccw.h" #include "trace.h" +static QTAILQ_HEAD(, IndAddr) indicator_addresses = + QTAILQ_HEAD_INITIALIZER(indicator_addresses); + +static IndAddr *get_indicator(hwaddr ind_addr, int len) +{ + IndAddr *indicator; + + QTAILQ_FOREACH(indicator, &indicator_addresses, sibling) { + if (indicator->addr == ind_addr) { + indicator->refcnt++; + return indicator; + } + } + indicator = g_new0(IndAddr, 1); + indicator->addr = ind_addr; + indicator->len = len; + indicator->refcnt = 1; + QTAILQ_INSERT_TAIL(&indicator_addresses, indicator, sibling); + return indicator; +} + +static int s390_io_adapter_map(AdapterInfo *adapter, uint64_t map_addr, + bool do_map) +{ + S390FLICState *fs = s390_get_flic(); + S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs); + + return fsc->io_adapter_map(fs, adapter->adapter_id, map_addr, do_map); +} + +static void release_indicator(AdapterInfo *adapter, IndAddr *indicator) +{ + assert(indicator->refcnt > 0); + indicator->refcnt--; + if (indicator->refcnt > 0) { + return; + } + QTAILQ_REMOVE(&indicator_addresses, indicator, sibling); + if (indicator->map) { + s390_io_adapter_map(adapter, indicator->map, false); + } + g_free(indicator); +} + +static int map_indicator(AdapterInfo *adapter, IndAddr *indicator) +{ + int ret; + + if (indicator->map) { + return 0; /* already mapped is not an error */ + } + indicator->map = indicator->addr; + ret = s390_io_adapter_map(adapter, indicator->map, true); + if ((ret != 0) && (ret != -ENOSYS)) { + goto out_err; + } + return 0; + +out_err: + indicator->map = 0; + return ret; +} + static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size, VirtioCcwDevice *dev); @@ -445,7 +510,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) ret = -EFAULT; } else { indicators = ldq_phys(&address_space_memory, ccw.cda); - dev->indicators = indicators; + dev->indicators = get_indicator(indicators, sizeof(uint64_t)); sch->curr_status.scsw.count = ccw.count - sizeof(indicators); ret = 0; } @@ -465,7 +530,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) ret = -EFAULT; } else { indicators = ldq_phys(&address_space_memory, ccw.cda); - dev->indicators2 = indicators; + dev->indicators2 = get_indicator(indicators, sizeof(uint64_t)); sch->curr_status.scsw.count = ccw.count - sizeof(indicators); ret = 0; } @@ -517,13 +582,20 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) ret = -EFAULT; } else { len = hw_len; - dev->summary_indicator = thinint->summary_indicator; - dev->indicators = thinint->device_indicator; + dev->summary_indicator = + get_indicator(thinint->summary_indicator, sizeof(uint8_t)); + dev->indicators = get_indicator(thinint->device_indicator, + thinint->ind_bit / 8 + 1); dev->thinint_isc = thinint->isc; - dev->ind_bit = thinint->ind_bit; + dev->routes.adapter.ind_offset = thinint->ind_bit; + dev->routes.adapter.summary_offset = 7; cpu_physical_memory_unmap(thinint, hw_len, 0, hw_len); - sch->thinint_active = ((dev->indicators != 0) && - (dev->summary_indicator != 0)); + ret = css_register_io_adapter(CSS_IO_ADAPTER_VIRTIO, + dev->thinint_isc, true, false, + &dev->routes.adapter.adapter_id); + assert(ret == 0); + sch->thinint_active = ((dev->indicators != NULL) && + (dev->summary_indicator != NULL)); sch->curr_status.scsw.count = ccw.count - len; ret = 0; } @@ -554,7 +626,7 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev) sch->driver_data = dev; dev->sch = sch; - dev->indicators = 0; + dev->indicators = NULL; /* Initialize subchannel structure. */ sch->channel_prog = 0x0; @@ -693,7 +765,10 @@ static int virtio_ccw_exit(VirtioCcwDevice *dev) css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL); g_free(sch); } - dev->indicators = 0; + if (dev->indicators) { + release_indicator(&dev->routes.adapter, dev->indicators); + dev->indicators = NULL; + } return 0; } @@ -950,17 +1025,19 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector) * ind_bit indicates the start of the indicators in a big * endian notation. */ - virtio_set_ind_atomic(sch, dev->indicators + - (dev->ind_bit + vector) / 8, - 0x80 >> ((dev->ind_bit + vector) % 8)); - if (!virtio_set_ind_atomic(sch, dev->summary_indicator, + uint64_t ind_bit = dev->routes.adapter.ind_offset; + + virtio_set_ind_atomic(sch, dev->indicators->addr + + (ind_bit + vector) / 8, + 0x80 >> ((ind_bit + vector) % 8)); + if (!virtio_set_ind_atomic(sch, dev->summary_indicator->addr, 0x01)) { css_adapter_interrupt(dev->thinint_isc); } } else { - indicators = ldq_phys(&address_space_memory, dev->indicators); + indicators = ldq_phys(&address_space_memory, dev->indicators->addr); indicators |= 1ULL << vector; - stq_phys(&address_space_memory, dev->indicators, indicators); + stq_phys(&address_space_memory, dev->indicators->addr, indicators); css_conditional_io_interrupt(sch); } } else { @@ -968,9 +1045,9 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector) return; } vector = 0; - indicators = ldq_phys(&address_space_memory, dev->indicators2); + indicators = ldq_phys(&address_space_memory, dev->indicators2->addr); indicators |= 1ULL << vector; - stq_phys(&address_space_memory, dev->indicators2, indicators); + stq_phys(&address_space_memory, dev->indicators2->addr, indicators); css_conditional_io_interrupt(sch); } } @@ -991,9 +1068,18 @@ static void virtio_ccw_reset(DeviceState *d) virtio_ccw_stop_ioeventfd(dev); virtio_reset(vdev); css_reset_sch(dev->sch); - dev->indicators = 0; - dev->indicators2 = 0; - dev->summary_indicator = 0; + if (dev->indicators) { + release_indicator(&dev->routes.adapter, dev->indicators); + dev->indicators = NULL; + } + if (dev->indicators2) { + release_indicator(&dev->routes.adapter, dev->indicators2); + dev->indicators2 = NULL; + } + if (dev->summary_indicator) { + release_indicator(&dev->routes.adapter, dev->summary_indicator); + dev->summary_indicator = NULL; + } } static void virtio_ccw_vmstate_change(DeviceState *d, bool running) @@ -1027,6 +1113,79 @@ static int virtio_ccw_set_host_notifier(DeviceState *d, int n, bool assign) return virtio_ccw_set_guest2host_notifier(dev, n, assign, false); } +static int virtio_ccw_get_mappings(VirtioCcwDevice *dev) +{ + int r; + + if (!dev->sch->thinint_active) { + return -EINVAL; + } + + r = map_indicator(&dev->routes.adapter, dev->summary_indicator); + if (r) { + return r; + } + r = map_indicator(&dev->routes.adapter, dev->indicators); + if (r) { + return r; + } + dev->routes.adapter.summary_addr = dev->summary_indicator->map; + dev->routes.adapter.ind_addr = dev->indicators->map; + + return 0; +} + +static int virtio_ccw_setup_irqroutes(VirtioCcwDevice *dev, int nvqs) +{ + int i; + VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); + int ret; + S390FLICState *fs = s390_get_flic(); + S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs); + + ret = virtio_ccw_get_mappings(dev); + if (ret) { + return ret; + } + for (i = 0; i < nvqs; i++) { + if (!virtio_queue_get_num(vdev, i)) { + break; + } + } + dev->routes.num_routes = i; + return fsc->add_adapter_routes(fs, &dev->routes); +} + +static void virtio_ccw_release_irqroutes(VirtioCcwDevice *dev, int nvqs) +{ + S390FLICState *fs = s390_get_flic(); + S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs); + + fsc->release_adapter_routes(fs, &dev->routes); +} + +static int virtio_ccw_add_irqfd(VirtioCcwDevice *dev, int n) +{ + VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); + VirtQueue *vq = virtio_get_queue(vdev, n); + EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); + + return kvm_irqchip_add_irqfd_notifier(kvm_state, notifier, NULL, + dev->routes.gsi[n]); +} + +static void virtio_ccw_remove_irqfd(VirtioCcwDevice *dev, int n) +{ + VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); + VirtQueue *vq = virtio_get_queue(vdev, n); + EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); + int ret; + + ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, notifier, + dev->routes.gsi[n]); + assert(ret == 0); +} + static int virtio_ccw_set_guest_notifier(VirtioCcwDevice *dev, int n, bool assign, bool with_irqfd) { @@ -1042,11 +1201,17 @@ static int virtio_ccw_set_guest_notifier(VirtioCcwDevice *dev, int n, return r; } virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd); - /* We do not support irqfd for classic I/O interrupts, because the - * classic interrupts are intermixed with the subchannel status, that - * is queried with test subchannel. We want to use vhost, though. - * Lets make sure to have vhost running and wire up the irq fd to - * land in qemu (and only the irq fd) in this code. + if (with_irqfd) { + r = virtio_ccw_add_irqfd(dev, n); + if (r) { + virtio_queue_set_guest_notifier_fd_handler(vq, false, + with_irqfd); + return r; + } + } + /* + * We do not support individual masking for channel devices, so we + * need to manually trigger any guest masking callbacks here. */ if (k->guest_notifier_mask) { k->guest_notifier_mask(vdev, n, false); @@ -1060,6 +1225,9 @@ static int virtio_ccw_set_guest_notifier(VirtioCcwDevice *dev, int n, if (k->guest_notifier_mask) { k->guest_notifier_mask(vdev, n, true); } + if (with_irqfd) { + virtio_ccw_remove_irqfd(dev, n); + } virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd); event_notifier_cleanup(notifier); } @@ -1071,24 +1239,39 @@ static int virtio_ccw_set_guest_notifiers(DeviceState *d, int nvqs, { VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); + bool with_irqfd = dev->sch->thinint_active && kvm_irqfds_enabled(); int r, n; + if (with_irqfd && assigned) { + /* irq routes need to be set up before assigning irqfds */ + r = virtio_ccw_setup_irqroutes(dev, nvqs); + if (r < 0) { + goto irqroute_error; + } + } for (n = 0; n < nvqs; n++) { if (!virtio_queue_get_num(vdev, n)) { break; } - /* false -> true, as soon as irqfd works */ - r = virtio_ccw_set_guest_notifier(dev, n, assigned, false); + r = virtio_ccw_set_guest_notifier(dev, n, assigned, with_irqfd); if (r < 0) { goto assign_error; } } + if (with_irqfd && !assigned) { + /* release irq routes after irqfds have been released */ + virtio_ccw_release_irqroutes(dev, nvqs); + } return 0; assign_error: while (--n >= 0) { virtio_ccw_set_guest_notifier(dev, n, !assigned, false); } +irqroute_error: + if (with_irqfd && assigned) { + virtio_ccw_release_irqroutes(dev, nvqs); + } return r; } diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h index 4393e44814..b8b8a8abaa 100644 --- a/hw/s390x/virtio-ccw.h +++ b/hw/s390x/virtio-ccw.h @@ -22,6 +22,7 @@ #include <hw/virtio/virtio-balloon.h> #include <hw/virtio/virtio-rng.h> #include <hw/virtio/virtio-bus.h> +#include <hw/s390x/s390_flic.h> #define VIRTUAL_CSSID 0xfe @@ -75,6 +76,14 @@ typedef struct VirtIOCCWDeviceClass { #define VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT 1 #define VIRTIO_CCW_FLAG_USE_IOEVENTFD (1 << VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT) +typedef struct IndAddr { + hwaddr addr; + uint64_t map; + unsigned long refcnt; + int len; + QTAILQ_ENTRY(IndAddr) sibling; +} IndAddr; + struct VirtioCcwDevice { DeviceState parent_obj; SubchDev *sch; @@ -85,10 +94,11 @@ struct VirtioCcwDevice { bool ioeventfd_disabled; uint32_t flags; uint8_t thinint_isc; + AdapterRoutes routes; /* Guest provided values: */ - hwaddr indicators; - hwaddr indicators2; - hwaddr summary_indicator; + IndAddr *indicators; + IndAddr *indicators2; + IndAddr *summary_indicator; uint64_t ind_bit; }; diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index e6e1ffd1bb..0e109a2844 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -21,6 +21,7 @@ #include "hw/hw.h" #include "hw/pci/pci.h" #include "sysemu/dma.h" +#include "hw/pci/msi.h" #include "hw/pci/msix.h" #include "qemu/iov.h" #include "hw/scsi/scsi.h" @@ -43,9 +44,11 @@ #define MEGASAS_FLAG_USE_JBOD 0 #define MEGASAS_MASK_USE_JBOD (1 << MEGASAS_FLAG_USE_JBOD) -#define MEGASAS_FLAG_USE_MSIX 1 +#define MEGASAS_FLAG_USE_MSI 1 +#define MEGASAS_MASK_USE_MSI (1 << MEGASAS_FLAG_USE_MSI) +#define MEGASAS_FLAG_USE_MSIX 2 #define MEGASAS_MASK_USE_MSIX (1 << MEGASAS_FLAG_USE_MSIX) -#define MEGASAS_FLAG_USE_QUEUE64 2 +#define MEGASAS_FLAG_USE_QUEUE64 3 #define MEGASAS_MASK_USE_QUEUE64 (1 << MEGASAS_FLAG_USE_QUEUE64) static const char *mfi_frame_desc[] = { @@ -132,6 +135,11 @@ static bool megasas_use_queue64(MegasasState *s) return s->flags & MEGASAS_MASK_USE_QUEUE64; } +static bool megasas_use_msi(MegasasState *s) +{ + return s->flags & MEGASAS_MASK_USE_MSI; +} + static bool megasas_use_msix(MegasasState *s) { return s->flags & MEGASAS_MASK_USE_MSIX; @@ -538,6 +546,9 @@ static void megasas_complete_frame(MegasasState *s, uint64_t context) if (msix_enabled(pci_dev)) { trace_megasas_msix_raise(0); msix_notify(pci_dev, 0); + } else if (msi_enabled(pci_dev)) { + trace_megasas_msi_raise(0); + msi_notify(pci_dev, 0); } else { trace_megasas_irq_raise(); pci_irq_assert(pci_dev); @@ -717,8 +728,8 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd) snprintf(info.package_version, 0x60, "%s-QEMU", QEMU_VERSION); memcpy(info.image_component[0].name, "APP", 3); memcpy(info.image_component[0].version, MEGASAS_VERSION "-QEMU", 9); - memcpy(info.image_component[0].build_date, __DATE__, 11); - memcpy(info.image_component[0].build_time, __TIME__, 8); + memcpy(info.image_component[0].build_date, "Apr 1 2014", 11); + memcpy(info.image_component[0].build_time, "12:34:56", 8); info.image_component_count = 1; if (pci_dev->has_rom) { uint8_t biosver[32]; @@ -1106,6 +1117,21 @@ static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd) return MFI_STAT_OK; } +static int megasas_dcmd_ld_list_query(MegasasState *s, MegasasCmd *cmd) +{ + uint16_t flags; + + /* mbox0 contains flags */ + flags = le16_to_cpu(cmd->frame->dcmd.mbox[0]); + trace_megasas_dcmd_ld_list_query(cmd->index, flags); + if (flags == MR_LD_QUERY_TYPE_ALL || + flags == MR_LD_QUERY_TYPE_EXPOSED_TO_HOST) { + return megasas_dcmd_ld_get_list(s, cmd); + } + + return MFI_STAT_OK; +} + static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun, MegasasCmd *cmd) { @@ -1409,6 +1435,8 @@ static const struct dcmd_cmd_tbl_t { megasas_dcmd_dummy }, { MFI_DCMD_LD_GET_LIST, "LD_GET_LIST", megasas_dcmd_ld_get_list}, + { MFI_DCMD_LD_LIST_QUERY, "LD_LIST_QUERY", + megasas_dcmd_ld_list_query }, { MFI_DCMD_LD_GET_INFO, "LD_GET_INFO", megasas_dcmd_ld_get_info }, { MFI_DCMD_LD_GET_PROP, "LD_GET_PROP", @@ -1939,12 +1967,20 @@ static void megasas_mmio_write(void *opaque, hwaddr addr, break; case MFI_OMSK: s->intr_mask = val; - if (!megasas_intr_enabled(s) && !msix_enabled(pci_dev)) { + if (!megasas_intr_enabled(s) && + !msi_enabled(pci_dev) && + !msix_enabled(pci_dev)) { trace_megasas_irq_lower(); pci_irq_deassert(pci_dev); } if (megasas_intr_enabled(s)) { - trace_megasas_intr_enabled(); + if (msix_enabled(pci_dev)) { + trace_megasas_msix_enabled(0); + } else if (msi_enabled(pci_dev)) { + trace_megasas_msi_enabled(0); + } else { + trace_megasas_intr_enabled(); + } } else { trace_megasas_intr_disabled(); } @@ -2068,6 +2104,7 @@ static const VMStateDescription vmstate_megasas = { .minimum_version_id_old = 0, .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(parent_obj, MegasasState), + VMSTATE_MSIX(parent_obj, MegasasState), VMSTATE_INT32(fw_state, MegasasState), VMSTATE_INT32(intr_mask, MegasasState), @@ -2083,9 +2120,12 @@ static void megasas_scsi_uninit(PCIDevice *d) { MegasasState *s = MEGASAS(d); -#ifdef USE_MSIX - msix_uninit(d, &s->mmio_io); -#endif + if (megasas_use_msix(s)) { + msix_uninit(d, &s->mmio_io, &s->mmio_io); + } + if (megasas_use_msi(s)) { + msi_uninit(d); + } memory_region_destroy(&s->mmio_io); memory_region_destroy(&s->port_io); memory_region_destroy(&s->queue_io); @@ -2124,15 +2164,15 @@ static int megasas_scsi_init(PCIDevice *dev) memory_region_init_io(&s->queue_io, OBJECT(s), &megasas_queue_ops, s, "megasas-queue", 0x40000); -#ifdef USE_MSIX - /* MSI-X support is currently broken */ + if (megasas_use_msi(s) && + msi_init(dev, 0x50, 1, true, false)) { + s->flags &= ~MEGASAS_MASK_USE_MSI; + } if (megasas_use_msix(s) && - msix_init(dev, 15, &s->mmio_io, 0, 0x2000)) { + msix_init(dev, 15, &s->mmio_io, 0, 0x2000, + &s->mmio_io, 0, 0x3800, 0x68)) { s->flags &= ~MEGASAS_MASK_USE_MSIX; } -#else - s->flags &= ~MEGASAS_MASK_USE_MSIX; -#endif bar_type = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64; pci_register_bar(dev, 0, bar_type, &s->mmio_io); @@ -2151,7 +2191,7 @@ static int megasas_scsi_init(PCIDevice *dev) s->sas_addr |= PCI_FUNC(dev->devfn); } if (!s->hba_serial) { - s->hba_serial = g_strdup(MEGASAS_HBA_SERIAL); + s->hba_serial = g_strdup(MEGASAS_HBA_SERIAL); } if (s->fw_sge >= MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE) { s->fw_sge = MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE; @@ -2164,7 +2204,6 @@ static int megasas_scsi_init(PCIDevice *dev) s->fw_cmds = MEGASAS_MAX_FRAMES; } trace_megasas_init(s->fw_sge, s->fw_cmds, - megasas_use_msix(s) ? "MSI-X" : "INTx", megasas_is_jbod(s) ? "jbod" : "raid"); s->fw_luns = (MFI_MAX_LD > MAX_SCSI_DEVS) ? MAX_SCSI_DEVS : MFI_MAX_LD; @@ -2189,6 +2228,13 @@ static int megasas_scsi_init(PCIDevice *dev) return 0; } +static void +megasas_write_config(PCIDevice *pci, uint32_t addr, uint32_t val, int len) +{ + pci_default_write_config(pci, addr, val, len); + msi_write_config(pci, addr, val, len); +} + static Property megasas_properties[] = { DEFINE_PROP_UINT32("max_sge", MegasasState, fw_sge, MEGASAS_DEFAULT_SGE), @@ -2196,10 +2242,10 @@ static Property megasas_properties[] = { MEGASAS_DEFAULT_FRAMES), DEFINE_PROP_STRING("hba_serial", MegasasState, hba_serial), DEFINE_PROP_UINT64("sas_address", MegasasState, sas_addr, 0), -#ifdef USE_MSIX + DEFINE_PROP_BIT("use_msi", MegasasState, flags, + MEGASAS_FLAG_USE_MSI, false), DEFINE_PROP_BIT("use_msix", MegasasState, flags, MEGASAS_FLAG_USE_MSIX, false), -#endif DEFINE_PROP_BIT("use_jbod", MegasasState, flags, MEGASAS_FLAG_USE_JBOD, false), DEFINE_PROP_END_OF_LIST(), @@ -2222,6 +2268,7 @@ static void megasas_class_init(ObjectClass *oc, void *data) dc->vmsd = &vmstate_megasas; set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->desc = "LSI MegaRAID SAS 1078"; + pc->config_write = megasas_write_config; } static const TypeInfo megasas_info = { diff --git a/hw/scsi/mfi.h b/hw/scsi/mfi.h index cd8355badf..a3034f6239 100644 --- a/hw/scsi/mfi.h +++ b/hw/scsi/mfi.h @@ -164,6 +164,7 @@ typedef enum { MFI_DCMD_PD_BLINK = 0x02070100, MFI_DCMD_PD_UNBLINK = 0x02070200, MFI_DCMD_LD_GET_LIST = 0x03010000, + MFI_DCMD_LD_LIST_QUERY = 0x03010100, MFI_DCMD_LD_GET_INFO = 0x03020000, MFI_DCMD_LD_GET_PROP = 0x03030000, MFI_DCMD_LD_SET_PROP = 0x03040000, @@ -411,6 +412,14 @@ typedef enum { MR_PD_QUERY_TYPE_EXPOSED_TO_HOST = 5, /*query for system drives */ } mfi_pd_query_type; +typedef enum { + MR_LD_QUERY_TYPE_ALL = 0, + MR_LD_QUERY_TYPE_EXPOSED_TO_HOST = 1, + MR_LD_QUERY_TYPE_USED_TGT_IDS = 2, + MR_LD_QUERY_TYPE_CLUSTER_ACCESS = 3, + MR_LD_QUERY_TYPE_CLUSTER_LOCALE = 4, +} mfi_ld_query_type; + /* * Other propertities and definitions */ diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index abe73022c0..06399fa37e 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -938,6 +938,7 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) if (cmd->xfer == 0) { cmd->xfer = 256; } + /* fall through */ case WRITE_10: case WRITE_VERIFY_10: case WRITE_12: @@ -952,6 +953,7 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) if (cmd->xfer == 0) { cmd->xfer = 256; } + /* fall through */ case READ_10: case RECOVER_BUFFERED_DATA: case READ_12: diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 48a28ae199..4bcef551a6 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -2458,21 +2458,27 @@ static int scsi_block_initfn(SCSIDevice *dev) int rc; if (!s->qdev.conf.bs) { - error_report("scsi-block: drive property not set"); + error_report("drive property not set"); return -1; } /* check we are using a driver managing SG_IO (version 3 and after) */ - if (bdrv_ioctl(s->qdev.conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0 || - sg_version < 30000) { - error_report("scsi-block: scsi generic interface too old"); + rc = bdrv_ioctl(s->qdev.conf.bs, SG_GET_VERSION_NUM, &sg_version); + if (rc < 0) { + error_report("cannot get SG_IO version number: %s. " + "Is this a SCSI device?", + strerror(-rc)); + return -1; + } + if (sg_version < 30000) { + error_report("scsi generic interface too old"); return -1; } /* get device type from INQUIRY data */ rc = get_device_type(s); if (rc < 0) { - error_report("scsi-block: INQUIRY failed"); + error_report("INQUIRY failed"); return -1; } diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index 8d92e0da15..3733d2c36c 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -394,6 +394,7 @@ static void scsi_destroy(SCSIDevice *s) static int scsi_generic_initfn(SCSIDevice *s) { + int rc; int sg_version; struct sg_scsi_id scsiid; @@ -412,8 +413,11 @@ static int scsi_generic_initfn(SCSIDevice *s) } /* check we are using a driver managing SG_IO (version 3 and after */ - if (bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0) { - error_report("scsi generic interface not supported"); + rc = bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version); + if (rc < 0) { + error_report("cannot get SG_IO version number: %s. " + "Is this a SCSI device?", + strerror(-rc)); return -1; } if (sg_version < 30000) { diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 175219376c..14261fb1a7 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -498,7 +498,7 @@ static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, uint32_t event, uint32_t reason) { VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); - VirtIOSCSIReq *req = virtio_scsi_pop_req(s, vs->event_vq); + VirtIOSCSIReq *req; VirtIOSCSIEvent *evt; VirtIODevice *vdev = VIRTIO_DEVICE(s); int in_size; @@ -507,6 +507,7 @@ static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, return; } + req = virtio_scsi_pop_req(s, vs->event_vq); if (!req) { s->events_dropped = true; return; diff --git a/hw/sh4/r2d.c b/hw/sh4/r2d.c index eaeb7ede4e..95c0246d47 100644 --- a/hw/sh4/r2d.c +++ b/hw/sh4/r2d.c @@ -219,12 +219,12 @@ static struct QEMU_PACKED char kernel_cmdline[256]; } boot_params; -static void r2d_init(QEMUMachineInitArgs *args) +static void r2d_init(MachineState *machine) { - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; SuperHCPU *cpu; CPUSH4State *env; ResetData *reset_info; diff --git a/hw/sh4/shix.c b/hw/sh4/shix.c index 904a966700..7c152b4a3a 100644 --- a/hw/sh4/shix.c +++ b/hw/sh4/shix.c @@ -39,9 +39,9 @@ #define BIOS_FILENAME "shix_bios.bin" #define BIOS_ADDRESS 0xA0000000 -static void shix_init(QEMUMachineInitArgs *args) +static void shix_init(MachineState *machine) { - const char *cpu_model = args->cpu_model; + const char *cpu_model = machine->cpu_model; int ret; SuperHCPU *cpu; struct SH7750State *s; diff --git a/hw/sparc/leon3.c b/hw/sparc/leon3.c index c16e9e4c81..827383b02f 100644 --- a/hw/sparc/leon3.c +++ b/hw/sparc/leon3.c @@ -101,11 +101,11 @@ static void leon3_set_pil_in(void *opaque, uint32_t pil_in) } } -static void leon3_generic_hw_init(QEMUMachineInitArgs *args) +static void leon3_generic_hw_init(MachineState *machine) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; SPARCCPU *cpu; CPUSPARCState *env; MemoryRegion *address_space_mem = get_system_memory(); diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 75adb68abc..4e793c2760 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -867,9 +867,9 @@ static void dummy_fdc_tc(void *opaque, int irq, int level) } static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, - QEMUMachineInitArgs *args) + MachineState *machine) { - const char *cpu_model = args->cpu_model; + const char *cpu_model = machine->cpu_model; unsigned int i; void *iommu, *espdma, *ledma, *nvram; qemu_irq *cpu_irqs[MAX_CPUS], slavio_irq[32], slavio_cpu_irq[MAX_CPUS], @@ -895,10 +895,10 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, /* set up devices */ - ram_init(0, args->ram_size, hwdef->max_mem); + ram_init(0, machine->ram_size, hwdef->max_mem); /* models without ECC don't trap when missing ram is accessed */ if (!hwdef->ecc_base) { - empty_slot_init(args->ram_size, hwdef->max_mem - args->ram_size); + empty_slot_init(machine->ram_size, hwdef->max_mem - machine->ram_size); } prom_init(hwdef->slavio_base, bios_name); @@ -1051,14 +1051,14 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, empty_slot_init(hwdef->bpp_base, 0x20); } - kernel_size = sun4m_load_kernel(args->kernel_filename, - args->initrd_filename, - args->ram_size); + kernel_size = sun4m_load_kernel(machine->kernel_filename, + machine->initrd_filename, + machine->ram_size); - nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, args->kernel_cmdline, - args->boot_order, args->ram_size, kernel_size, graphic_width, - graphic_height, graphic_depth, hwdef->nvram_machine_id, - "Sun4m"); + nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, machine->kernel_cmdline, + machine->boot_order, machine->ram_size, kernel_size, + graphic_width, graphic_height, graphic_depth, + hwdef->nvram_machine_id, "Sun4m"); if (hwdef->ecc_base) ecc_init(hwdef->ecc_base, slavio_irq[28], @@ -1074,20 +1074,20 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_HEIGHT, graphic_height); fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, KERNEL_LOAD_ADDR); fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); - if (args->kernel_cmdline) { + if (machine->kernel_cmdline) { fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR); pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, - args->kernel_cmdline); - fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, args->kernel_cmdline); + machine->kernel_cmdline); + fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, machine->kernel_cmdline); fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, - strlen(args->kernel_cmdline) + 1); + strlen(machine->kernel_cmdline) + 1); } else { fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0); fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0); } fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR); fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, 0); // not used - fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, args->boot_order[0]); + fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, machine->boot_order[0]); qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); } @@ -1349,57 +1349,57 @@ static const struct sun4m_hwdef sun4m_hwdefs[] = { }; /* SPARCstation 5 hardware initialisation */ -static void ss5_init(QEMUMachineInitArgs *args) +static void ss5_init(MachineState *machine) { - sun4m_hw_init(&sun4m_hwdefs[0], args); + sun4m_hw_init(&sun4m_hwdefs[0], machine); } /* SPARCstation 10 hardware initialisation */ -static void ss10_init(QEMUMachineInitArgs *args) +static void ss10_init(MachineState *machine) { - sun4m_hw_init(&sun4m_hwdefs[1], args); + sun4m_hw_init(&sun4m_hwdefs[1], machine); } /* SPARCserver 600MP hardware initialisation */ -static void ss600mp_init(QEMUMachineInitArgs *args) +static void ss600mp_init(MachineState *machine) { - sun4m_hw_init(&sun4m_hwdefs[2], args); + sun4m_hw_init(&sun4m_hwdefs[2], machine); } /* SPARCstation 20 hardware initialisation */ -static void ss20_init(QEMUMachineInitArgs *args) +static void ss20_init(MachineState *machine) { - sun4m_hw_init(&sun4m_hwdefs[3], args); + sun4m_hw_init(&sun4m_hwdefs[3], machine); } /* SPARCstation Voyager hardware initialisation */ -static void vger_init(QEMUMachineInitArgs *args) +static void vger_init(MachineState *machine) { - sun4m_hw_init(&sun4m_hwdefs[4], args); + sun4m_hw_init(&sun4m_hwdefs[4], machine); } /* SPARCstation LX hardware initialisation */ -static void ss_lx_init(QEMUMachineInitArgs *args) +static void ss_lx_init(MachineState *machine) { - sun4m_hw_init(&sun4m_hwdefs[5], args); + sun4m_hw_init(&sun4m_hwdefs[5], machine); } /* SPARCstation 4 hardware initialisation */ -static void ss4_init(QEMUMachineInitArgs *args) +static void ss4_init(MachineState *machine) { - sun4m_hw_init(&sun4m_hwdefs[6], args); + sun4m_hw_init(&sun4m_hwdefs[6], machine); } /* SPARCClassic hardware initialisation */ -static void scls_init(QEMUMachineInitArgs *args) +static void scls_init(MachineState *machine) { - sun4m_hw_init(&sun4m_hwdefs[7], args); + sun4m_hw_init(&sun4m_hwdefs[7], machine); } /* SPARCbook hardware initialisation */ -static void sbook_init(QEMUMachineInitArgs *args) +static void sbook_init(MachineState *machine) { - sun4m_hw_init(&sun4m_hwdefs[8], args); + sun4m_hw_init(&sun4m_hwdefs[8], machine); } static QEMUMachine ss5_machine = { diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 6f271d9cfc..33c311bf28 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -811,7 +811,7 @@ static SPARCCPU *cpu_devinit(const char *cpu_model, const struct hwdef *hwdef) } static void sun4uv_init(MemoryRegion *address_space_mem, - QEMUMachineInitArgs *args, + MachineState *machine, const struct hwdef *hwdef) { SPARCCPU *cpu; @@ -826,10 +826,10 @@ static void sun4uv_init(MemoryRegion *address_space_mem, FWCfgState *fw_cfg; /* init CPUs */ - cpu = cpu_devinit(args->cpu_model, hwdef); + cpu = cpu_devinit(machine->cpu_model, hwdef); /* set up devices */ - ram_init(0, args->ram_size); + ram_init(0, machine->ram_size); prom_init(hwdef->prom_addr, bios_name); @@ -875,15 +875,15 @@ static void sun4uv_init(MemoryRegion *address_space_mem, initrd_size = 0; initrd_addr = 0; - kernel_size = sun4u_load_kernel(args->kernel_filename, - args->initrd_filename, + kernel_size = sun4u_load_kernel(machine->kernel_filename, + machine->initrd_filename, ram_size, &initrd_size, &initrd_addr, &kernel_addr, &kernel_entry); - sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", args->ram_size, - args->boot_order, + sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", machine->ram_size, + machine->boot_order, kernel_addr, kernel_size, - args->kernel_cmdline, + machine->kernel_cmdline, initrd_addr, initrd_size, /* XXX: need an option to load a NVRAM image */ 0, @@ -897,16 +897,16 @@ static void sun4uv_init(MemoryRegion *address_space_mem, fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_entry); fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); - if (args->kernel_cmdline) { + if (machine->kernel_cmdline) { fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, - strlen(args->kernel_cmdline) + 1); - fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, args->kernel_cmdline); + strlen(machine->kernel_cmdline) + 1); + fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, machine->kernel_cmdline); } else { fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0); } fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr); fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size); - fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, args->boot_order[0]); + fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, machine->boot_order[0]); fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_WIDTH, graphic_width); fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_HEIGHT, graphic_height); @@ -946,21 +946,21 @@ static const struct hwdef hwdefs[] = { }; /* Sun4u hardware initialisation */ -static void sun4u_init(QEMUMachineInitArgs *args) +static void sun4u_init(MachineState *machine) { - sun4uv_init(get_system_memory(), args, &hwdefs[0]); + sun4uv_init(get_system_memory(), machine, &hwdefs[0]); } /* Sun4v hardware initialisation */ -static void sun4v_init(QEMUMachineInitArgs *args) +static void sun4v_init(MachineState *machine) { - sun4uv_init(get_system_memory(), args, &hwdefs[1]); + sun4uv_init(get_system_memory(), machine, &hwdefs[1]); } /* Niagara hardware initialisation */ -static void niagara_init(QEMUMachineInitArgs *args) +static void niagara_init(MachineState *machine) { - sun4uv_init(get_system_memory(), args, &hwdefs[2]); + sun4uv_init(get_system_memory(), machine, &hwdefs[2]); } static QEMUMachine sun4u_machine = { diff --git a/hw/ssi/ssi.c b/hw/ssi/ssi.c index 1c82a93590..2aab79ba7f 100644 --- a/hw/ssi/ssi.c +++ b/hw/ssi/ssi.c @@ -60,7 +60,7 @@ static int ssi_slave_init(DeviceState *dev) if (ssc->transfer_raw == ssi_transfer_raw_default && ssc->cs_polarity != SSI_CS_NONE) { - qdev_init_gpio_in(dev, ssi_cs_default, 1); + qdev_init_gpio_in_named(dev, ssi_cs_default, SSI_GPIO_CS, 1); } return ssc->init(s); @@ -155,7 +155,7 @@ static int ssi_auto_connect_slave(Object *child, void *opaque) return 0; } - cs_line = qdev_get_gpio_in(DEVICE(dev), 0); + cs_line = qdev_get_gpio_in_named(DEVICE(dev), SSI_GPIO_CS, 0); qdev_set_parent_bus(DEVICE(dev), BUS(arg->bus)); **arg->cs_linep = cs_line; (*arg->cs_linep)++; diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c index 8509309fa7..df54546562 100644 --- a/hw/timer/mc146818rtc.c +++ b/hw/timer/mc146818rtc.c @@ -793,19 +793,46 @@ static const MemoryRegionOps cmos_ops = { static void rtc_get_date(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { + Error *err = NULL; RTCState *s = MC146818_RTC(obj); struct tm current_tm; rtc_update_time(s); rtc_get_time(s, ¤t_tm); - visit_start_struct(v, NULL, "struct tm", name, 0, errp); - visit_type_int32(v, ¤t_tm.tm_year, "tm_year", errp); - visit_type_int32(v, ¤t_tm.tm_mon, "tm_mon", errp); - visit_type_int32(v, ¤t_tm.tm_mday, "tm_mday", errp); - visit_type_int32(v, ¤t_tm.tm_hour, "tm_hour", errp); - visit_type_int32(v, ¤t_tm.tm_min, "tm_min", errp); - visit_type_int32(v, ¤t_tm.tm_sec, "tm_sec", errp); + visit_start_struct(v, NULL, "struct tm", name, 0, &err); + if (err) { + goto out; + } + visit_type_int32(v, ¤t_tm.tm_year, "tm_year", &err); + if (err) { + goto out_end; + } + visit_type_int32(v, ¤t_tm.tm_mon, "tm_mon", &err); + if (err) { + goto out_end; + } + visit_type_int32(v, ¤t_tm.tm_mday, "tm_mday", &err); + if (err) { + goto out_end; + } + visit_type_int32(v, ¤t_tm.tm_hour, "tm_hour", &err); + if (err) { + goto out_end; + } + visit_type_int32(v, ¤t_tm.tm_min, "tm_min", &err); + if (err) { + goto out_end; + } + visit_type_int32(v, ¤t_tm.tm_sec, "tm_sec", &err); + if (err) { + goto out_end; + } +out_end: + error_propagate(errp, err); + err = NULL; visit_end_struct(v, errp); +out: + error_propagate(errp, err); } static void rtc_realizefn(DeviceState *dev, Error **errp) diff --git a/hw/unicore32/puv3.c b/hw/unicore32/puv3.c index 42913b6a5a..08dd4d04cb 100644 --- a/hw/unicore32/puv3.c +++ b/hw/unicore32/puv3.c @@ -101,12 +101,12 @@ static void puv3_load_kernel(const char *kernel_filename) graphic_console_init(NULL, 0, &no_ops, NULL); } -static void puv3_init(QEMUMachineInitArgs *args) +static void puv3_init(MachineState *machine) { - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *initrd_filename = args->initrd_filename; + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *initrd_filename = machine->initrd_filename; CPUUniCore32State *env; if (initrd_filename) { diff --git a/hw/usb/core.c b/hw/usb/core.c index 67ba7d6018..cf34755bba 100644 --- a/hw/usb/core.c +++ b/hw/usb/core.c @@ -28,6 +28,26 @@ #include "qemu/iov.h" #include "trace.h" +void usb_pick_speed(USBPort *port) +{ + static const int speeds[] = { + USB_SPEED_SUPER, + USB_SPEED_HIGH, + USB_SPEED_FULL, + USB_SPEED_LOW, + }; + USBDevice *udev = port->dev; + int i; + + for (i = 0; i < ARRAY_SIZE(speeds); i++) { + if ((udev->speedmask & (1 << speeds[i])) && + (port->speedmask & (1 << speeds[i]))) { + udev->speed = speeds[i]; + return; + } + } +} + void usb_attach(USBPort *port) { USBDevice *dev = port->dev; @@ -35,6 +55,7 @@ void usb_attach(USBPort *port) assert(dev != NULL); assert(dev->attached); assert(dev->state == USB_STATE_NOTATTACHED); + usb_pick_speed(port); port->ops->attach(port); dev->state = USB_STATE_ATTACHED; usb_device_handle_attach(dev); diff --git a/hw/usb/desc.c b/hw/usb/desc.c index ab48691363..b82c397ef9 100644 --- a/hw/usb/desc.c +++ b/hw/usb/desc.c @@ -518,18 +518,6 @@ void usb_desc_init(USBDevice *dev) void usb_desc_attach(USBDevice *dev) { - const USBDesc *desc = usb_device_get_usb_desc(dev); - - assert(desc != NULL); - if (desc->super && (dev->port->speedmask & USB_SPEED_MASK_SUPER)) { - dev->speed = USB_SPEED_SUPER; - } else if (desc->high && (dev->port->speedmask & USB_SPEED_MASK_HIGH)) { - dev->speed = USB_SPEED_HIGH; - } else if (desc->full && (dev->port->speedmask & USB_SPEED_MASK_FULL)) { - dev->speed = USB_SPEED_FULL; - } else { - return; - } usb_desc_setdefaults(dev); } diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index d097d937ea..67a57f1dcd 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -47,6 +47,8 @@ typedef struct USBHIDState { USBEndpoint *intr; HIDState hid; uint32_t usb_version; + char *display; + uint32_t head; } USBHIDState; enum { @@ -574,6 +576,9 @@ static int usb_hid_initfn(USBDevice *dev, int kind) usb_desc_init(dev); us->intr = usb_ep_get(dev, USB_TOKEN_IN, 1); hid_init(&us->hid, kind, usb_hid_changed); + if (us->display && us->hid.s) { + qemu_input_handler_bind(us->hid.s, us->display, us->head, NULL); + } return 0; } @@ -653,6 +658,8 @@ static void usb_hid_class_initfn(ObjectClass *klass, void *data) static Property usb_tablet_properties[] = { DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2), + DEFINE_PROP_STRING("display", USBHIDState, display), + DEFINE_PROP_UINT32("head", USBHIDState, head, 0), DEFINE_PROP_END_OF_LIST(), }; @@ -696,6 +703,11 @@ static const TypeInfo usb_mouse_info = { .class_init = usb_mouse_class_initfn, }; +static Property usb_keyboard_properties[] = { + DEFINE_PROP_STRING("display", USBHIDState, display), + DEFINE_PROP_END_OF_LIST(), +}; + static void usb_keyboard_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -706,6 +718,7 @@ static void usb_keyboard_class_initfn(ObjectClass *klass, void *data) uc->product_desc = "QEMU USB Keyboard"; uc->usb_desc = &desc_keyboard; dc->vmsd = &vmstate_usb_kbd; + dc->props = usb_keyboard_properties; set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index 943f930404..380b465621 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -46,6 +46,7 @@ enum mtp_code { /* response codes */ RES_OK = 0x2001, + RES_GENERAL_ERROR = 0x2002, RES_SESSION_NOT_OPEN = 0x2003, RES_INVALID_TRANSACTION_ID = 0x2004, RES_OPERATION_NOT_SUPPORTED = 0x2005, @@ -109,7 +110,8 @@ struct MTPObject { struct stat stat; MTPObject *parent; MTPObject **children; - int32_t nchildren; + uint32_t nchildren; + bool have_children; QTAILQ_ENTRY(MTPObject) next; }; @@ -273,7 +275,6 @@ static MTPObject *usb_mtp_object_alloc(MTPState *s, uint32_t handle, o->handle = handle; o->parent = parent; o->name = g_strdup(name); - o->nchildren = -1; if (parent == NULL) { o->path = g_strdup(name); } else { @@ -340,7 +341,11 @@ static void usb_mtp_object_readdir(MTPState *s, MTPObject *o) struct dirent *entry; DIR *dir; - o->nchildren = 0; + if (o->have_children) { + return; + } + o->have_children = true; + dir = opendir(o->path); if (!dir) { return; @@ -698,7 +703,10 @@ static MTPData *usb_mtp_get_partial_object(MTPState *s, MTPControl *c, if (offset > o->stat.st_size) { offset = o->stat.st_size; } - lseek(d->fd, offset, SEEK_SET); + if (lseek(d->fd, offset, SEEK_SET) < 0) { + usb_mtp_data_free(d); + return NULL; + } d->length = c->argv[2]; if (d->length > o->stat.st_size - offset) { @@ -789,9 +797,7 @@ static void usb_mtp_command(MTPState *s, MTPControl *c) c->trans, 0, 0, 0); return; } - if (o->nchildren == -1) { - usb_mtp_object_readdir(s, o); - } + usb_mtp_object_readdir(s, o); if (c->code == CMD_GET_NUM_OBJECTS) { trace_usb_mtp_op_get_num_objects(s->dev.addr, o->handle, o->path); nres = 1; @@ -823,7 +829,9 @@ static void usb_mtp_command(MTPState *s, MTPControl *c) } data_in = usb_mtp_get_object(s, c, o); if (NULL == data_in) { - fprintf(stderr, "%s: TODO: handle error\n", __func__); + usb_mtp_queue_result(s, RES_GENERAL_ERROR, + c->trans, 0, 0, 0); + return; } break; case CMD_GET_PARTIAL_OBJECT: @@ -840,7 +848,9 @@ static void usb_mtp_command(MTPState *s, MTPControl *c) } data_in = usb_mtp_get_partial_object(s, c, o); if (NULL == data_in) { - fprintf(stderr, "%s: TODO: handle error\n", __func__); + usb_mtp_queue_result(s, RES_GENERAL_ERROR, + c->trans, 0, 0, 0); + return; } nres = 1; res0 = data_in->length; diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index a3ae9f260a..a00a93c3eb 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -27,87 +27,10 @@ * along with this program; if not, see <http://www.gnu.org/licenses/>. */ +#include "hw/usb/ehci-regs.h" #include "hw/usb/hcd-ehci.h" #include "trace.h" -/* Capability Registers Base Address - section 2.2 */ -#define CAPLENGTH 0x0000 /* 1-byte, 0x0001 reserved */ -#define HCIVERSION 0x0002 /* 2-bytes, i/f version # */ -#define HCSPARAMS 0x0004 /* 4-bytes, structural params */ -#define HCCPARAMS 0x0008 /* 4-bytes, capability params */ -#define EECP HCCPARAMS + 1 -#define HCSPPORTROUTE1 0x000c -#define HCSPPORTROUTE2 0x0010 - -#define USBCMD 0x0000 -#define USBCMD_RUNSTOP (1 << 0) // run / Stop -#define USBCMD_HCRESET (1 << 1) // HC Reset -#define USBCMD_FLS (3 << 2) // Frame List Size -#define USBCMD_FLS_SH 2 // Frame List Size Shift -#define USBCMD_PSE (1 << 4) // Periodic Schedule Enable -#define USBCMD_ASE (1 << 5) // Asynch Schedule Enable -#define USBCMD_IAAD (1 << 6) // Int Asynch Advance Doorbell -#define USBCMD_LHCR (1 << 7) // Light Host Controller Reset -#define USBCMD_ASPMC (3 << 8) // Async Sched Park Mode Count -#define USBCMD_ASPME (1 << 11) // Async Sched Park Mode Enable -#define USBCMD_ITC (0x7f << 16) // Int Threshold Control -#define USBCMD_ITC_SH 16 // Int Threshold Control Shift - -#define USBSTS 0x0004 -#define USBSTS_RO_MASK 0x0000003f -#define USBSTS_INT (1 << 0) // USB Interrupt -#define USBSTS_ERRINT (1 << 1) // Error Interrupt -#define USBSTS_PCD (1 << 2) // Port Change Detect -#define USBSTS_FLR (1 << 3) // Frame List Rollover -#define USBSTS_HSE (1 << 4) // Host System Error -#define USBSTS_IAA (1 << 5) // Interrupt on Async Advance -#define USBSTS_HALT (1 << 12) // HC Halted -#define USBSTS_REC (1 << 13) // Reclamation -#define USBSTS_PSS (1 << 14) // Periodic Schedule Status -#define USBSTS_ASS (1 << 15) // Asynchronous Schedule Status - -/* - * Interrupt enable bits correspond to the interrupt active bits in USBSTS - * so no need to redefine here. - */ -#define USBINTR 0x0008 -#define USBINTR_MASK 0x0000003f - -#define FRINDEX 0x000c -#define CTRLDSSEGMENT 0x0010 -#define PERIODICLISTBASE 0x0014 -#define ASYNCLISTADDR 0x0018 -#define ASYNCLISTADDR_MASK 0xffffffe0 - -#define CONFIGFLAG 0x0040 - -/* - * Bits that are reserved or are read-only are masked out of values - * written to us by software - */ -#define PORTSC_RO_MASK 0x007001c0 -#define PORTSC_RWC_MASK 0x0000002a -#define PORTSC_WKOC_E (1 << 22) // Wake on Over Current Enable -#define PORTSC_WKDS_E (1 << 21) // Wake on Disconnect Enable -#define PORTSC_WKCN_E (1 << 20) // Wake on Connect Enable -#define PORTSC_PTC (15 << 16) // Port Test Control -#define PORTSC_PTC_SH 16 // Port Test Control shift -#define PORTSC_PIC (3 << 14) // Port Indicator Control -#define PORTSC_PIC_SH 14 // Port Indicator Control Shift -#define PORTSC_POWNER (1 << 13) // Port Owner -#define PORTSC_PPOWER (1 << 12) // Port Power -#define PORTSC_LINESTAT (3 << 10) // Port Line Status -#define PORTSC_LINESTAT_SH 10 // Port Line Status Shift -#define PORTSC_PRESET (1 << 8) // Port Reset -#define PORTSC_SUSPEND (1 << 7) // Port Suspend -#define PORTSC_FPRES (1 << 6) // Force Port Resume -#define PORTSC_OCC (1 << 5) // Over Current Change -#define PORTSC_OCA (1 << 4) // Over Current Active -#define PORTSC_PEDC (1 << 3) // Port Enable/Disable Change -#define PORTSC_PED (1 << 2) // Port Enable/Disable -#define PORTSC_CSC (1 << 1) // Connect Status Change -#define PORTSC_CONNECT (1 << 0) // Current Connect Status - #define FRAME_TIMER_FREQ 1000 #define FRAME_TIMER_NS (1000000000 / FRAME_TIMER_FREQ) #define UFRAME_TIMER_NS (FRAME_TIMER_NS / 8) diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index 9b1166b2ef..c3bf72cc17 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -27,6 +27,7 @@ */ #include "hw/hw.h" #include "hw/usb.h" +#include "hw/usb/uhci-regs.h" #include "hw/pci/pci.h" #include "qemu/timer.h" #include "qemu/iov.h" @@ -37,41 +38,6 @@ //#define DEBUG //#define DEBUG_DUMP_DATA -#define UHCI_CMD_FGR (1 << 4) -#define UHCI_CMD_EGSM (1 << 3) -#define UHCI_CMD_GRESET (1 << 2) -#define UHCI_CMD_HCRESET (1 << 1) -#define UHCI_CMD_RS (1 << 0) - -#define UHCI_STS_HCHALTED (1 << 5) -#define UHCI_STS_HCPERR (1 << 4) -#define UHCI_STS_HSERR (1 << 3) -#define UHCI_STS_RD (1 << 2) -#define UHCI_STS_USBERR (1 << 1) -#define UHCI_STS_USBINT (1 << 0) - -#define TD_CTRL_SPD (1 << 29) -#define TD_CTRL_ERROR_SHIFT 27 -#define TD_CTRL_IOS (1 << 25) -#define TD_CTRL_IOC (1 << 24) -#define TD_CTRL_ACTIVE (1 << 23) -#define TD_CTRL_STALL (1 << 22) -#define TD_CTRL_BABBLE (1 << 20) -#define TD_CTRL_NAK (1 << 19) -#define TD_CTRL_TIMEOUT (1 << 18) - -#define UHCI_PORT_SUSPEND (1 << 12) -#define UHCI_PORT_RESET (1 << 9) -#define UHCI_PORT_LSDA (1 << 8) -#define UHCI_PORT_RD (1 << 6) -#define UHCI_PORT_ENC (1 << 3) -#define UHCI_PORT_EN (1 << 2) -#define UHCI_PORT_CSC (1 << 1) -#define UHCI_PORT_CCS (1 << 0) - -#define UHCI_PORT_READ_ONLY (0x1bb) -#define UHCI_PORT_WRITE_CLEAR (UHCI_PORT_CSC | UHCI_PORT_ENC) - #define FRAME_TIMER_FREQ 1000 #define FRAME_MAX_LOOPS 256 diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index ef3177aee9..7f2af8925f 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -498,6 +498,7 @@ typedef struct XHCIEvRingSeg { enum xhci_flags { XHCI_FLAG_USE_MSI = 1, XHCI_FLAG_USE_MSI_X, + XHCI_FLAG_SS_FIRST, }; static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, @@ -621,6 +622,11 @@ static const char *ep_state_name(uint32_t state) ARRAY_SIZE(ep_state_names)); } +static bool xhci_get_flag(XHCIState *xhci, enum xhci_flags bit) +{ + return xhci->flags & (1 << bit); +} + static uint64_t xhci_mfindex_get(XHCIState *xhci) { int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); @@ -709,10 +715,18 @@ static XHCIPort *xhci_lookup_port(XHCIState *xhci, struct USBPort *uport) case USB_SPEED_LOW: case USB_SPEED_FULL: case USB_SPEED_HIGH: - index = uport->index; + if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) { + index = uport->index + xhci->numports_3; + } else { + index = uport->index; + } break; case USB_SPEED_SUPER: - index = uport->index + xhci->numports_2; + if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) { + index = uport->index; + } else { + index = uport->index + xhci->numports_2; + } break; default: return NULL; @@ -2851,7 +2865,7 @@ static void xhci_port_update(XHCIPort *port, int is_detach) static void xhci_port_reset(XHCIPort *port, bool warm_reset) { - trace_usb_xhci_port_reset(port->portnr); + trace_usb_xhci_port_reset(port->portnr, warm_reset); if (!xhci_port_have_device(port)) { return; @@ -2967,7 +2981,11 @@ static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size) ret = 0x20425355; /* "USB " */ break; case 0x28: /* Supported Protocol:08 */ - ret = 0x00000001 | (xhci->numports_2<<8); + if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) { + ret = (xhci->numports_2<<8) | (xhci->numports_3+1); + } else { + ret = (xhci->numports_2<<8) | 1; + } break; case 0x2c: /* Supported Protocol:0c */ ret = 0x00000000; /* reserved */ @@ -2979,7 +2997,11 @@ static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size) ret = 0x20425355; /* "USB " */ break; case 0x38: /* Supported Protocol:08 */ - ret = 0x00000000 | (xhci->numports_2+1) | (xhci->numports_3<<8); + if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) { + ret = (xhci->numports_3<<8) | 1; + } else { + ret = (xhci->numports_3<<8) | (xhci->numports_2+1); + } break; case 0x3c: /* Supported Protocol:0c */ ret = 0x00000000; /* reserved */ @@ -3435,7 +3457,7 @@ static void xhci_child_detach(USBPort *uport, USBDevice *child) USBBus *bus = usb_bus_from_device(child); XHCIState *xhci = container_of(bus, XHCIState, bus); - xhci_detach_slot(xhci, uport); + xhci_detach_slot(xhci, child->port); } static USBPortOps xhci_uport_ops = { @@ -3512,8 +3534,13 @@ static void usb_xhci_init(XHCIState *xhci) for (i = 0; i < usbports; i++) { speedmask = 0; if (i < xhci->numports_2) { - port = &xhci->ports[i]; - port->portnr = i + 1; + if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) { + port = &xhci->ports[i + xhci->numports_3]; + port->portnr = i + 1 + xhci->numports_3; + } else { + port = &xhci->ports[i]; + port->portnr = i + 1; + } port->uport = &xhci->uports[i]; port->speedmask = USB_SPEED_MASK_LOW | @@ -3523,8 +3550,13 @@ static void usb_xhci_init(XHCIState *xhci) speedmask |= port->speedmask; } if (i < xhci->numports_3) { - port = &xhci->ports[i + xhci->numports_2]; - port->portnr = i + 1 + xhci->numports_2; + if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) { + port = &xhci->ports[i]; + port->portnr = i + 1; + } else { + port = &xhci->ports[i + xhci->numports_2]; + port->portnr = i + 1 + xhci->numports_2; + } port->uport = &xhci->uports[i]; port->speedmask = USB_SPEED_MASK_SUPER; snprintf(port->name, sizeof(port->name), "usb3 port #%d", i+1); @@ -3594,13 +3626,15 @@ static int usb_xhci_initfn(struct PCIDevice *dev) PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64, &xhci->mem); - ret = pcie_endpoint_cap_init(dev, 0xa0); - assert(ret >= 0); + if (pci_bus_is_express(dev->bus)) { + ret = pcie_endpoint_cap_init(dev, 0xa0); + assert(ret >= 0); + } - if (xhci->flags & (1 << XHCI_FLAG_USE_MSI)) { + if (xhci_get_flag(xhci, XHCI_FLAG_USE_MSI)) { msi_init(dev, 0x70, xhci->numintrs, true, false); } - if (xhci->flags & (1 << XHCI_FLAG_USE_MSI_X)) { + if (xhci_get_flag(xhci, XHCI_FLAG_USE_MSI_X)) { msix_init(dev, xhci->numintrs, &xhci->mem, 0, OFF_MSIX_TABLE, &xhci->mem, 0, OFF_MSIX_PBA, @@ -3781,6 +3815,8 @@ static const VMStateDescription vmstate_xhci = { static Property xhci_properties[] = { DEFINE_PROP_BIT("msi", XHCIState, flags, XHCI_FLAG_USE_MSI, true), DEFINE_PROP_BIT("msix", XHCIState, flags, XHCI_FLAG_USE_MSI_X, true), + DEFINE_PROP_BIT("superspeed-ports-first", + XHCIState, flags, XHCI_FLAG_SS_FIRST, true), DEFINE_PROP_UINT32("intrs", XHCIState, numintrs, MAXINTRS), DEFINE_PROP_UINT32("slots", XHCIState, numslots, MAXSLOTS), DEFINE_PROP_UINT32("p2", XHCIState, numports_2, 4), diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index 57bed09a1e..afbf1563f4 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -111,6 +111,7 @@ struct USBHostRequest { unsigned char *buffer; unsigned char *cbuf; unsigned int clen; + bool usb3ep0quirk; QTAILQ_ENTRY(USBHostRequest) next; }; @@ -146,6 +147,10 @@ static void usb_host_attach_kernel(USBHostDevice *s); #define BULK_TIMEOUT 0 /* unlimited */ #define INTR_TIMEOUT 0 /* unlimited */ +#if LIBUSBX_API_VERSION >= 0x01000103 +# define HAVE_STREAMS 1 +#endif + static const char *speed_name[] = { [LIBUSB_SPEED_UNKNOWN] = "?", [LIBUSB_SPEED_LOW] = "1.5", @@ -346,6 +351,13 @@ static void usb_host_req_complete_ctrl(struct libusb_transfer *xfer) r->p->actual_length = xfer->actual_length; if (r->in && xfer->actual_length) { memcpy(r->cbuf, r->buffer + 8, xfer->actual_length); + + /* Fix up USB-3 ep0 maxpacket size to allow superspeed connected devices + * to work redirected to a not superspeed capable hcd */ + if (r->usb3ep0quirk && xfer->actual_length >= 18 && + r->cbuf[7] == 9) { + r->cbuf[7] = 64; + } } trace_usb_host_req_complete(s->bus_num, s->addr, r->p, r->p->status, r->p->actual_length); @@ -672,11 +684,17 @@ static void usb_host_iso_data_out(USBHostDevice *s, USBPacket *p) /* ------------------------------------------------------------------------ */ -static bool usb_host_full_speed_compat(USBHostDevice *s) +static void usb_host_speed_compat(USBHostDevice *s) { + USBDevice *udev = USB_DEVICE(s); struct libusb_config_descriptor *conf; const struct libusb_interface_descriptor *intf; const struct libusb_endpoint_descriptor *endp; +#ifdef HAVE_STREAMS + struct libusb_ss_endpoint_companion_descriptor *endp_ss_comp; +#endif + bool compat_high = true; + bool compat_full = true; uint8_t type; int rc, c, i, a, e; @@ -693,10 +711,27 @@ static bool usb_host_full_speed_compat(USBHostDevice *s) type = endp->bmAttributes & 0x3; switch (type) { case 0x01: /* ISO */ - return false; + compat_full = false; + compat_high = false; + break; + case 0x02: /* BULK */ +#ifdef HAVE_STREAMS + rc = libusb_get_ss_endpoint_companion_descriptor + (ctx, endp, &endp_ss_comp); + if (rc == LIBUSB_SUCCESS) { + libusb_free_ss_endpoint_companion_descriptor + (endp_ss_comp); + compat_full = false; + compat_high = false; + } +#endif + break; case 0x03: /* INTERRUPT */ if (endp->wMaxPacketSize > 64) { - return false; + compat_full = false; + } + if (endp->wMaxPacketSize > 1024) { + compat_high = false; } break; } @@ -705,7 +740,17 @@ static bool usb_host_full_speed_compat(USBHostDevice *s) } libusb_free_config_descriptor(conf); } - return true; + + udev->speedmask = (1 << udev->speed); + if (udev->speed == USB_SPEED_SUPER && compat_high) { + udev->speedmask |= USB_SPEED_HIGH; + } + if (udev->speed == USB_SPEED_SUPER && compat_full) { + udev->speedmask |= USB_SPEED_FULL; + } + if (udev->speed == USB_SPEED_HIGH && compat_full) { + udev->speedmask |= USB_SPEED_FULL; + } } static void usb_host_ep_update(USBHostDevice *s) @@ -720,6 +765,9 @@ static void usb_host_ep_update(USBHostDevice *s) struct libusb_config_descriptor *conf; const struct libusb_interface_descriptor *intf; const struct libusb_endpoint_descriptor *endp; +#ifdef HAVE_STREAMS + struct libusb_ss_endpoint_companion_descriptor *endp_ss_comp; +#endif uint8_t devep, type; int pid, ep; int rc, i, e; @@ -765,6 +813,15 @@ static void usb_host_ep_update(USBHostDevice *s) usb_ep_set_type(udev, pid, ep, type); usb_ep_set_ifnum(udev, pid, ep, i); usb_ep_set_halted(udev, pid, ep, 0); +#ifdef HAVE_STREAMS + if (type == LIBUSB_TRANSFER_TYPE_BULK && + libusb_get_ss_endpoint_companion_descriptor(ctx, endp, + &endp_ss_comp) == LIBUSB_SUCCESS) { + usb_ep_set_max_streams(udev, pid, ep, + endp_ss_comp->bmAttributes); + libusb_free_ss_endpoint_companion_descriptor(endp_ss_comp); + } +#endif } } @@ -801,10 +858,7 @@ static int usb_host_open(USBHostDevice *s, libusb_device *dev) usb_host_ep_update(s); udev->speed = speed_map[libusb_get_device_speed(dev)]; - udev->speedmask = (1 << udev->speed); - if (udev->speed == USB_SPEED_HIGH && usb_host_full_speed_compat(s)) { - udev->speedmask |= USB_SPEED_MASK_FULL; - } + usb_host_speed_compat(s); if (s->ddesc.iProduct) { libusb_get_string_descriptor_ascii(s->dh, s->ddesc.iProduct, @@ -1150,6 +1204,14 @@ static void usb_host_handle_control(USBDevice *udev, USBPacket *p, memcpy(r->buffer + 8, r->cbuf, r->clen); } + /* Fix up USB-3 ep0 maxpacket size to allow superspeed connected devices + * to work redirected to a not superspeed capable hcd */ + if (udev->speed == USB_SPEED_SUPER && + !((udev->port->speedmask & USB_SPEED_MASK_SUPER)) && + request == 0x8006 && value == 0x100 && index == 0) { + r->usb3ep0quirk = true; + } + libusb_fill_control_transfer(r->xfer, s->dh, r->buffer, usb_host_req_complete_ctrl, r, CONTROL_TIMEOUT); @@ -1202,10 +1264,23 @@ static void usb_host_handle_data(USBDevice *udev, USBPacket *p) usb_packet_copy(p, r->buffer, size); } ep = p->ep->nr | (r->in ? USB_DIR_IN : 0); - libusb_fill_bulk_transfer(r->xfer, s->dh, ep, - r->buffer, size, - usb_host_req_complete_data, r, - BULK_TIMEOUT); + if (p->stream) { +#ifdef HAVE_STREAMS + libusb_fill_bulk_stream_transfer(r->xfer, s->dh, ep, p->stream, + r->buffer, size, + usb_host_req_complete_data, r, + BULK_TIMEOUT); +#else + usb_host_req_free(r); + p->status = USB_RET_STALL; + return; +#endif + } else { + libusb_fill_bulk_transfer(r->xfer, s->dh, ep, + r->buffer, size, + usb_host_req_complete_data, r, + BULK_TIMEOUT); + } break; case USB_ENDPOINT_XFER_INT: r = usb_host_req_alloc(s, p, p->pid == USB_TOKEN_IN, p->iov.size); @@ -1268,6 +1343,54 @@ static void usb_host_handle_reset(USBDevice *udev) } } +static int usb_host_alloc_streams(USBDevice *udev, USBEndpoint **eps, + int nr_eps, int streams) +{ +#ifdef HAVE_STREAMS + USBHostDevice *s = USB_HOST_DEVICE(udev); + unsigned char endpoints[30]; + int i, rc; + + for (i = 0; i < nr_eps; i++) { + endpoints[i] = eps[i]->nr; + if (eps[i]->pid == USB_TOKEN_IN) { + endpoints[i] |= 0x80; + } + } + rc = libusb_alloc_streams(s->dh, streams, endpoints, nr_eps); + if (rc < 0) { + usb_host_libusb_error("libusb_alloc_streams", rc); + } else if (rc != streams) { + fprintf(stderr, + "libusb_alloc_streams: got less streams then requested %d < %d\n", + rc, streams); + } + + return (rc == streams) ? 0 : -1; +#else + fprintf(stderr, "libusb_alloc_streams: error not implemented\n"); + return -1; +#endif +} + +static void usb_host_free_streams(USBDevice *udev, USBEndpoint **eps, + int nr_eps) +{ +#ifdef HAVE_STREAMS + USBHostDevice *s = USB_HOST_DEVICE(udev); + unsigned char endpoints[30]; + int i; + + for (i = 0; i < nr_eps; i++) { + endpoints[i] = eps[i]->nr; + if (eps[i]->pid == USB_TOKEN_IN) { + endpoints[i] |= 0x80; + } + } + libusb_free_streams(s->dh, endpoints, nr_eps); +#endif +} + /* * This is *NOT* about restoring state. We have absolutely no idea * what state the host device is in at the moment and whenever it is @@ -1349,6 +1472,8 @@ static void usb_host_class_initfn(ObjectClass *klass, void *data) uc->handle_reset = usb_host_handle_reset; uc->handle_destroy = usb_host_handle_destroy; uc->flush_ep_queue = usb_host_flush_ep_queue; + uc->alloc_streams = usb_host_alloc_streams; + uc->free_streams = usb_host_free_streams; dc->vmsd = &vmstate_usb_host; dc->props = usb_host_dev_properties; set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 287a505b48..4c6187bebd 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -50,6 +50,10 @@ ((i) & 0x10) ? USB_TOKEN_IN : USB_TOKEN_OUT, \ (i) & 0x0f)) +#ifndef USBREDIR_VERSION /* This is not defined in older usbredir versions */ +#define USBREDIR_VERSION 0 +#endif + typedef struct USBRedirDevice USBRedirDevice; /* Struct to hold buffered packets */ @@ -68,6 +72,7 @@ struct endp_data { uint8_t interval; uint8_t interface; /* bInterfaceNumber this ep belongs to */ uint16_t max_packet_size; /* In bytes, not wMaxPacketSize format !! */ + uint32_t max_streams; uint8_t iso_started; uint8_t iso_error; /* For reporting iso errors to the HC */ uint8_t interrupt_started; @@ -106,8 +111,9 @@ struct USBRedirDevice { int read_buf_size; /* Active chardev-watch-tag */ guint watch; - /* For async handling of close */ + /* For async handling of close / reject */ QEMUBH *chardev_close_bh; + QEMUBH *device_reject_bh; /* To delay the usb attach in case of quick chardev close + open */ QEMUTimer *attach_timer; int64_t next_attach_time; @@ -780,11 +786,12 @@ static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p, dev->endpoint[EP2I(ep)].bulk_receiving_enabled = 0; } - DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, size, p->id); + DPRINTF("bulk-out ep %02X stream %u len %zd id %"PRIu64"\n", + ep, p->stream, size, p->id); bulk_packet.endpoint = ep; bulk_packet.length = size; - bulk_packet.stream_id = 0; + bulk_packet.stream_id = p->stream; bulk_packet.length_high = size >> 16; assert(bulk_packet.length_high == 0 || usbredirparser_peer_has_cap(dev->parser, @@ -1091,6 +1098,66 @@ static void usbredir_handle_control(USBDevice *udev, USBPacket *p, p->status = USB_RET_ASYNC; } +static int usbredir_alloc_streams(USBDevice *udev, USBEndpoint **eps, + int nr_eps, int streams) +{ + USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); +#if USBREDIR_VERSION >= 0x000700 + struct usb_redir_alloc_bulk_streams_header alloc_streams; + int i; + + if (!usbredirparser_peer_has_cap(dev->parser, + usb_redir_cap_bulk_streams)) { + ERROR("peer does not support streams\n"); + goto reject; + } + + if (streams == 0) { + ERROR("request to allocate 0 streams\n"); + return -1; + } + + alloc_streams.no_streams = streams; + alloc_streams.endpoints = 0; + for (i = 0; i < nr_eps; i++) { + alloc_streams.endpoints |= 1 << USBEP2I(eps[i]); + } + usbredirparser_send_alloc_bulk_streams(dev->parser, 0, &alloc_streams); + usbredirparser_do_write(dev->parser); + + return 0; +#else + ERROR("usbredir_alloc_streams not implemented\n"); + goto reject; +#endif +reject: + ERROR("streams are not available, disconnecting\n"); + qemu_bh_schedule(dev->device_reject_bh); + return -1; +} + +static void usbredir_free_streams(USBDevice *udev, USBEndpoint **eps, + int nr_eps) +{ +#if USBREDIR_VERSION >= 0x000700 + USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); + struct usb_redir_free_bulk_streams_header free_streams; + int i; + + if (!usbredirparser_peer_has_cap(dev->parser, + usb_redir_cap_bulk_streams)) { + return; + } + + free_streams.endpoints = 0; + for (i = 0; i < nr_eps; i++) { + free_streams.endpoints |= 1 << USBEP2I(eps[i]); + } + usbredirparser_send_free_bulk_streams(dev->parser, 0, &free_streams); + usbredirparser_do_write(dev->parser); +#endif +} + /* * Close events can be triggered by usbredirparser_do_write which gets called * from within the USBDevice data / control packet callbacks and doing a @@ -1102,6 +1169,7 @@ static void usbredir_chardev_close_bh(void *opaque) { USBRedirDevice *dev = opaque; + qemu_bh_cancel(dev->device_reject_bh); usbredir_device_disconnect(dev); if (dev->parser) { @@ -1153,6 +1221,9 @@ static void usbredir_create_parser(USBRedirDevice *dev) usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids); usbredirparser_caps_set_cap(caps, usb_redir_cap_32bits_bulk_length); usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_receiving); +#if USBREDIR_VERSION >= 0x000700 + usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_streams); +#endif if (runstate_check(RUN_STATE_INMIGRATE)) { flags |= usbredirparser_fl_no_hello; @@ -1171,6 +1242,17 @@ static void usbredir_reject_device(USBRedirDevice *dev) } } +/* + * We may need to reject the device when the hcd calls alloc_streams, doing + * an usb_detach from within a hcd call is not a good idea, hence this bh. + */ +static void usbredir_device_reject_bh(void *opaque) +{ + USBRedirDevice *dev = opaque; + + usbredir_reject_device(dev); +} + static void usbredir_do_attach(void *opaque) { USBRedirDevice *dev = opaque; @@ -1297,6 +1379,7 @@ static int usbredir_initfn(USBDevice *udev) } dev->chardev_close_bh = qemu_bh_new(usbredir_chardev_close_bh, dev); + dev->device_reject_bh = qemu_bh_new(usbredir_device_reject_bh, dev); dev->attach_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, usbredir_do_attach, dev); packet_id_queue_init(&dev->cancelled, dev, "cancelled"); @@ -1337,6 +1420,7 @@ static void usbredir_handle_destroy(USBDevice *udev) dev->cs = NULL; /* Note must be done after qemu_chr_close, as that causes a close event */ qemu_bh_delete(dev->chardev_close_bh); + qemu_bh_delete(dev->device_reject_bh); timer_del(dev->attach_timer); timer_free(dev->attach_timer); @@ -1628,6 +1712,7 @@ static void usbredir_setup_usb_eps(USBRedirDevice *dev) usb_ep->type = dev->endpoint[i].type; usb_ep->ifnum = dev->endpoint[i].interface; usb_ep->max_packet_size = dev->endpoint[i].max_packet_size; + usb_ep->max_streams = dev->endpoint[i].max_streams; usbredir_set_pipeline(dev, usb_ep); } } @@ -1646,6 +1731,12 @@ static void usbredir_ep_info(void *priv, usb_redir_cap_ep_info_max_packet_size)) { dev->endpoint[i].max_packet_size = ep_info->max_packet_size[i]; } +#if USBREDIR_VERSION >= 0x000700 + if (usbredirparser_peer_has_cap(dev->parser, + usb_redir_cap_bulk_streams)) { + dev->endpoint[i].max_streams = ep_info->max_streams[i]; + } +#endif switch (dev->endpoint[i].type) { case usb_redir_type_invalid: break; @@ -1779,6 +1870,20 @@ static void usbredir_interrupt_receiving_status(void *priv, uint64_t id, static void usbredir_bulk_streams_status(void *priv, uint64_t id, struct usb_redir_bulk_streams_status_header *bulk_streams_status) { +#if USBREDIR_VERSION >= 0x000700 + USBRedirDevice *dev = priv; + + if (bulk_streams_status->status == usb_redir_success) { + DPRINTF("bulk streams status %d eps %08x\n", + bulk_streams_status->status, bulk_streams_status->endpoints); + } else { + ERROR("bulk streams %s failed status %d eps %08x\n", + (bulk_streams_status->no_streams == 0) ? "free" : "alloc", + bulk_streams_status->status, bulk_streams_status->endpoints); + ERROR("usb-redir-host does not provide streams, disconnecting\n"); + usbredir_reject_device(dev); + } +#endif } static void usbredir_bulk_receiving_status(void *priv, uint64_t id, @@ -1850,8 +1955,8 @@ static void usbredir_bulk_packet(void *priv, uint64_t id, int len = (bulk_packet->length_high << 16) | bulk_packet->length; USBPacket *p; - DPRINTF("bulk-in status %d ep %02X len %d id %"PRIu64"\n", - bulk_packet->status, ep, len, id); + DPRINTF("bulk-in status %d ep %02X stream %u len %d id %"PRIu64"\n", + bulk_packet->status, ep, bulk_packet->stream_id, len, id); p = usbredir_find_packet_by_id(dev, ep, id); if (p) { @@ -2165,6 +2270,23 @@ static bool usbredir_bulk_receiving_needed(void *priv) return endp->bulk_receiving_started; } +static const VMStateDescription usbredir_stream_vmstate = { + .name = "usb-redir-ep/stream-state", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(max_streams, struct endp_data), + VMSTATE_END_OF_LIST() + } +}; + +static bool usbredir_stream_needed(void *priv) +{ + struct endp_data *endp = priv; + + return endp->max_streams; +} + static const VMStateDescription usbredir_ep_vmstate = { .name = "usb-redir-ep", .version_id = 1, @@ -2197,6 +2319,9 @@ static const VMStateDescription usbredir_ep_vmstate = { .vmsd = &usbredir_bulk_receiving_vmstate, .needed = usbredir_bulk_receiving_needed, }, { + .vmsd = &usbredir_stream_vmstate, + .needed = usbredir_stream_needed, + }, { /* empty */ } } @@ -2361,6 +2486,8 @@ static void usbredir_class_initfn(ObjectClass *klass, void *data) uc->handle_control = usbredir_handle_control; uc->flush_ep_queue = usbredir_flush_ep_queue; uc->ep_stopped = usbredir_ep_stopped; + uc->alloc_streams = usbredir_alloc_streams; + uc->free_streams = usbredir_free_streams; dc->vmsd = &usbredir_vmstate; dc->props = usbredir_properties; set_bit(DEVICE_CATEGORY_MISC, dc->categories); diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 971a921777..bf2b588b24 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -108,6 +108,7 @@ static void balloon_stats_poll_cb(void *opaque) static void balloon_stats_get_all(Object *obj, struct Visitor *v, void *opaque, const char *name, Error **errp) { + Error *err = NULL; VirtIOBalloon *s = opaque; int i; @@ -116,17 +117,33 @@ static void balloon_stats_get_all(Object *obj, struct Visitor *v, return; } - visit_start_struct(v, NULL, "guest-stats", name, 0, errp); - visit_type_int(v, &s->stats_last_update, "last-update", errp); + visit_start_struct(v, NULL, "guest-stats", name, 0, &err); + if (err) { + goto out; + } + visit_type_int(v, &s->stats_last_update, "last-update", &err); + if (err) { + goto out_end; + } - visit_start_struct(v, NULL, NULL, "stats", 0, errp); - for (i = 0; i < VIRTIO_BALLOON_S_NR; i++) { + visit_start_struct(v, NULL, NULL, "stats", 0, &err); + if (err) { + goto out_end; + } + for (i = 0; !err && i < VIRTIO_BALLOON_S_NR; i++) { visit_type_int64(v, (int64_t *) &s->stats[i], balloon_stat_names[i], - errp); + &err); } - visit_end_struct(v, errp); - - visit_end_struct(v, errp); + error_propagate(errp, err); + err = NULL; + visit_end_struct(v, &err); + +out_end: + error_propagate(errp, err); + err = NULL; + visit_end_struct(v, &err); +out: + error_propagate(errp, err); } static void balloon_stats_get_poll_interval(Object *obj, struct Visitor *v, diff --git a/hw/xenpv/xen_machine_pv.c b/hw/xenpv/xen_machine_pv.c index 9adb57fc14..31500643a2 100644 --- a/hw/xenpv/xen_machine_pv.c +++ b/hw/xenpv/xen_machine_pv.c @@ -28,11 +28,11 @@ #include "xen_domainbuild.h" #include "sysemu/blockdev.h" -static void xen_init_pv(QEMUMachineInitArgs *args) +static void xen_init_pv(MachineState *machine) { - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; DriveInfo *dinfo; int i; diff --git a/hw/xtensa/xtensa_lx60.c b/hw/xtensa/xtensa_lx60.c index 49c58d11a3..507dd88452 100644 --- a/hw/xtensa/xtensa_lx60.c +++ b/hw/xtensa/xtensa_lx60.c @@ -159,7 +159,7 @@ static void lx60_reset(void *opaque) cpu_reset(CPU(cpu)); } -static void lx_init(const LxBoardDesc *board, QEMUMachineInitArgs *args) +static void lx_init(const LxBoardDesc *board, MachineState *machine) { #ifdef TARGET_WORDS_BIGENDIAN int be = 1; @@ -172,9 +172,9 @@ static void lx_init(const LxBoardDesc *board, QEMUMachineInitArgs *args) MemoryRegion *ram, *rom, *system_io; DriveInfo *dinfo; pflash_t *flash = NULL; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; int n; if (!cpu_model) { @@ -198,7 +198,7 @@ static void lx_init(const LxBoardDesc *board, QEMUMachineInitArgs *args) } ram = g_malloc(sizeof(*ram)); - memory_region_init_ram(ram, NULL, "lx60.dram", args->ram_size); + memory_region_init_ram(ram, NULL, "lx60.dram", machine->ram_size); vmstate_register_ram_global(ram); memory_region_add_subregion(system_memory, 0, ram); @@ -275,7 +275,7 @@ static void lx_init(const LxBoardDesc *board, QEMUMachineInitArgs *args) } } -static void xtensa_lx60_init(QEMUMachineInitArgs *args) +static void xtensa_lx60_init(MachineState *machine) { static const LxBoardDesc lx60_board = { .flash_base = 0xf8000000, @@ -283,10 +283,10 @@ static void xtensa_lx60_init(QEMUMachineInitArgs *args) .flash_sector_size = 0x10000, .sram_size = 0x20000, }; - lx_init(&lx60_board, args); + lx_init(&lx60_board, machine); } -static void xtensa_lx200_init(QEMUMachineInitArgs *args) +static void xtensa_lx200_init(MachineState *machine) { static const LxBoardDesc lx200_board = { .flash_base = 0xf8000000, @@ -294,10 +294,10 @@ static void xtensa_lx200_init(QEMUMachineInitArgs *args) .flash_sector_size = 0x20000, .sram_size = 0x2000000, }; - lx_init(&lx200_board, args); + lx_init(&lx200_board, machine); } -static void xtensa_ml605_init(QEMUMachineInitArgs *args) +static void xtensa_ml605_init(MachineState *machine) { static const LxBoardDesc ml605_board = { .flash_base = 0xf8000000, @@ -305,10 +305,10 @@ static void xtensa_ml605_init(QEMUMachineInitArgs *args) .flash_sector_size = 0x20000, .sram_size = 0x2000000, }; - lx_init(&ml605_board, args); + lx_init(&ml605_board, machine); } -static void xtensa_kc705_init(QEMUMachineInitArgs *args) +static void xtensa_kc705_init(MachineState *machine) { static const LxBoardDesc kc705_board = { .flash_base = 0xf0000000, @@ -316,7 +316,7 @@ static void xtensa_kc705_init(QEMUMachineInitArgs *args) .flash_sector_size = 0x20000, .sram_size = 0x2000000, }; - lx_init(&kc705_board, args); + lx_init(&kc705_board, machine); } static QEMUMachine xtensa_lx60_machine = { diff --git a/hw/xtensa/xtensa_sim.c b/hw/xtensa/xtensa_sim.c index 1192ce7134..89da43c160 100644 --- a/hw/xtensa/xtensa_sim.c +++ b/hw/xtensa/xtensa_sim.c @@ -46,14 +46,14 @@ static void sim_reset(void *opaque) cpu_reset(CPU(cpu)); } -static void xtensa_sim_init(QEMUMachineInitArgs *args) +static void xtensa_sim_init(MachineState *machine) { XtensaCPU *cpu = NULL; CPUXtensaState *env = NULL; MemoryRegion *ram, *rom; - ram_addr_t ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; int n; if (!cpu_model) { |