aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml84
-rw-r--r--MAINTAINERS34
-rw-r--r--Makefile9
-rw-r--r--Makefile.objs89
-rw-r--r--Makefile.target2
-rw-r--r--accel/tcg/cpu-exec.c1
-rw-r--r--accel/tcg/translate-all.c4
-rw-r--r--block.c2
-rw-r--r--block/backup.c59
-rw-r--r--block/commit.c44
-rw-r--r--block/create.c67
-rw-r--r--block/mirror.c113
-rw-r--r--block/qcow2.c5
-rw-r--r--block/replication.c10
-rw-r--r--block/sheepdog.c4
-rw-r--r--block/stream.c39
-rw-r--r--block/trace-events5
-rw-r--r--block/vdi.c1
-rw-r--r--block/vhdx.c2
-rw-r--r--blockdev.c68
-rw-r--r--blockjob.c1094
-rw-r--r--bsd-user/main.c7
-rw-r--r--bsd-user/mmap.c1
-rw-r--r--bsd-user/qemu.h1
-rw-r--r--chardev/char-mux.c1
-rw-r--r--chardev/char-serial.c2
-rw-r--r--chardev/char-stdio.c2
-rwxr-xr-xconfigure23
-rw-r--r--default-configs/arm-softmmu.mak1
-rw-r--r--default-configs/hppa-softmmu.mak2
-rw-r--r--default-configs/mips-softmmu-common.mak1
-rw-r--r--default-configs/pci.mak5
-rw-r--r--default-configs/riscv32-softmmu.mak3
-rw-r--r--default-configs/riscv64-softmmu.mak3
-rw-r--r--default-configs/s390x-softmmu.mak4
-rw-r--r--default-configs/sparc-softmmu.mak1
-rw-r--r--default-configs/usb.mak1
-rw-r--r--default-configs/virtio.mak14
-rw-r--r--docs/devel/memory.txt5
-rw-r--r--docs/devel/qapi-code-gen.txt11
-rw-r--r--docs/interop/firmware.json540
-rw-r--r--docs/specs/tpm.txt106
-rw-r--r--exec.c96
-rw-r--r--gdbstub.c7
-rw-r--r--hw/9pfs/Makefile.objs6
-rw-r--r--hw/9pfs/xen-9p-backend.c32
-rw-r--r--hw/Makefile.objs2
-rw-r--r--hw/acpi/pcihp.c1
-rw-r--r--hw/acpi/piix4.c1
-rw-r--r--hw/arm/aspeed.c1
-rw-r--r--hw/arm/bcm2836.c1
-rw-r--r--hw/arm/boot.c18
-rw-r--r--hw/arm/collie.c1
-rw-r--r--hw/arm/gumstix.c1
-rw-r--r--hw/arm/mainstone.c1
-rw-r--r--hw/arm/nseries.c1
-rw-r--r--hw/arm/omap1.c2
-rw-r--r--hw/arm/omap2.c2
-rw-r--r--hw/arm/omap_sx1.c1
-rw-r--r--hw/arm/pxa2xx.c1
-rw-r--r--hw/arm/spitz.c1
-rw-r--r--hw/arm/versatilepb.c1
-rw-r--r--hw/arm/vexpress.c1
-rw-r--r--hw/arm/virt-acpi-build.c20
-rw-r--r--hw/arm/virt.c1
-rw-r--r--hw/arm/xilinx_zynq.c1
-rw-r--r--hw/arm/xlnx-zcu102.c1
-rw-r--r--hw/arm/z2.c1
-rw-r--r--hw/audio/wm8750.c8
-rw-r--r--hw/block/Makefile.objs6
-rw-r--r--hw/block/dataplane/virtio-blk.c1
-rw-r--r--hw/block/m25p80.c1
-rw-r--r--hw/block/nvme.c1
-rw-r--r--hw/block/nvme.h1
-rw-r--r--hw/block/onenand.c2
-rw-r--r--hw/block/pflash_cfi01.c1
-rw-r--r--hw/block/pflash_cfi02.c1
-rw-r--r--hw/block/virtio-blk.c1
-rw-r--r--hw/block/xen_disk.c614
-rw-r--r--hw/char/Makefile.objs2
-rw-r--r--hw/char/mcf_uart.c1
-rw-r--r--hw/char/serial.c1
-rw-r--r--hw/char/sh_serial.c1
-rw-r--r--hw/char/xen_console.c9
-rw-r--r--hw/core/loader-fit.c1
-rw-r--r--hw/core/machine.c5
-rw-r--r--hw/core/platform-bus.c1
-rw-r--r--hw/core/qdev-properties.c1
-rw-r--r--hw/core/qdev.c28
-rw-r--r--hw/core/sysbus.c12
-rw-r--r--hw/cris/axis_dev88.c1
-rw-r--r--hw/display/Makefile.objs5
-rw-r--r--hw/display/bochs-display.c363
-rw-r--r--hw/display/sm501.c1
-rw-r--r--hw/display/ssd0303.c9
-rw-r--r--hw/display/tc6393xb.c1
-rw-r--r--hw/display/vga-pci.c19
-rw-r--r--hw/display/vga.c23
-rw-r--r--hw/display/vga_int.h35
-rw-r--r--hw/dma/xlnx-zdma.c10
-rw-r--r--hw/gpio/max7310.c9
-rw-r--r--hw/hppa/dino.c3
-rw-r--r--hw/hppa/hppa_sys.h1
-rw-r--r--hw/i2c/core.c13
-rw-r--r--hw/i2c/smbus.c9
-rw-r--r--hw/i2c/smbus_eeprom.c5
-rw-r--r--hw/i386/kvm/i8254.c2
-rw-r--r--hw/i386/kvm/i8259.c4
-rw-r--r--hw/i386/kvm/ioapic.c2
-rw-r--r--hw/i386/kvmvapic.c1
-rw-r--r--hw/i386/pc.c1
-rw-r--r--hw/i386/pc_piix.c8
-rw-r--r--hw/i386/pc_q35.c8
-rw-r--r--hw/i386/xen/trace-events3
-rw-r--r--hw/i386/xen/xen-hvm.c251
-rw-r--r--hw/i386/xen/xen-mapcache.c3
-rw-r--r--hw/i386/xen/xen_pvdevice.c11
-rw-r--r--hw/ide/core.c1
-rw-r--r--hw/ide/pci.c1
-rw-r--r--hw/ide/via.c1
-rw-r--r--hw/input/Makefile.objs6
-rw-r--r--hw/input/lm832x.c9
-rw-r--r--hw/intc/arm_gic_kvm.c1
-rw-r--r--hw/intc/arm_gicv3_cpuif.c12
-rw-r--r--hw/intc/arm_gicv3_kvm.c2
-rw-r--r--hw/ipmi/isa_ipmi_kcs.c81
-rw-r--r--hw/isa/isa-superio.c5
-rw-r--r--hw/lm32/lm32_boards.c1
-rw-r--r--hw/lm32/milkymist.c1
-rw-r--r--hw/m68k/mcf5206.c1
-rw-r--r--hw/m68k/mcf_intc.c1
-rw-r--r--hw/microblaze/petalogix_ml605_mmu.c1
-rw-r--r--hw/microblaze/petalogix_s3adsp1800_mmu.c1
-rw-r--r--hw/mips/mips_malta.c1
-rw-r--r--hw/mips/mips_r4k.c1
-rw-r--r--hw/misc/arm_integrator_debug.c1
-rw-r--r--hw/misc/mips_itu.c5
-rw-r--r--hw/misc/sga.c2
-rw-r--r--hw/misc/tmp105.c7
-rw-r--r--hw/misc/tmp421.c8
-rw-r--r--hw/net/Makefile.objs2
-rw-r--r--hw/net/mcf_fec.c1
-rw-r--r--hw/net/ne2000-isa.c1
-rw-r--r--hw/net/xen_nic.c33
-rw-r--r--hw/nvram/eeprom_at24c.c24
-rw-r--r--hw/nvram/fw_cfg.c12
-rw-r--r--hw/pci-host/versatile.c1
-rw-r--r--hw/ppc/ppc405_boards.c1
-rw-r--r--hw/ppc/sam460ex.c1
-rw-r--r--hw/ppc/spapr.c15
-rw-r--r--hw/ppc/virtex_ml507.c2
-rw-r--r--hw/riscv/riscv_htif.c1
-rw-r--r--hw/s390x/s390-pci-inst.c3
-rw-r--r--hw/s390x/s390-virtio-ccw.c10
-rw-r--r--hw/s390x/virtio-ccw.c2
-rw-r--r--hw/scsi/Makefile.objs2
-rw-r--r--hw/scsi/esp.c3
-rw-r--r--hw/scsi/mptsas.c1
-rw-r--r--hw/scsi/scsi-generic.c1
-rw-r--r--hw/sd/pl181.c1
-rw-r--r--hw/sd/sdhci.c2
-rw-r--r--hw/sd/ssi-sd.c1
-rw-r--r--hw/sh4/r2d.c1
-rw-r--r--hw/sh4/sh7750.c1
-rw-r--r--hw/timer/sh_timer.c1
-rw-r--r--hw/timer/twl92230.c11
-rw-r--r--hw/tpm/tpm_emulator.c323
-rw-r--r--hw/tpm/tpm_tis.c52
-rw-r--r--hw/tpm/trace-events9
-rw-r--r--hw/usb/dev-storage.c1
-rw-r--r--hw/usb/xen-usb.c37
-rw-r--r--hw/vfio/ccw.c1
-rw-r--r--hw/vfio/common.c3
-rw-r--r--hw/vfio/platform.c1
-rw-r--r--hw/virtio/Makefile.objs14
-rw-r--r--hw/virtio/vhost.c3
-rw-r--r--hw/virtio/virtio-pci.c1
-rw-r--r--hw/virtio/virtio.c33
-rw-r--r--hw/xen/xen_backend.c178
-rw-r--r--hw/xen/xen_devconfig.c1
-rw-r--r--hw/xen/xen_pt.c2
-rw-r--r--hw/xen/xen_pt_config_init.c2
-rw-r--r--hw/xen/xen_pt_msi.c3
-rw-r--r--hw/xtensa/xtfpga.c1
-rw-r--r--include/block/block_int.h2
-rw-r--r--include/block/blockjob.h324
-rw-r--r--include/block/blockjob_int.h176
-rw-r--r--include/exec/exec-all.h5
-rw-r--r--include/exec/gdbstub.h15
-rw-r--r--include/exec/helper-head.h2
-rw-r--r--include/exec/memory-internal.h3
-rw-r--r--include/exec/memory.h151
-rw-r--r--include/exec/user/thunk.h4
-rw-r--r--include/hw/arm/allwinner-a10.h1
-rw-r--r--include/hw/arm/bcm2835_peripherals.h1
-rw-r--r--include/hw/devices.h7
-rw-r--r--include/hw/display/bcm2835_fb.h1
-rw-r--r--include/hw/display/bochs-vbe.h69
-rw-r--r--include/hw/dma/bcm2835_dma.h1
-rw-r--r--include/hw/i2c/i2c.h3
-rw-r--r--include/hw/i2c/smbus.h1
-rw-r--r--include/hw/misc/bcm2835_mbox.h1
-rw-r--r--include/hw/misc/bcm2835_property.h1
-rw-r--r--include/hw/misc/mips_itu.h2
-rw-r--r--include/hw/qdev-core.h20
-rw-r--r--include/hw/sh4/sh_intc.h1
-rw-r--r--include/hw/vfio/vfio-common.h1
-rw-r--r--include/hw/virtio/virtio-access.h1
-rw-r--r--include/hw/virtio/virtio-gpu.h6
-rw-r--r--include/hw/xen/xen_backend.h34
-rw-r--r--include/hw/xen/xen_common.h33
-rw-r--r--include/migration/vmstate.h48
-rw-r--r--include/qapi/qmp/dispatch.h1
-rw-r--r--include/qemu/job.h567
-rw-r--r--include/standard-headers/asm-x86/hyperv.h1
-rw-r--r--include/standard-headers/asm-x86/kvm_para.h2
-rw-r--r--include/standard-headers/linux/ethtool.h36
-rw-r--r--include/standard-headers/linux/input.h4
-rw-r--r--include/standard-headers/linux/pci_regs.h7
-rw-r--r--include/standard-headers/linux/virtio_balloon.h15
-rw-r--r--include/standard-headers/linux/virtio_gpu.h1
-rw-r--r--include/standard-headers/rdma/vmw_pvrdma-abi.h49
-rw-r--r--include/sysemu/dma.h6
-rw-r--r--include/sysemu/numa.h2
-rw-r--r--include/sysemu/seccomp.h3
-rw-r--r--include/sysemu/sysemu.h1
-rw-r--r--include/sysemu/xen-mapcache.h5
-rw-r--r--job-qmp.c183
-rw-r--r--job.c1012
-rw-r--r--linux-headers/COPYING358
-rw-r--r--linux-headers/LICENSES/exceptions/Linux-syscall-note25
-rw-r--r--linux-headers/LICENSES/preferred/BSD-2-Clause32
-rw-r--r--linux-headers/LICENSES/preferred/BSD-3-Clause36
-rw-r--r--linux-headers/LICENSES/preferred/GPL-2.0353
-rw-r--r--linux-headers/asm-arm/kvm.h15
-rw-r--r--linux-headers/asm-arm64/kvm.h6
-rw-r--r--linux-headers/asm-x86/hyperv.h1
-rw-r--r--linux-headers/asm-x86/kvm.h19
-rw-r--r--linux-headers/linux/kvm.h30
-rw-r--r--linux-headers/linux/vfio.h27
-rw-r--r--linux-user/aarch64/sockbits.h1
-rw-r--r--linux-user/alpha/sockbits.h83
-rw-r--r--linux-user/arm/sockbits.h1
-rw-r--r--linux-user/cris/sockbits.h1
-rw-r--r--linux-user/generic/sockbits.h58
-rw-r--r--linux-user/hppa/sockbits.h33
-rw-r--r--linux-user/i386/sockbits.h1
-rw-r--r--linux-user/m68k/sockbits.h1
-rw-r--r--linux-user/main.c5
-rw-r--r--linux-user/microblaze/cpu_loop.c4
-rw-r--r--linux-user/microblaze/sockbits.h1
-rw-r--r--linux-user/mips/sockbits.h110
-rw-r--r--linux-user/mips64/sockbits.h1
-rw-r--r--linux-user/nios2/sockbits.h1
-rw-r--r--linux-user/openrisc/sockbits.h1
-rw-r--r--linux-user/ppc/sockbits.h26
-rw-r--r--linux-user/riscv/sockbits.h1
-rw-r--r--linux-user/s390x/sockbits.h1
-rw-r--r--linux-user/sh4/sockbits.h1
-rw-r--r--linux-user/socket.h377
-rw-r--r--linux-user/sparc/sockbits.h111
-rw-r--r--linux-user/sparc64/sockbits.h1
-rw-r--r--linux-user/syscall.c61
-rw-r--r--linux-user/tilegx/sockbits.h1
-rw-r--r--linux-user/x86_64/sockbits.h1
-rw-r--r--linux-user/xtensa/sockbits.h1
-rw-r--r--memory.c59
-rw-r--r--memory_ldst.inc.c18
-rw-r--r--migration/exec.c4
-rw-r--r--migration/fd.c4
-rw-r--r--migration/ram.c4
-rw-r--r--migration/vmstate.c25
-rw-r--r--monitor.c12
-rw-r--r--net/slirp.c16
-rw-r--r--numa.c75
-rw-r--r--qapi/block-core.json138
-rw-r--r--qapi/common.json2
-rw-r--r--qapi/introspect.json5
-rw-r--r--qapi/job.json255
-rw-r--r--qapi/migration.json16
-rw-r--r--qapi/misc.json61
-rw-r--r--qapi/net.json6
-rw-r--r--qapi/qapi-schema.json1
-rw-r--r--qapi/qmp-dispatch.c8
-rw-r--r--qapi/run-state.json8
-rw-r--r--qapi/ui.json2
-rw-r--r--qemu-doc.texi9
-rw-r--r--qemu-img.c22
-rw-r--r--qemu-nbd.c8
-rw-r--r--qemu-options.hx20
-rw-r--r--qemu-seccomp.c121
-rw-r--r--qemu-tech.texi40
-rw-r--r--qmp.c10
-rw-r--r--qom/object.c28
-rwxr-xr-xscripts/checkpatch.pl2
-rw-r--r--scripts/qapi/commands.py11
-rw-r--r--scripts/qapi/common.py18
-rw-r--r--scripts/qapi/doc.py4
-rw-r--r--scripts/qapi/introspect.py7
-rwxr-xr-xscripts/update-linux-headers.sh17
-rw-r--r--slirp/arp_table.c4
-rw-r--r--slirp/bootp.c8
-rw-r--r--slirp/libslirp.h2
-rw-r--r--slirp/ncsi.c51
-rw-r--r--slirp/slirp.c16
-rw-r--r--slirp/slirp.h1
-rw-r--r--slirp/socket.c6
-rw-r--r--slirp/tcp_subr.c2
-rw-r--r--target/arm/arm-powerctl.c1
-rw-r--r--target/arm/arm_ldst.h1
-rw-r--r--target/arm/crypto_helper.c1
-rw-r--r--target/arm/gdbstub.c3
-rw-r--r--target/arm/helper-a64.c41
-rw-r--r--target/arm/helper.c90
-rw-r--r--target/arm/iwmmxt_helper.c1
-rw-r--r--target/arm/kvm.c3
-rw-r--r--target/arm/neon_helper.c1
-rw-r--r--target/arm/psci.c1
-rw-r--r--target/arm/vec_helper.c1
-rw-r--r--target/cris/cpu.c1
-rw-r--r--target/hppa/helper.c1
-rw-r--r--target/hppa/int_helper.c2
-rw-r--r--target/i386/hax-all.c2
-rw-r--r--target/i386/hax-mem.c1
-rw-r--r--target/i386/hax-windows.c1
-rw-r--r--target/i386/hvf/hvf.c2
-rw-r--r--target/i386/hvf/x86_task.c3
-rw-r--r--target/i386/kvm.c3
-rw-r--r--target/i386/whpx-all.c262
-rw-r--r--target/lm32/cpu.c1
-rw-r--r--target/lm32/op_helper.c4
-rw-r--r--target/m68k/cpu.c1
-rw-r--r--target/microblaze/cpu.c30
-rw-r--r--target/microblaze/cpu.h34
-rw-r--r--target/microblaze/helper.c32
-rw-r--r--target/microblaze/helper.h8
-rw-r--r--target/microblaze/mmu.c81
-rw-r--r--target/microblaze/mmu.h17
-rw-r--r--target/microblaze/op_helper.c30
-rw-r--r--target/microblaze/translate.c930
-rw-r--r--target/moxie/cpu.c1
-rw-r--r--target/moxie/mmu.c1
-rw-r--r--target/nios2/cpu.h1
-rw-r--r--target/nios2/op_helper.c1
-rw-r--r--target/openrisc/cpu.c1
-rw-r--r--target/ppc/cpu.h2
-rw-r--r--target/ppc/helper_regs.h1
-rw-r--r--target/ppc/int_helper.c1
-rw-r--r--target/ppc/machine.c8
-rw-r--r--target/ppc/mmu-hash64.c3
-rw-r--r--target/ppc/translate_init.inc.c2
-rw-r--r--target/riscv/helper.c2
-rw-r--r--target/s390x/cpu.c1
-rw-r--r--target/s390x/diag.c7
-rw-r--r--target/s390x/excp_helper.c3
-rw-r--r--target/s390x/helper.c1
-rw-r--r--target/s390x/kvm.c1
-rw-r--r--target/s390x/mem_helper.c1
-rw-r--r--target/s390x/misc_helper.c1
-rw-r--r--target/s390x/mmu_helper.c3
-rw-r--r--target/s390x/sigp.c3
-rw-r--r--target/sparc/mmu_helper.c1
-rw-r--r--target/tilegx/cpu.c1
-rw-r--r--target/xtensa/core-dc232b.c2
-rw-r--r--target/xtensa/core-dc233c.c1
-rw-r--r--target/xtensa/core-de212.c1
-rw-r--r--target/xtensa/core-fsf.c1
-rw-r--r--target/xtensa/core-sample_controller.c1
-rw-r--r--target/xtensa/cpu.c1
-rwxr-xr-xtarget/xtensa/import_core.sh1
-rw-r--r--target/xtensa/op_helper.c3
-rw-r--r--tcg/tcg-op-vec.c1
-rw-r--r--tests/Makefile.include4
-rw-r--r--tests/docker/Makefile.include5
-rw-r--r--tests/docker/dockerfiles/travis.docker9
-rw-r--r--tests/libqtest.c7
-rw-r--r--tests/libqtest.h9
-rw-r--r--tests/numa-test.c61
-rw-r--r--tests/qapi-schema/allow-preconfig-test.err1
-rw-r--r--tests/qapi-schema/allow-preconfig-test.exit1
-rw-r--r--tests/qapi-schema/allow-preconfig-test.json2
-rw-r--r--tests/qapi-schema/allow-preconfig-test.out0
-rw-r--r--tests/qapi-schema/doc-good.out4
-rw-r--r--tests/qapi-schema/ident-with-escape.out2
-rw-r--r--tests/qapi-schema/indented-expr.out4
-rw-r--r--tests/qapi-schema/qapi-schema-test.json4
-rw-r--r--tests/qapi-schema/qapi-schema-test.out22
-rw-r--r--tests/qapi-schema/test-qapi.py8
-rwxr-xr-xtests/qemu-iotests/03017
-rwxr-xr-xtests/qemu-iotests/0402
-rwxr-xr-xtests/qemu-iotests/04123
-rwxr-xr-xtests/qemu-iotests/0862
-rw-r--r--tests/qemu-iotests/094.out7
-rwxr-xr-xtests/qemu-iotests/0952
-rw-r--r--tests/qemu-iotests/095.out6
-rwxr-xr-xtests/qemu-iotests/1092
-rw-r--r--tests/qemu-iotests/109.out178
-rwxr-xr-xtests/qemu-iotests/1248
-rw-r--r--tests/qemu-iotests/126.out2
-rw-r--r--tests/qemu-iotests/127.out7
-rwxr-xr-xtests/qemu-iotests/14113
-rw-r--r--tests/qemu-iotests/141.out29
-rwxr-xr-xtests/qemu-iotests/1442
-rw-r--r--tests/qemu-iotests/144.out7
-rwxr-xr-xtests/qemu-iotests/1552
-rwxr-xr-xtests/qemu-iotests/1562
-rw-r--r--tests/qemu-iotests/156.out7
-rwxr-xr-xtests/qemu-iotests/18514
-rw-r--r--tests/qemu-iotests/185.out10
-rwxr-xr-xtests/qemu-iotests/1916
-rw-r--r--tests/qemu-iotests/191.out132
-rwxr-xr-xtests/qemu-iotests/206680
-rw-r--r--tests/qemu-iotests/206.out253
-rwxr-xr-xtests/qemu-iotests/207440
-rw-r--r--tests/qemu-iotests/207.out107
-rwxr-xr-xtests/qemu-iotests/210393
-rw-r--r--tests/qemu-iotests/210.out197
-rwxr-xr-xtests/qemu-iotests/211381
-rw-r--r--tests/qemu-iotests/211.out133
-rwxr-xr-xtests/qemu-iotests/212483
-rw-r--r--tests/qemu-iotests/212.out191
-rwxr-xr-xtests/qemu-iotests/213520
-rw-r--r--tests/qemu-iotests/213.out208
-rwxr-xr-xtests/qemu-iotests/219209
-rw-r--r--tests/qemu-iotests/219.out327
-rw-r--r--tests/qemu-iotests/common.filter6
-rw-r--r--tests/qemu-iotests/common.rc12
-rw-r--r--tests/qemu-iotests/group11
-rw-r--r--tests/qemu-iotests/iotests.py128
-rw-r--r--tests/qmp-test.c40
-rw-r--r--tests/test-bdrv-drain.c63
-rw-r--r--tests/test-blockjob-txn.c74
-rw-r--r--tests/test-blockjob.c141
-rw-r--r--tests/test-char.c8
-rw-r--r--tests/test-qmp-cmds.c2
-rw-r--r--tests/tpm-crb-swtpm-test.c247
-rw-r--r--tests/tpm-util.c186
-rw-r--r--tests/tpm-util.h36
-rw-r--r--trace-events14
-rw-r--r--ui/cocoa.m12
-rw-r--r--util/memfd.c2
-rw-r--r--vl.c161
442 files changed, 11534 insertions, 7245 deletions
diff --git a/.travis.yml b/.travis.yml
index c1e99237b2..814be151f4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,8 @@
+# The current Travis default is a container based 14.04 Trust on EC2
+# Additional builds with specific requirements for a full VM need to
+# be added as additional matrix: entries later on
sudo: false
+dist: trusty
language: c
python:
- "2.6"
@@ -70,11 +74,13 @@ script:
- make ${MAKEFLAGS} && ${TEST_CMD}
matrix:
include:
- # Test with CLang for compile portability
- - env: CONFIG=""
+ # Test with Clang for compile portability (Travis uses clang-5.0)
+ - env: CONFIG="--disable-system"
+ compiler: clang
+ - env: CONFIG="--disable-user"
compiler: clang
# gprof/gcov are GCC features
- - env: CONFIG="--enable-gprof --enable-gcov --disable-pie"
+ - env: CONFIG="--enable-gprof --enable-gcov --disable-pie --disable-linux-user"
compiler: gcc
# We manually include builds which we disable "make check" for
- env: CONFIG="--enable-debug --enable-tcg-interpreter"
@@ -95,80 +101,24 @@ matrix:
- env: CONFIG=""
os: osx
compiler: clang
- # Plain Trusty System Build
- - env: CONFIG="--disable-linux-user"
- sudo: required
- addons:
- dist: trusty
- compiler: gcc
- before_install:
- - sudo apt-get update -qq
- - sudo apt-get build-dep -qq qemu
- - wget -O - http://people.linaro.org/~alex.bennee/qemu-submodule-git-seed.tar.xz | tar -xvJ
- - git submodule update --init --recursive
- # Plain Trusty Linux User Build
- - env: CONFIG="--disable-system"
- sudo: required
- addons:
- dist: trusty
- compiler: gcc
- before_install:
- - sudo apt-get update -qq
- - sudo apt-get build-dep -qq qemu
- - wget -O - http://people.linaro.org/~alex.bennee/qemu-submodule-git-seed.tar.xz | tar -xvJ
- - git submodule update --init --recursive
- # Trusty System build with latest stable clang & python 3.0
- - sudo: required
- addons:
- dist: trusty
- language: generic
- compiler: none
+ # Python builds
+ - env: CONFIG="--target-list=x86_64-softmmu"
python:
- "3.0"
- env:
- - COMPILER_NAME=clang CXX=clang++-3.9 CC=clang-3.9
- - CONFIG="--disable-linux-user --cc=clang-3.9 --cxx=clang++-3.9 --python=/usr/bin/python3"
- before_install:
- - wget -nv -O - http://llvm.org/apt/llvm-snapshot.gpg.key | sudo apt-key add -
- - sudo apt-add-repository -y 'deb http://llvm.org/apt/trusty llvm-toolchain-trusty-3.9 main'
- - sudo apt-get update -qq
- - sudo apt-get install -qq -y clang-3.9
- - sudo apt-get build-dep -qq qemu
- - wget -O - http://people.linaro.org/~alex.bennee/qemu-submodule-git-seed.tar.xz | tar -xvJ
- - git submodule update --init --recursive
- before_script:
- - ./configure ${CONFIG} || cat config.log
- # Trusty Linux User build with latest stable clang & python 3.6
- - sudo: required
- addons:
- dist: trusty
- language: generic
- compiler: none
+ - env: CONFIG="--target-list=x86_64-softmmu"
python:
- "3.6"
- env:
- - COMPILER_NAME=clang CXX=clang++-3.9 CC=clang-3.9
- - CONFIG="--disable-system --cc=clang-3.9 --cxx=clang++-3.9 --python=/usr/bin/python3"
- before_install:
- - wget -nv -O - http://llvm.org/apt/llvm-snapshot.gpg.key | sudo apt-key add -
- - sudo apt-add-repository -y 'deb http://llvm.org/apt/trusty llvm-toolchain-trusty-3.9 main'
- - sudo apt-get update -qq
- - sudo apt-get install -qq -y clang-3.9
- - sudo apt-get build-dep -qq qemu
- - wget -O - http://people.linaro.org/~alex.bennee/qemu-submodule-git-seed.tar.xz | tar -xvJ
- - git submodule update --init --recursive
- before_script:
- - ./configure ${CONFIG} || cat config.log
# Using newer GCC with sanitizers
- addons:
apt:
+ update: true
sources:
# PPAs for newer toolchains
- ubuntu-toolchain-r-test
packages:
# Extra toolchains
- - gcc-5
- - g++-5
+ - gcc-7
+ - g++-7
# Build dependencies
- libaio-dev
- libattr1-dev
@@ -197,8 +147,8 @@ matrix:
language: generic
compiler: none
env:
- - COMPILER_NAME=gcc CXX=g++-5 CC=gcc-5
- - CONFIG="--cc=gcc-5 --cxx=g++-5 --disable-pie --disable-linux-user"
+ - COMPILER_NAME=gcc CXX=g++-7 CC=gcc-7
+ - CONFIG="--cc=gcc-7 --cxx=g++-7 --disable-pie --disable-linux-user"
- TEST_CMD=""
before_script:
- ./configure ${CONFIG} --extra-cflags="-g3 -O0 -fsanitize=thread -fuse-ld=gold" || cat config.log
diff --git a/MAINTAINERS b/MAINTAINERS
index f07fcee72e..41cd3736a9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -447,6 +447,8 @@ F: hw/timer/cmsdk-apb-timer.c
F: include/hw/timer/cmsdk-apb-timer.h
F: hw/char/cmsdk-apb-uart.c
F: include/hw/char/cmsdk-apb-uart.h
+F: hw/misc/tz-ppc.c
+F: include/hw/misc/tz-ppc.h
ARM cores
M: Peter Maydell <peter.maydell@linaro.org>
@@ -515,8 +517,11 @@ M: Peter Maydell <peter.maydell@linaro.org>
L: qemu-arm@nongnu.org
S: Maintained
F: hw/arm/mps2.c
-F: hw/misc/mps2-scc.c
-F: include/hw/misc/mps2-scc.h
+F: hw/arm/mps2-tz.c
+F: hw/misc/mps2-*.c
+F: include/hw/misc/mps2-*.h
+F: hw/arm/iotkit.c
+F: include/hw/arm/iotkit.h
Musicpal
M: Jan Kiszka <jan.kiszka@web.de>
@@ -1314,6 +1319,27 @@ S: Maintained
F: include/hw/misc/unimp.h
F: hw/misc/unimp.c
+Standard VGA
+M: Gerd Hoffmann <kraxel@redhat.com>
+S: Maintained
+F: hw/display/vga*
+F: hw/display/bochs-display.c
+F: include/hw/display/vga.h
+F: include/hw/display/bochs-vbe.h
+
+virtio-gpu
+M: Gerd Hoffmann <kraxel@redhat.com>
+S: Maintained
+F: hw/display/virtio-gpu*
+F: hw/display/virtio-vga.c
+F: include/hw/virtio/virtio-gpu.h
+
+Cirrus VGA
+M: Gerd Hoffmann <kraxel@redhat.com>
+S: Odd Fixes
+W: https://www.kraxel.org/blog/2014/10/qemu-using-cirrus-considered-harmful/
+F: hw/display/cirrus*
+
Subsystems
----------
Audio
@@ -1369,10 +1395,14 @@ L: qemu-block@nongnu.org
S: Supported
F: blockjob.c
F: include/block/blockjob.h
+F: job.c
+F: job-qmp.c
+F: include/block/job.h
F: block/backup.c
F: block/commit.c
F: block/stream.c
F: block/mirror.c
+F: qapi/job.json
T: git git://github.com/codyprime/qemu-kvm-jtc.git block
Block QAPI, monitor, command line
diff --git a/Makefile b/Makefile
index 35554b5bef..6d588d1f71 100644
--- a/Makefile
+++ b/Makefile
@@ -98,6 +98,7 @@ GENERATED_FILES += qapi/qapi-types-char.h qapi/qapi-types-char.c
GENERATED_FILES += qapi/qapi-types-common.h qapi/qapi-types-common.c
GENERATED_FILES += qapi/qapi-types-crypto.h qapi/qapi-types-crypto.c
GENERATED_FILES += qapi/qapi-types-introspect.h qapi/qapi-types-introspect.c
+GENERATED_FILES += qapi/qapi-types-job.h qapi/qapi-types-job.c
GENERATED_FILES += qapi/qapi-types-migration.h qapi/qapi-types-migration.c
GENERATED_FILES += qapi/qapi-types-misc.h qapi/qapi-types-misc.c
GENERATED_FILES += qapi/qapi-types-net.h qapi/qapi-types-net.c
@@ -116,6 +117,7 @@ GENERATED_FILES += qapi/qapi-visit-char.h qapi/qapi-visit-char.c
GENERATED_FILES += qapi/qapi-visit-common.h qapi/qapi-visit-common.c
GENERATED_FILES += qapi/qapi-visit-crypto.h qapi/qapi-visit-crypto.c
GENERATED_FILES += qapi/qapi-visit-introspect.h qapi/qapi-visit-introspect.c
+GENERATED_FILES += qapi/qapi-visit-job.h qapi/qapi-visit-job.c
GENERATED_FILES += qapi/qapi-visit-migration.h qapi/qapi-visit-migration.c
GENERATED_FILES += qapi/qapi-visit-misc.h qapi/qapi-visit-misc.c
GENERATED_FILES += qapi/qapi-visit-net.h qapi/qapi-visit-net.c
@@ -133,6 +135,7 @@ GENERATED_FILES += qapi/qapi-commands-char.h qapi/qapi-commands-char.c
GENERATED_FILES += qapi/qapi-commands-common.h qapi/qapi-commands-common.c
GENERATED_FILES += qapi/qapi-commands-crypto.h qapi/qapi-commands-crypto.c
GENERATED_FILES += qapi/qapi-commands-introspect.h qapi/qapi-commands-introspect.c
+GENERATED_FILES += qapi/qapi-commands-job.h qapi/qapi-commands-job.c
GENERATED_FILES += qapi/qapi-commands-migration.h qapi/qapi-commands-migration.c
GENERATED_FILES += qapi/qapi-commands-misc.h qapi/qapi-commands-misc.c
GENERATED_FILES += qapi/qapi-commands-net.h qapi/qapi-commands-net.c
@@ -150,6 +153,7 @@ GENERATED_FILES += qapi/qapi-events-char.h qapi/qapi-events-char.c
GENERATED_FILES += qapi/qapi-events-common.h qapi/qapi-events-common.c
GENERATED_FILES += qapi/qapi-events-crypto.h qapi/qapi-events-crypto.c
GENERATED_FILES += qapi/qapi-events-introspect.h qapi/qapi-events-introspect.c
+GENERATED_FILES += qapi/qapi-events-job.h qapi/qapi-events-job.c
GENERATED_FILES += qapi/qapi-events-migration.h qapi/qapi-events-migration.c
GENERATED_FILES += qapi/qapi-events-misc.h qapi/qapi-events-misc.c
GENERATED_FILES += qapi/qapi-events-net.h qapi/qapi-events-net.c
@@ -582,6 +586,7 @@ qapi-modules = $(SRC_PATH)/qapi/qapi-schema.json $(SRC_PATH)/qapi/common.json \
$(SRC_PATH)/qapi/char.json \
$(SRC_PATH)/qapi/crypto.json \
$(SRC_PATH)/qapi/introspect.json \
+ $(SRC_PATH)/qapi/job.json \
$(SRC_PATH)/qapi/migration.json \
$(SRC_PATH)/qapi/misc.json \
$(SRC_PATH)/qapi/net.json \
@@ -601,6 +606,7 @@ qapi/qapi-types-char.c qapi/qapi-types-char.h \
qapi/qapi-types-common.c qapi/qapi-types-common.h \
qapi/qapi-types-crypto.c qapi/qapi-types-crypto.h \
qapi/qapi-types-introspect.c qapi/qapi-types-introspect.h \
+qapi/qapi-types-job.c qapi/qapi-types-job.h \
qapi/qapi-types-migration.c qapi/qapi-types-migration.h \
qapi/qapi-types-misc.c qapi/qapi-types-misc.h \
qapi/qapi-types-net.c qapi/qapi-types-net.h \
@@ -619,6 +625,7 @@ qapi/qapi-visit-char.c qapi/qapi-visit-char.h \
qapi/qapi-visit-common.c qapi/qapi-visit-common.h \
qapi/qapi-visit-crypto.c qapi/qapi-visit-crypto.h \
qapi/qapi-visit-introspect.c qapi/qapi-visit-introspect.h \
+qapi/qapi-visit-job.c qapi/qapi-visit-job.h \
qapi/qapi-visit-migration.c qapi/qapi-visit-migration.h \
qapi/qapi-visit-misc.c qapi/qapi-visit-misc.h \
qapi/qapi-visit-net.c qapi/qapi-visit-net.h \
@@ -636,6 +643,7 @@ qapi/qapi-commands-char.c qapi/qapi-commands-char.h \
qapi/qapi-commands-common.c qapi/qapi-commands-common.h \
qapi/qapi-commands-crypto.c qapi/qapi-commands-crypto.h \
qapi/qapi-commands-introspect.c qapi/qapi-commands-introspect.h \
+qapi/qapi-commands-job.c qapi/qapi-commands-job.h \
qapi/qapi-commands-migration.c qapi/qapi-commands-migration.h \
qapi/qapi-commands-misc.c qapi/qapi-commands-misc.h \
qapi/qapi-commands-net.c qapi/qapi-commands-net.h \
@@ -653,6 +661,7 @@ qapi/qapi-events-char.c qapi/qapi-events-char.h \
qapi/qapi-events-common.c qapi/qapi-events-common.h \
qapi/qapi-events-crypto.c qapi/qapi-events-crypto.h \
qapi/qapi-events-introspect.c qapi/qapi-events-introspect.h \
+qapi/qapi-events-job.c qapi/qapi-events-job.h \
qapi/qapi-events-migration.c qapi/qapi-events-migration.h \
qapi/qapi-events-misc.c qapi/qapi-events-misc.h \
qapi/qapi-events-net.c qapi/qapi-events-net.h \
diff --git a/Makefile.objs b/Makefile.objs
index c6c9b8fc21..2c8cb72407 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -10,6 +10,7 @@ util-obj-y += qapi/qapi-types-char.o
util-obj-y += qapi/qapi-types-common.o
util-obj-y += qapi/qapi-types-crypto.o
util-obj-y += qapi/qapi-types-introspect.o
+util-obj-y += qapi/qapi-types-job.o
util-obj-y += qapi/qapi-types-migration.o
util-obj-y += qapi/qapi-types-misc.o
util-obj-y += qapi/qapi-types-net.o
@@ -28,6 +29,7 @@ util-obj-y += qapi/qapi-visit-char.o
util-obj-y += qapi/qapi-visit-common.o
util-obj-y += qapi/qapi-visit-crypto.o
util-obj-y += qapi/qapi-visit-introspect.o
+util-obj-y += qapi/qapi-visit-job.o
util-obj-y += qapi/qapi-visit-migration.o
util-obj-y += qapi/qapi-visit-misc.o
util-obj-y += qapi/qapi-visit-net.o
@@ -45,6 +47,7 @@ util-obj-y += qapi/qapi-events-char.o
util-obj-y += qapi/qapi-events-common.o
util-obj-y += qapi/qapi-events-crypto.o
util-obj-y += qapi/qapi-events-introspect.o
+util-obj-y += qapi/qapi-events-job.o
util-obj-y += qapi/qapi-events-migration.o
util-obj-y += qapi/qapi-events-misc.o
util-obj-y += qapi/qapi-events-net.o
@@ -63,7 +66,7 @@ chardev-obj-y = chardev/
# block-obj-y is code used by both qemu system emulation and qemu-img
block-obj-y += nbd/
-block-obj-y += block.o blockjob.o
+block-obj-y += block.o blockjob.o job.o
block-obj-y += block/ scsi/
block-obj-y += qemu-io-cmds.o
block-obj-$(CONFIG_REPLICATION) += replication.o
@@ -94,6 +97,7 @@ io-obj-y = io/
ifeq ($(CONFIG_SOFTMMU),y)
common-obj-y = blockdev.o blockdev-nbd.o block/
common-obj-y += bootdevice.o iothread.o
+common-obj-y += job-qmp.o
common-obj-y += net/
common-obj-y += qdev-monitor.o device-hotplug.o
common-obj-$(CONFIG_WIN32) += os-win32.o
@@ -140,6 +144,7 @@ common-obj-y += qapi/qapi-commands-char.o
common-obj-y += qapi/qapi-commands-common.o
common-obj-y += qapi/qapi-commands-crypto.o
common-obj-y += qapi/qapi-commands-introspect.o
+common-obj-y += qapi/qapi-commands-job.o
common-obj-y += qapi/qapi-commands-migration.o
common-obj-y += qapi/qapi-commands-misc.o
common-obj-y += qapi/qapi-commands-net.o
@@ -191,66 +196,66 @@ vhost-user-blk-obj-y = contrib/vhost-user-blk/
######################################################################
trace-events-subdirs =
-trace-events-subdirs += util
-trace-events-subdirs += crypto
-trace-events-subdirs += io
-trace-events-subdirs += migration
+trace-events-subdirs += accel/kvm
+trace-events-subdirs += accel/tcg
+trace-events-subdirs += audio
trace-events-subdirs += block
trace-events-subdirs += chardev
+trace-events-subdirs += crypto
+trace-events-subdirs += hw/9pfs
+trace-events-subdirs += hw/acpi
+trace-events-subdirs += hw/alpha
+trace-events-subdirs += hw/arm
+trace-events-subdirs += hw/audio
trace-events-subdirs += hw/block
trace-events-subdirs += hw/block/dataplane
trace-events-subdirs += hw/char
-trace-events-subdirs += hw/intc
-trace-events-subdirs += hw/net
-trace-events-subdirs += hw/rdma
-trace-events-subdirs += hw/rdma/vmw
-trace-events-subdirs += hw/virtio
-trace-events-subdirs += hw/audio
-trace-events-subdirs += hw/misc
-trace-events-subdirs += hw/misc/macio
-trace-events-subdirs += hw/usb
-trace-events-subdirs += hw/scsi
-trace-events-subdirs += hw/nvram
trace-events-subdirs += hw/display
-trace-events-subdirs += hw/input
-trace-events-subdirs += hw/timer
trace-events-subdirs += hw/dma
-trace-events-subdirs += hw/sparc
-trace-events-subdirs += hw/sparc64
-trace-events-subdirs += hw/sd
-trace-events-subdirs += hw/isa
-trace-events-subdirs += hw/mem
+trace-events-subdirs += hw/hppa
trace-events-subdirs += hw/i386
trace-events-subdirs += hw/i386/xen
-trace-events-subdirs += hw/9pfs
-trace-events-subdirs += hw/ppc
+trace-events-subdirs += hw/ide
+trace-events-subdirs += hw/input
+trace-events-subdirs += hw/intc
+trace-events-subdirs += hw/isa
+trace-events-subdirs += hw/mem
+trace-events-subdirs += hw/misc
+trace-events-subdirs += hw/misc/macio
+trace-events-subdirs += hw/net
+trace-events-subdirs += hw/nvram
trace-events-subdirs += hw/pci
trace-events-subdirs += hw/pci-host
+trace-events-subdirs += hw/ppc
+trace-events-subdirs += hw/rdma
+trace-events-subdirs += hw/rdma/vmw
trace-events-subdirs += hw/s390x
+trace-events-subdirs += hw/scsi
+trace-events-subdirs += hw/sd
+trace-events-subdirs += hw/sparc
+trace-events-subdirs += hw/sparc64
+trace-events-subdirs += hw/timer
+trace-events-subdirs += hw/tpm
+trace-events-subdirs += hw/usb
trace-events-subdirs += hw/vfio
-trace-events-subdirs += hw/acpi
-trace-events-subdirs += hw/arm
-trace-events-subdirs += hw/alpha
-trace-events-subdirs += hw/hppa
+trace-events-subdirs += hw/virtio
trace-events-subdirs += hw/xen
-trace-events-subdirs += hw/ide
-trace-events-subdirs += hw/tpm
-trace-events-subdirs += ui
-trace-events-subdirs += audio
+trace-events-subdirs += io
+trace-events-subdirs += linux-user
+trace-events-subdirs += migration
+trace-events-subdirs += nbd
trace-events-subdirs += net
+trace-events-subdirs += qapi
+trace-events-subdirs += qom
+trace-events-subdirs += scsi
trace-events-subdirs += target/arm
trace-events-subdirs += target/i386
trace-events-subdirs += target/mips
-trace-events-subdirs += target/sparc
-trace-events-subdirs += target/s390x
trace-events-subdirs += target/ppc
-trace-events-subdirs += qom
-trace-events-subdirs += linux-user
-trace-events-subdirs += qapi
-trace-events-subdirs += accel/tcg
-trace-events-subdirs += accel/kvm
-trace-events-subdirs += nbd
-trace-events-subdirs += scsi
+trace-events-subdirs += target/s390x
+trace-events-subdirs += target/sparc
+trace-events-subdirs += ui
+trace-events-subdirs += util
trace-events-files = $(SRC_PATH)/trace-events $(trace-events-subdirs:%=$(SRC_PATH)/%/trace-events)
diff --git a/Makefile.target b/Makefile.target
index d0ec77a307..dad2cf8778 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -97,7 +97,7 @@ obj-$(CONFIG_TCG) += tcg/tcg.o tcg/tcg-op.o tcg/tcg-op-vec.o tcg/tcg-op-gvec.o
obj-$(CONFIG_TCG) += tcg/tcg-common.o tcg/optimize.o
obj-$(CONFIG_TCG_INTERPRETER) += tcg/tci.o
obj-$(CONFIG_TCG_INTERPRETER) += disas/tci.o
-obj-y += fpu/softfloat.o
+obj-$(CONFIG_TCG) += fpu/softfloat.o
obj-y += target/$(TARGET_BASE_ARCH)/
obj-y += disas.o
obj-$(call notempty,$(TARGET_XML_FILES)) += gdbstub-xml.o
diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index 0b154cc678..4ef95d8dd3 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -25,7 +25,6 @@
#include "qemu/atomic.h"
#include "sysemu/qtest.h"
#include "qemu/timer.h"
-#include "exec/address-spaces.h"
#include "qemu/rcu.h"
#include "exec/tb-hash.h"
#include "exec/tb-lookup.h"
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index 732c919629..d48b56ca38 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -1669,14 +1669,14 @@ static TranslationBlock *tb_find_pc(uintptr_t tc_ptr)
}
#if !defined(CONFIG_USER_ONLY)
-void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr)
+void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr, MemTxAttrs attrs)
{
ram_addr_t ram_addr;
MemoryRegion *mr;
hwaddr l = 1;
rcu_read_lock();
- mr = address_space_translate(as, addr, &addr, &l, false);
+ mr = address_space_translate(as, addr, &addr, &l, false, attrs);
if (!(memory_region_is_ram(mr)
|| memory_region_is_romd(mr))) {
rcu_read_unlock();
diff --git a/block.c b/block.c
index 676e57f562..501b64c819 100644
--- a/block.c
+++ b/block.c
@@ -3362,7 +3362,7 @@ static void bdrv_close(BlockDriverState *bs)
void bdrv_close_all(void)
{
- block_job_cancel_sync_all();
+ assert(job_next(NULL) == NULL);
nbd_export_close_all();
/* Drop references from requests still in flight, such as canceled block
diff --git a/block/backup.c b/block/backup.c
index e14d99560d..5661435675 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -160,7 +160,7 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job,
* offset field is an opaque progress value, it is not a disk offset.
*/
job->bytes_read += n;
- block_job_progress_update(&job->common, n);
+ job_progress_update(&job->common.job, n);
}
out:
@@ -207,25 +207,25 @@ static void backup_cleanup_sync_bitmap(BackupBlockJob *job, int ret)
}
}
-static void backup_commit(BlockJob *job)
+static void backup_commit(Job *job)
{
- BackupBlockJob *s = container_of(job, BackupBlockJob, common);
+ BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
if (s->sync_bitmap) {
backup_cleanup_sync_bitmap(s, 0);
}
}
-static void backup_abort(BlockJob *job)
+static void backup_abort(Job *job)
{
- BackupBlockJob *s = container_of(job, BackupBlockJob, common);
+ BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
if (s->sync_bitmap) {
backup_cleanup_sync_bitmap(s, -1);
}
}
-static void backup_clean(BlockJob *job)
+static void backup_clean(Job *job)
{
- BackupBlockJob *s = container_of(job, BackupBlockJob, common);
+ BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
assert(s->target);
blk_unref(s->target);
s->target = NULL;
@@ -317,11 +317,11 @@ typedef struct {
int ret;
} BackupCompleteData;
-static void backup_complete(BlockJob *job, void *opaque)
+static void backup_complete(Job *job, void *opaque)
{
BackupCompleteData *data = opaque;
- block_job_completed(job, data->ret);
+ job_completed(job, data->ret, NULL);
g_free(data);
}
@@ -329,7 +329,7 @@ static bool coroutine_fn yield_and_check(BackupBlockJob *job)
{
uint64_t delay_ns;
- if (block_job_is_cancelled(&job->common)) {
+ if (job_is_cancelled(&job->common.job)) {
return true;
}
@@ -337,9 +337,9 @@ static bool coroutine_fn yield_and_check(BackupBlockJob *job)
* return. Without a yield, the VM would not reboot. */
delay_ns = block_job_ratelimit_get_delay(&job->common, job->bytes_read);
job->bytes_read = 0;
- block_job_sleep_ns(&job->common, delay_ns);
+ job_sleep_ns(&job->common.job, delay_ns);
- if (block_job_is_cancelled(&job->common)) {
+ if (job_is_cancelled(&job->common.job)) {
return true;
}
@@ -406,8 +406,8 @@ static void backup_incremental_init_copy_bitmap(BackupBlockJob *job)
bdrv_set_dirty_iter(dbi, next_cluster * job->cluster_size);
}
- /* TODO block_job_progress_set_remaining() would make more sense */
- block_job_progress_update(&job->common,
+ /* TODO job_progress_set_remaining() would make more sense */
+ job_progress_update(&job->common.job,
job->len - hbitmap_count(job->copy_bitmap) * job->cluster_size);
bdrv_dirty_iter_free(dbi);
@@ -425,7 +425,7 @@ static void coroutine_fn backup_run(void *opaque)
qemu_co_rwlock_init(&job->flush_rwlock);
nb_clusters = DIV_ROUND_UP(job->len, job->cluster_size);
- block_job_progress_set_remaining(&job->common, job->len);
+ job_progress_set_remaining(&job->common.job, job->len);
job->copy_bitmap = hbitmap_alloc(nb_clusters, 0);
if (job->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) {
@@ -441,10 +441,10 @@ static void coroutine_fn backup_run(void *opaque)
if (job->sync_mode == MIRROR_SYNC_MODE_NONE) {
/* All bits are set in copy_bitmap to allow any cluster to be copied.
* This does not actually require them to be copied. */
- while (!block_job_is_cancelled(&job->common)) {
+ while (!job_is_cancelled(&job->common.job)) {
/* Yield until the job is cancelled. We just let our before_write
* notify callback service CoW requests. */
- block_job_yield(&job->common);
+ job_yield(&job->common.job);
}
} else if (job->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) {
ret = backup_run_incremental(job);
@@ -519,16 +519,21 @@ static void coroutine_fn backup_run(void *opaque)
data = g_malloc(sizeof(*data));
data->ret = ret;
- block_job_defer_to_main_loop(&job->common, backup_complete, data);
+ job_defer_to_main_loop(&job->common.job, backup_complete, data);
}
static const BlockJobDriver backup_job_driver = {
- .instance_size = sizeof(BackupBlockJob),
- .job_type = BLOCK_JOB_TYPE_BACKUP,
- .start = backup_run,
- .commit = backup_commit,
- .abort = backup_abort,
- .clean = backup_clean,
+ .job_driver = {
+ .instance_size = sizeof(BackupBlockJob),
+ .job_type = JOB_TYPE_BACKUP,
+ .free = block_job_free,
+ .user_resume = block_job_user_resume,
+ .drain = block_job_drain,
+ .start = backup_run,
+ .commit = backup_commit,
+ .abort = backup_abort,
+ .clean = backup_clean,
+ },
.attached_aio_context = backup_attached_aio_context,
.drain = backup_drain,
};
@@ -541,7 +546,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
BlockdevOnError on_target_error,
int creation_flags,
BlockCompletionFunc *cb, void *opaque,
- BlockJobTxn *txn, Error **errp)
+ JobTxn *txn, Error **errp)
{
int64_t len;
BlockDriverInfo bdi;
@@ -673,8 +678,8 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
bdrv_reclaim_dirty_bitmap(bs, sync_bitmap, NULL);
}
if (job) {
- backup_clean(&job->common);
- block_job_early_fail(&job->common);
+ backup_clean(&job->common.job);
+ job_early_fail(&job->common.job);
}
return NULL;
diff --git a/block/commit.c b/block/commit.c
index ba5df6aa0a..e1814d9693 100644
--- a/block/commit.c
+++ b/block/commit.c
@@ -72,9 +72,10 @@ typedef struct {
int ret;
} CommitCompleteData;
-static void commit_complete(BlockJob *job, void *opaque)
+static void commit_complete(Job *job, void *opaque)
{
- CommitBlockJob *s = container_of(job, CommitBlockJob, common);
+ CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
+ BlockJob *bjob = &s->common;
CommitCompleteData *data = opaque;
BlockDriverState *top = blk_bs(s->top);
BlockDriverState *base = blk_bs(s->base);
@@ -90,7 +91,7 @@ static void commit_complete(BlockJob *job, void *opaque)
* the normal backing chain can be restored. */
blk_unref(s->base);
- if (!block_job_is_cancelled(&s->common) && ret == 0) {
+ if (!job_is_cancelled(job) && ret == 0) {
/* success */
ret = bdrv_drop_intermediate(s->commit_top_bs, base,
s->backing_file_str);
@@ -111,12 +112,12 @@ static void commit_complete(BlockJob *job, void *opaque)
blk_unref(s->top);
/* If there is more than one reference to the job (e.g. if called from
- * block_job_finish_sync()), block_job_completed() won't free it and
- * therefore the blockers on the intermediate nodes remain. This would
- * cause bdrv_set_backing_hd() to fail. */
- block_job_remove_all_bdrv(job);
+ * job_finish_sync()), job_completed() won't free it and therefore the
+ * blockers on the intermediate nodes remain. This would cause
+ * bdrv_set_backing_hd() to fail. */
+ block_job_remove_all_bdrv(bjob);
- block_job_completed(&s->common, ret);
+ job_completed(job, ret, NULL);
g_free(data);
/* If bdrv_drop_intermediate() didn't already do that, remove the commit
@@ -149,7 +150,7 @@ static void coroutine_fn commit_run(void *opaque)
if (len < 0) {
goto out;
}
- block_job_progress_set_remaining(&s->common, len);
+ job_progress_set_remaining(&s->common.job, len);
ret = base_len = blk_getlength(s->base);
if (base_len < 0) {
@@ -171,8 +172,8 @@ static void coroutine_fn commit_run(void *opaque)
/* Note that even when no rate limit is applied we need to yield
* with no pending I/O here so that bdrv_drain_all() returns.
*/
- block_job_sleep_ns(&s->common, delay_ns);
- if (block_job_is_cancelled(&s->common)) {
+ job_sleep_ns(&s->common.job, delay_ns);
+ if (job_is_cancelled(&s->common.job)) {
break;
}
/* Copy if allocated above the base */
@@ -195,7 +196,7 @@ static void coroutine_fn commit_run(void *opaque)
}
}
/* Publish progress */
- block_job_progress_update(&s->common, n);
+ job_progress_update(&s->common.job, n);
if (copy) {
delay_ns = block_job_ratelimit_get_delay(&s->common, n);
@@ -211,13 +212,18 @@ out:
data = g_malloc(sizeof(*data));
data->ret = ret;
- block_job_defer_to_main_loop(&s->common, commit_complete, data);
+ job_defer_to_main_loop(&s->common.job, commit_complete, data);
}
static const BlockJobDriver commit_job_driver = {
- .instance_size = sizeof(CommitBlockJob),
- .job_type = BLOCK_JOB_TYPE_COMMIT,
- .start = commit_run,
+ .job_driver = {
+ .instance_size = sizeof(CommitBlockJob),
+ .job_type = JOB_TYPE_COMMIT,
+ .free = block_job_free,
+ .user_resume = block_job_user_resume,
+ .drain = block_job_drain,
+ .start = commit_run,
+ },
};
static int coroutine_fn bdrv_commit_top_preadv(BlockDriverState *bs,
@@ -277,7 +283,7 @@ void commit_start(const char *job_id, BlockDriverState *bs,
}
s = block_job_create(job_id, &commit_job_driver, NULL, bs, 0, BLK_PERM_ALL,
- speed, BLOCK_JOB_DEFAULT, NULL, NULL, errp);
+ speed, JOB_DEFAULT, NULL, NULL, errp);
if (!s) {
return;
}
@@ -367,7 +373,7 @@ void commit_start(const char *job_id, BlockDriverState *bs,
s->on_error = on_error;
trace_commit_start(bs, base, top, s);
- block_job_start(&s->common);
+ job_start(&s->common.job);
return;
fail:
@@ -380,7 +386,7 @@ fail:
if (commit_top_bs) {
bdrv_replace_node(commit_top_bs, top, &error_abort);
}
- block_job_early_fail(&s->common);
+ job_early_fail(&s->common.job);
}
diff --git a/block/create.c b/block/create.c
index 8bd8a03719..915cd41bcc 100644
--- a/block/create.c
+++ b/block/create.c
@@ -24,28 +24,51 @@
#include "qemu/osdep.h"
#include "block/block_int.h"
+#include "qemu/job.h"
#include "qapi/qapi-commands-block-core.h"
+#include "qapi/qapi-visit-block-core.h"
+#include "qapi/clone-visitor.h"
#include "qapi/error.h"
-typedef struct BlockdevCreateCo {
+typedef struct BlockdevCreateJob {
+ Job common;
BlockDriver *drv;
BlockdevCreateOptions *opts;
int ret;
- Error **errp;
-} BlockdevCreateCo;
+ Error *err;
+} BlockdevCreateJob;
-static void coroutine_fn bdrv_co_create_co_entry(void *opaque)
+static void blockdev_create_complete(Job *job, void *opaque)
{
- BlockdevCreateCo *cco = opaque;
- cco->ret = cco->drv->bdrv_co_create(cco->opts, cco->errp);
+ BlockdevCreateJob *s = container_of(job, BlockdevCreateJob, common);
+
+ job_completed(job, s->ret, s->err);
}
-void qmp_x_blockdev_create(BlockdevCreateOptions *options, Error **errp)
+static void coroutine_fn blockdev_create_run(void *opaque)
{
+ BlockdevCreateJob *s = opaque;
+
+ job_progress_set_remaining(&s->common, 1);
+ s->ret = s->drv->bdrv_co_create(s->opts, &s->err);
+ job_progress_update(&s->common, 1);
+
+ qapi_free_BlockdevCreateOptions(s->opts);
+ job_defer_to_main_loop(&s->common, blockdev_create_complete, NULL);
+}
+
+static const JobDriver blockdev_create_job_driver = {
+ .instance_size = sizeof(BlockdevCreateJob),
+ .job_type = JOB_TYPE_CREATE,
+ .start = blockdev_create_run,
+};
+
+void qmp_blockdev_create(const char *job_id, BlockdevCreateOptions *options,
+ Error **errp)
+{
+ BlockdevCreateJob *s;
const char *fmt = BlockdevDriver_str(options->driver);
BlockDriver *drv = bdrv_find_format(fmt);
- Coroutine *co;
- BlockdevCreateCo cco;
/* If the driver is in the schema, we know that it exists. But it may not
* be whitelisted. */
@@ -55,22 +78,24 @@ void qmp_x_blockdev_create(BlockdevCreateOptions *options, Error **errp)
return;
}
- /* Call callback if it exists */
+ /* Error out if the driver doesn't support .bdrv_co_create */
if (!drv->bdrv_co_create) {
error_setg(errp, "Driver does not support blockdev-create");
return;
}
- cco = (BlockdevCreateCo) {
- .drv = drv,
- .opts = options,
- .ret = -EINPROGRESS,
- .errp = errp,
- };
-
- co = qemu_coroutine_create(bdrv_co_create_co_entry, &cco);
- qemu_coroutine_enter(co);
- while (cco.ret == -EINPROGRESS) {
- aio_poll(qemu_get_aio_context(), true);
+ /* Create the block job */
+ /* TODO Running in the main context. Block drivers need to error out or add
+ * locking when they use a BDS in a different AioContext. */
+ s = job_create(job_id, &blockdev_create_job_driver, NULL,
+ qemu_get_aio_context(), JOB_DEFAULT | JOB_MANUAL_DISMISS,
+ NULL, NULL, errp);
+ if (!s) {
+ return;
}
+
+ s->drv = drv,
+ s->opts = QAPI_CLONE(BlockdevCreateOptions, options),
+
+ job_start(&s->common);
}
diff --git a/block/mirror.c b/block/mirror.c
index a4197bb975..435268bbbf 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -119,14 +119,14 @@ static void mirror_iteration_done(MirrorOp *op, int ret)
bitmap_set(s->cow_bitmap, chunk_num, nb_chunks);
}
if (!s->initial_zeroing_ongoing) {
- block_job_progress_update(&s->common, op->bytes);
+ job_progress_update(&s->common.job, op->bytes);
}
}
qemu_iovec_destroy(&op->qiov);
g_free(op);
if (s->waiting_for_io) {
- qemu_coroutine_enter(s->common.co);
+ qemu_coroutine_enter(s->common.job.co);
}
}
@@ -345,7 +345,7 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
mirror_wait_for_io(s);
}
- block_job_pause_point(&s->common);
+ job_pause_point(&s->common.job);
/* Find the number of consective dirty chunks following the first dirty
* one, and wait for in flight requests in them. */
@@ -484,9 +484,10 @@ typedef struct {
int ret;
} MirrorExitData;
-static void mirror_exit(BlockJob *job, void *opaque)
+static void mirror_exit(Job *job, void *opaque)
{
- MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
+ MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job);
+ BlockJob *bjob = &s->common;
MirrorExitData *data = opaque;
AioContext *replace_aio_context = NULL;
BlockDriverState *src = s->source;
@@ -497,7 +498,7 @@ static void mirror_exit(BlockJob *job, void *opaque)
bdrv_release_dirty_bitmap(src, s->dirty_bitmap);
/* Make sure that the source BDS doesn't go away before we called
- * block_job_completed(). */
+ * job_completed(). */
bdrv_ref(src);
bdrv_ref(mirror_top_bs);
bdrv_ref(target_bs);
@@ -568,7 +569,7 @@ static void mirror_exit(BlockJob *job, void *opaque)
* the blockers on the intermediate nodes so that the resulting state is
* valid. Also give up permissions on mirror_top_bs->backing, which might
* block the removal. */
- block_job_remove_all_bdrv(job);
+ block_job_remove_all_bdrv(bjob);
bdrv_child_try_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL,
&error_abort);
bdrv_replace_node(mirror_top_bs, backing_bs(mirror_top_bs), &error_abort);
@@ -576,11 +577,11 @@ static void mirror_exit(BlockJob *job, void *opaque)
/* We just changed the BDS the job BB refers to (with either or both of the
* bdrv_replace_node() calls), so switch the BB back so the cleanup does
* the right thing. We don't need any permissions any more now. */
- blk_remove_bs(job->blk);
- blk_set_perm(job->blk, 0, BLK_PERM_ALL, &error_abort);
- blk_insert_bs(job->blk, mirror_top_bs, &error_abort);
+ blk_remove_bs(bjob->blk);
+ blk_set_perm(bjob->blk, 0, BLK_PERM_ALL, &error_abort);
+ blk_insert_bs(bjob->blk, mirror_top_bs, &error_abort);
- block_job_completed(&s->common, data->ret);
+ job_completed(job, data->ret, NULL);
g_free(data);
bdrv_drained_end(src);
@@ -594,9 +595,9 @@ static void mirror_throttle(MirrorBlockJob *s)
if (now - s->last_pause_ns > BLOCK_JOB_SLICE_TIME) {
s->last_pause_ns = now;
- block_job_sleep_ns(&s->common, 0);
+ job_sleep_ns(&s->common.job, 0);
} else {
- block_job_pause_point(&s->common);
+ job_pause_point(&s->common.job);
}
}
@@ -622,7 +623,7 @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
mirror_throttle(s);
- if (block_job_is_cancelled(&s->common)) {
+ if (job_is_cancelled(&s->common.job)) {
s->initial_zeroing_ongoing = false;
return 0;
}
@@ -650,7 +651,7 @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
mirror_throttle(s);
- if (block_job_is_cancelled(&s->common)) {
+ if (job_is_cancelled(&s->common.job)) {
return 0;
}
@@ -695,7 +696,7 @@ static void coroutine_fn mirror_run(void *opaque)
checking for a NULL string */
int ret = 0;
- if (block_job_is_cancelled(&s->common)) {
+ if (job_is_cancelled(&s->common.job)) {
goto immediate_exit;
}
@@ -726,13 +727,13 @@ static void coroutine_fn mirror_run(void *opaque)
}
if (s->bdev_length == 0) {
- /* Report BLOCK_JOB_READY and wait for complete. */
- block_job_event_ready(&s->common);
+ /* Transition to the READY state and wait for complete. */
+ job_transition_to_ready(&s->common.job);
s->synced = true;
- while (!block_job_is_cancelled(&s->common) && !s->should_complete) {
- block_job_yield(&s->common);
+ while (!job_is_cancelled(&s->common.job) && !s->should_complete) {
+ job_yield(&s->common.job);
}
- s->common.cancelled = false;
+ s->common.job.cancelled = false;
goto immediate_exit;
}
@@ -768,7 +769,7 @@ static void coroutine_fn mirror_run(void *opaque)
s->last_pause_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
if (!s->is_none_mode) {
ret = mirror_dirty_init(s);
- if (ret < 0 || block_job_is_cancelled(&s->common)) {
+ if (ret < 0 || job_is_cancelled(&s->common.job)) {
goto immediate_exit;
}
}
@@ -785,13 +786,13 @@ static void coroutine_fn mirror_run(void *opaque)
goto immediate_exit;
}
- block_job_pause_point(&s->common);
+ job_pause_point(&s->common.job);
cnt = bdrv_get_dirty_count(s->dirty_bitmap);
/* cnt is the number of dirty bytes remaining and s->bytes_in_flight is
* the number of bytes currently being processed; together those are
* the current remaining operation length */
- block_job_progress_set_remaining(&s->common, s->bytes_in_flight + cnt);
+ job_progress_set_remaining(&s->common.job, s->bytes_in_flight + cnt);
/* Note that even when no rate limit is applied we need to yield
* periodically with no pending I/O so that bdrv_drain_all() returns.
@@ -823,12 +824,12 @@ static void coroutine_fn mirror_run(void *opaque)
* report completion. This way, block-job-cancel will leave
* the target in a consistent state.
*/
- block_job_event_ready(&s->common);
+ job_transition_to_ready(&s->common.job);
s->synced = true;
}
should_complete = s->should_complete ||
- block_job_is_cancelled(&s->common);
+ job_is_cancelled(&s->common.job);
cnt = bdrv_get_dirty_count(s->dirty_bitmap);
}
@@ -856,7 +857,7 @@ static void coroutine_fn mirror_run(void *opaque)
* completion.
*/
assert(QLIST_EMPTY(&bs->tracked_requests));
- s->common.cancelled = false;
+ s->common.job.cancelled = false;
need_drain = false;
break;
}
@@ -868,9 +869,9 @@ static void coroutine_fn mirror_run(void *opaque)
cnt == 0 ? BLOCK_JOB_SLICE_TIME : 0);
}
trace_mirror_before_sleep(s, cnt, s->synced, delay_ns);
- block_job_sleep_ns(&s->common, delay_ns);
- if (block_job_is_cancelled(&s->common) &&
- (!s->synced || s->common.force))
+ job_sleep_ns(&s->common.job, delay_ns);
+ if (job_is_cancelled(&s->common.job) &&
+ (!s->synced || s->common.job.force_cancel))
{
break;
}
@@ -883,8 +884,8 @@ immediate_exit:
* or it was cancelled prematurely so that we do not guarantee that
* the target is a copy of the source.
*/
- assert(ret < 0 || ((s->common.force || !s->synced) &&
- block_job_is_cancelled(&s->common)));
+ assert(ret < 0 || ((s->common.job.force_cancel || !s->synced) &&
+ job_is_cancelled(&s->common.job)));
assert(need_drain);
mirror_wait_for_all_io(s);
}
@@ -901,12 +902,12 @@ immediate_exit:
if (need_drain) {
bdrv_drained_begin(bs);
}
- block_job_defer_to_main_loop(&s->common, mirror_exit, data);
+ job_defer_to_main_loop(&s->common.job, mirror_exit, data);
}
-static void mirror_complete(BlockJob *job, Error **errp)
+static void mirror_complete(Job *job, Error **errp)
{
- MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
+ MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job);
BlockDriverState *target;
target = blk_bs(s->target);
@@ -953,12 +954,12 @@ static void mirror_complete(BlockJob *job, Error **errp)
}
s->should_complete = true;
- block_job_enter(&s->common);
+ job_enter(job);
}
-static void mirror_pause(BlockJob *job)
+static void mirror_pause(Job *job)
{
- MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
+ MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job);
mirror_wait_for_all_io(s);
}
@@ -986,21 +987,31 @@ static void mirror_drain(BlockJob *job)
}
static const BlockJobDriver mirror_job_driver = {
- .instance_size = sizeof(MirrorBlockJob),
- .job_type = BLOCK_JOB_TYPE_MIRROR,
- .start = mirror_run,
- .complete = mirror_complete,
- .pause = mirror_pause,
+ .job_driver = {
+ .instance_size = sizeof(MirrorBlockJob),
+ .job_type = JOB_TYPE_MIRROR,
+ .free = block_job_free,
+ .user_resume = block_job_user_resume,
+ .drain = block_job_drain,
+ .start = mirror_run,
+ .pause = mirror_pause,
+ .complete = mirror_complete,
+ },
.attached_aio_context = mirror_attached_aio_context,
.drain = mirror_drain,
};
static const BlockJobDriver commit_active_job_driver = {
- .instance_size = sizeof(MirrorBlockJob),
- .job_type = BLOCK_JOB_TYPE_COMMIT,
- .start = mirror_run,
- .complete = mirror_complete,
- .pause = mirror_pause,
+ .job_driver = {
+ .instance_size = sizeof(MirrorBlockJob),
+ .job_type = JOB_TYPE_COMMIT,
+ .free = block_job_free,
+ .user_resume = block_job_user_resume,
+ .drain = block_job_drain,
+ .start = mirror_run,
+ .pause = mirror_pause,
+ .complete = mirror_complete,
+ },
.attached_aio_context = mirror_attached_aio_context,
.drain = mirror_drain,
};
@@ -1237,7 +1248,7 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
}
trace_mirror_start(bs, s, opaque);
- block_job_start(&s->common);
+ job_start(&s->common.job);
return;
fail:
@@ -1248,7 +1259,7 @@ fail:
g_free(s->replaces);
blk_unref(s->target);
- block_job_early_fail(&s->common);
+ job_early_fail(&s->common.job);
}
bdrv_child_try_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL,
@@ -1275,7 +1286,7 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
}
is_none_mode = mode == MIRROR_SYNC_MODE_NONE;
base = mode == MIRROR_SYNC_MODE_TOP ? backing_bs(bs) : NULL;
- mirror_start_job(job_id, bs, BLOCK_JOB_DEFAULT, target, replaces,
+ mirror_start_job(job_id, bs, JOB_DEFAULT, target, replaces,
speed, granularity, buf_size, backing_mode,
on_source_error, on_target_error, unmap, NULL, NULL,
&mirror_job_driver, is_none_mode, base, false,
diff --git a/block/qcow2.c b/block/qcow2.c
index db13109744..c87c593e83 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -768,6 +768,7 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
BDRVQcow2State *s = bs->opaque;
uint64_t combined_cache_size;
bool l2_cache_size_set, refcount_cache_size_set, combined_cache_size_set;
+ int min_refcount_cache = MIN_REFCOUNT_CACHE_SIZE * s->cluster_size;
combined_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_CACHE_SIZE);
l2_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_L2_CACHE_SIZE);
@@ -804,8 +805,6 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
} else {
uint64_t virtual_disk_size = bs->total_sectors * BDRV_SECTOR_SIZE;
uint64_t max_l2_cache = virtual_disk_size / (s->cluster_size / 8);
- uint64_t min_refcount_cache =
- (uint64_t) MIN_REFCOUNT_CACHE_SIZE * s->cluster_size;
/* Assign as much memory as possible to the L2 cache, and
* use the remainder for the refcount cache */
@@ -825,7 +824,7 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
* s->cluster_size);
}
if (!refcount_cache_size_set) {
- *refcount_cache_size = MIN_REFCOUNT_CACHE_SIZE * s->cluster_size;
+ *refcount_cache_size = min_refcount_cache;
}
}
diff --git a/block/replication.c b/block/replication.c
index 48148b884a..826db7b304 100644
--- a/block/replication.c
+++ b/block/replication.c
@@ -145,7 +145,7 @@ static void replication_close(BlockDriverState *bs)
replication_stop(s->rs, false, NULL);
}
if (s->stage == BLOCK_REPLICATION_FAILOVER) {
- block_job_cancel_sync(s->active_disk->bs->job);
+ job_cancel_sync(&s->active_disk->bs->job->job);
}
if (s->mode == REPLICATION_MODE_SECONDARY) {
@@ -568,7 +568,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
job = backup_job_create(NULL, s->secondary_disk->bs, s->hidden_disk->bs,
0, MIRROR_SYNC_MODE_NONE, NULL, false,
BLOCKDEV_ON_ERROR_REPORT,
- BLOCKDEV_ON_ERROR_REPORT, BLOCK_JOB_INTERNAL,
+ BLOCKDEV_ON_ERROR_REPORT, JOB_INTERNAL,
backup_job_completed, bs, NULL, &local_err);
if (local_err) {
error_propagate(errp, local_err);
@@ -576,7 +576,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
aio_context_release(aio_context);
return;
}
- block_job_start(job);
+ job_start(&job->job);
break;
default:
aio_context_release(aio_context);
@@ -681,7 +681,7 @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp)
* disk, secondary disk in backup_job_completed().
*/
if (s->secondary_disk->bs->job) {
- block_job_cancel_sync(s->secondary_disk->bs->job);
+ job_cancel_sync(&s->secondary_disk->bs->job->job);
}
if (!failover) {
@@ -693,7 +693,7 @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp)
s->stage = BLOCK_REPLICATION_FAILOVER;
commit_active_start(NULL, s->active_disk->bs, s->secondary_disk->bs,
- BLOCK_JOB_INTERNAL, 0, BLOCKDEV_ON_ERROR_REPORT,
+ JOB_INTERNAL, 0, BLOCKDEV_ON_ERROR_REPORT,
NULL, replication_done, bs, true, errp);
break;
default:
diff --git a/block/sheepdog.c b/block/sheepdog.c
index 4237132419..2a5bc0a59a 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -1859,9 +1859,7 @@ out:
error_setg_errno(errp, -ret, "Can't pre-allocate");
}
out_with_err_set:
- if (blk) {
- blk_unref(blk);
- }
+ blk_unref(blk);
g_free(buf);
return ret;
diff --git a/block/stream.c b/block/stream.c
index df9660d2fc..9264b68a1e 100644
--- a/block/stream.c
+++ b/block/stream.c
@@ -58,16 +58,16 @@ typedef struct {
int ret;
} StreamCompleteData;
-static void stream_complete(BlockJob *job, void *opaque)
+static void stream_complete(Job *job, void *opaque)
{
- StreamBlockJob *s = container_of(job, StreamBlockJob, common);
+ StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
+ BlockJob *bjob = &s->common;
StreamCompleteData *data = opaque;
- BlockDriverState *bs = blk_bs(job->blk);
+ BlockDriverState *bs = blk_bs(bjob->blk);
BlockDriverState *base = s->base;
Error *local_err = NULL;
- if (!block_job_is_cancelled(&s->common) && bs->backing &&
- data->ret == 0) {
+ if (!job_is_cancelled(job) && bs->backing && data->ret == 0) {
const char *base_id = NULL, *base_fmt = NULL;
if (base) {
base_id = s->backing_file_str;
@@ -88,12 +88,12 @@ out:
/* Reopen the image back in read-only mode if necessary */
if (s->bs_flags != bdrv_get_flags(bs)) {
/* Give up write permissions before making it read-only */
- blk_set_perm(job->blk, 0, BLK_PERM_ALL, &error_abort);
+ blk_set_perm(bjob->blk, 0, BLK_PERM_ALL, &error_abort);
bdrv_reopen(bs, s->bs_flags, NULL);
}
g_free(s->backing_file_str);
- block_job_completed(&s->common, data->ret);
+ job_completed(job, data->ret, NULL);
g_free(data);
}
@@ -121,7 +121,7 @@ static void coroutine_fn stream_run(void *opaque)
ret = len;
goto out;
}
- block_job_progress_set_remaining(&s->common, len);
+ job_progress_set_remaining(&s->common.job, len);
buf = qemu_blockalign(bs, STREAM_BUFFER_SIZE);
@@ -140,8 +140,8 @@ static void coroutine_fn stream_run(void *opaque)
/* Note that even when no rate limit is applied we need to yield
* with no pending I/O here so that bdrv_drain_all() returns.
*/
- block_job_sleep_ns(&s->common, delay_ns);
- if (block_job_is_cancelled(&s->common)) {
+ job_sleep_ns(&s->common.job, delay_ns);
+ if (job_is_cancelled(&s->common.job)) {
break;
}
@@ -184,7 +184,7 @@ static void coroutine_fn stream_run(void *opaque)
ret = 0;
/* Publish progress */
- block_job_progress_update(&s->common, n);
+ job_progress_update(&s->common.job, n);
if (copy) {
delay_ns = block_job_ratelimit_get_delay(&s->common, n);
} else {
@@ -205,13 +205,18 @@ out:
/* Modify backing chain and close BDSes in main loop */
data = g_malloc(sizeof(*data));
data->ret = ret;
- block_job_defer_to_main_loop(&s->common, stream_complete, data);
+ job_defer_to_main_loop(&s->common.job, stream_complete, data);
}
static const BlockJobDriver stream_job_driver = {
- .instance_size = sizeof(StreamBlockJob),
- .job_type = BLOCK_JOB_TYPE_STREAM,
- .start = stream_run,
+ .job_driver = {
+ .instance_size = sizeof(StreamBlockJob),
+ .job_type = JOB_TYPE_STREAM,
+ .free = block_job_free,
+ .start = stream_run,
+ .user_resume = block_job_user_resume,
+ .drain = block_job_drain,
+ },
};
void stream_start(const char *job_id, BlockDriverState *bs,
@@ -238,7 +243,7 @@ void stream_start(const char *job_id, BlockDriverState *bs,
BLK_PERM_GRAPH_MOD,
BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
BLK_PERM_WRITE,
- speed, BLOCK_JOB_DEFAULT, NULL, NULL, errp);
+ speed, JOB_DEFAULT, NULL, NULL, errp);
if (!s) {
goto fail;
}
@@ -259,7 +264,7 @@ void stream_start(const char *job_id, BlockDriverState *bs,
s->on_error = on_error;
trace_stream_start(bs, base, s);
- block_job_start(&s->common);
+ job_start(&s->common.job);
return;
fail:
diff --git a/block/trace-events b/block/trace-events
index f8c50b4063..2d59b53fd3 100644
--- a/block/trace-events
+++ b/block/trace-events
@@ -4,11 +4,6 @@
bdrv_open_common(void *bs, const char *filename, int flags, const char *format_name) "bs %p filename \"%s\" flags 0x%x format_name \"%s\""
bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d"
-# blockjob.c
-block_job_completed(void *job, int ret, int jret) "job %p ret %d corrected ret %d"
-block_job_state_transition(void *job, int ret, const char *legal, const char *s0, const char *s1) "job %p (ret: %d) attempting %s transition (%s-->%s)"
-block_job_apply_verb(void *job, const char *state, const char *verb, const char *legal) "job %p in state %s; applying verb %s (%s)"
-
# block/block-backend.c
blk_co_preadv(void *blk, void *bs, int64_t offset, unsigned int bytes, int flags) "blk %p bs %p offset %"PRId64" bytes %u flags 0x%x"
blk_co_pwritev(void *blk, void *bs, int64_t offset, unsigned int bytes, int flags) "blk %p bs %p offset %"PRId64" bytes %u flags 0x%x"
diff --git a/block/vdi.c b/block/vdi.c
index 96a22b8e83..668af0a828 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -865,6 +865,7 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
}
}
+ ret = 0;
exit:
blk_unref(blk);
bdrv_unref(bs_file);
diff --git a/block/vhdx.c b/block/vhdx.c
index 79c68a2061..0831c5c5f4 100644
--- a/block/vhdx.c
+++ b/block/vhdx.c
@@ -1951,7 +1951,7 @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts,
goto delete_and_exit;
}
-
+ ret = 0;
delete_and_exit:
blk_unref(blk);
bdrv_unref(bs);
diff --git a/blockdev.c b/blockdev.c
index 3808b1fc00..8de95be8f4 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -150,7 +150,7 @@ void blockdev_mark_auto_del(BlockBackend *blk)
aio_context_acquire(aio_context);
if (bs->job) {
- block_job_cancel(bs->job, false);
+ job_cancel(&bs->job->job, false);
}
aio_context_release(aio_context);
@@ -1446,7 +1446,7 @@ typedef struct BlkActionOps {
struct BlkActionState {
TransactionAction *action;
const BlkActionOps *ops;
- BlockJobTxn *block_job_txn;
+ JobTxn *block_job_txn;
TransactionProperties *txn_props;
QSIMPLEQ_ENTRY(BlkActionState) entry;
};
@@ -1864,7 +1864,7 @@ typedef struct DriveBackupState {
BlockJob *job;
} DriveBackupState;
-static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn,
+static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
Error **errp);
static void drive_backup_prepare(BlkActionState *common, Error **errp)
@@ -1910,7 +1910,7 @@ static void drive_backup_commit(BlkActionState *common)
aio_context_acquire(aio_context);
assert(state->job);
- block_job_start(state->job);
+ job_start(&state->job->job);
aio_context_release(aio_context);
}
@@ -1925,7 +1925,7 @@ static void drive_backup_abort(BlkActionState *common)
aio_context = bdrv_get_aio_context(state->bs);
aio_context_acquire(aio_context);
- block_job_cancel_sync(state->job);
+ job_cancel_sync(&state->job->job);
aio_context_release(aio_context);
}
@@ -1954,7 +1954,7 @@ typedef struct BlockdevBackupState {
BlockJob *job;
} BlockdevBackupState;
-static BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn,
+static BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn,
Error **errp);
static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
@@ -2008,7 +2008,7 @@ static void blockdev_backup_commit(BlkActionState *common)
aio_context_acquire(aio_context);
assert(state->job);
- block_job_start(state->job);
+ job_start(&state->job->job);
aio_context_release(aio_context);
}
@@ -2023,7 +2023,7 @@ static void blockdev_backup_abort(BlkActionState *common)
aio_context = bdrv_get_aio_context(state->bs);
aio_context_acquire(aio_context);
- block_job_cancel_sync(state->job);
+ job_cancel_sync(&state->job->job);
aio_context_release(aio_context);
}
@@ -2243,7 +2243,7 @@ void qmp_transaction(TransactionActionList *dev_list,
Error **errp)
{
TransactionActionList *dev_entry = dev_list;
- BlockJobTxn *block_job_txn = NULL;
+ JobTxn *block_job_txn = NULL;
BlkActionState *state, *next;
Error *local_err = NULL;
@@ -2251,11 +2251,11 @@ void qmp_transaction(TransactionActionList *dev_list,
QSIMPLEQ_INIT(&snap_bdrv_states);
/* Does this transaction get canceled as a group on failure?
- * If not, we don't really need to make a BlockJobTxn.
+ * If not, we don't really need to make a JobTxn.
*/
props = get_transaction_properties(props);
if (props->completion_mode != ACTION_COMPLETION_MODE_INDIVIDUAL) {
- block_job_txn = block_job_txn_new();
+ block_job_txn = job_txn_new();
}
/* drain all i/o before any operations */
@@ -2314,7 +2314,7 @@ exit:
if (!has_props) {
qapi_free_TransactionProperties(props);
}
- block_job_txn_unref(block_job_txn);
+ job_txn_unref(block_job_txn);
}
void qmp_eject(bool has_device, const char *device,
@@ -3244,7 +3244,7 @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device,
goto out;
}
commit_active_start(has_job_id ? job_id : NULL, bs, base_bs,
- BLOCK_JOB_DEFAULT, speed, on_error,
+ JOB_DEFAULT, speed, on_error,
filter_node_name, NULL, NULL, false, &local_err);
} else {
BlockDriverState *overlay_bs = bdrv_find_overlay(bs, top_bs);
@@ -3264,7 +3264,7 @@ out:
aio_context_release(aio_context);
}
-static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn,
+static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
Error **errp)
{
BlockDriverState *bs;
@@ -3275,7 +3275,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn,
AioContext *aio_context;
QDict *options = NULL;
Error *local_err = NULL;
- int flags, job_flags = BLOCK_JOB_DEFAULT;
+ int flags, job_flags = JOB_DEFAULT;
int64_t size;
bool set_backing_hd = false;
@@ -3398,10 +3398,10 @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn,
}
}
if (!backup->auto_finalize) {
- job_flags |= BLOCK_JOB_MANUAL_FINALIZE;
+ job_flags |= JOB_MANUAL_FINALIZE;
}
if (!backup->auto_dismiss) {
- job_flags |= BLOCK_JOB_MANUAL_DISMISS;
+ job_flags |= JOB_MANUAL_DISMISS;
}
job = backup_job_create(backup->job_id, bs, target_bs, backup->speed,
@@ -3425,7 +3425,7 @@ void qmp_drive_backup(DriveBackup *arg, Error **errp)
BlockJob *job;
job = do_drive_backup(arg, NULL, errp);
if (job) {
- block_job_start(job);
+ job_start(&job->job);
}
}
@@ -3434,7 +3434,7 @@ BlockDeviceInfoList *qmp_query_named_block_nodes(Error **errp)
return bdrv_named_nodes_list(errp);
}
-BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn,
+BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn,
Error **errp)
{
BlockDriverState *bs;
@@ -3442,7 +3442,7 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn,
Error *local_err = NULL;
AioContext *aio_context;
BlockJob *job = NULL;
- int job_flags = BLOCK_JOB_DEFAULT;
+ int job_flags = JOB_DEFAULT;
if (!backup->has_speed) {
backup->speed = 0;
@@ -3491,10 +3491,10 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn,
}
}
if (!backup->auto_finalize) {
- job_flags |= BLOCK_JOB_MANUAL_FINALIZE;
+ job_flags |= JOB_MANUAL_FINALIZE;
}
if (!backup->auto_dismiss) {
- job_flags |= BLOCK_JOB_MANUAL_DISMISS;
+ job_flags |= JOB_MANUAL_DISMISS;
}
job = backup_job_create(backup->job_id, bs, target_bs, backup->speed,
backup->sync, NULL, backup->compress,
@@ -3513,7 +3513,7 @@ void qmp_blockdev_backup(BlockdevBackup *arg, Error **errp)
BlockJob *job;
job = do_blockdev_backup(arg, NULL, errp);
if (job) {
- block_job_start(job);
+ job_start(&job->job);
}
}
@@ -3844,14 +3844,14 @@ void qmp_block_job_cancel(const char *device,
force = false;
}
- if (block_job_user_paused(job) && !force) {
+ if (job_user_paused(&job->job) && !force) {
error_setg(errp, "The block job for device '%s' is currently paused",
device);
goto out;
}
trace_qmp_block_job_cancel(job);
- block_job_user_cancel(job, force, errp);
+ job_user_cancel(&job->job, force, errp);
out:
aio_context_release(aio_context);
}
@@ -3866,7 +3866,7 @@ void qmp_block_job_pause(const char *device, Error **errp)
}
trace_qmp_block_job_pause(job);
- block_job_user_pause(job, errp);
+ job_user_pause(&job->job, errp);
aio_context_release(aio_context);
}
@@ -3880,7 +3880,7 @@ void qmp_block_job_resume(const char *device, Error **errp)
}
trace_qmp_block_job_resume(job);
- block_job_user_resume(job, errp);
+ job_user_resume(&job->job, errp);
aio_context_release(aio_context);
}
@@ -3894,7 +3894,7 @@ void qmp_block_job_complete(const char *device, Error **errp)
}
trace_qmp_block_job_complete(job);
- block_job_complete(job, errp);
+ job_complete(&job->job, errp);
aio_context_release(aio_context);
}
@@ -3908,21 +3908,23 @@ void qmp_block_job_finalize(const char *id, Error **errp)
}
trace_qmp_block_job_finalize(job);
- block_job_finalize(job, errp);
+ job_finalize(&job->job, errp);
aio_context_release(aio_context);
}
void qmp_block_job_dismiss(const char *id, Error **errp)
{
AioContext *aio_context;
- BlockJob *job = find_block_job(id, &aio_context, errp);
+ BlockJob *bjob = find_block_job(id, &aio_context, errp);
+ Job *job;
- if (!job) {
+ if (!bjob) {
return;
}
- trace_qmp_block_job_dismiss(job);
- block_job_dismiss(&job, errp);
+ trace_qmp_block_job_dismiss(bjob);
+ job = &bjob->job;
+ job_dismiss(&job, errp);
aio_context_release(aio_context);
}
diff --git a/blockjob.c b/blockjob.c
index 112672a68b..0306533a2e 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -34,103 +34,8 @@
#include "qapi/qapi-events-block-core.h"
#include "qapi/qmp/qerror.h"
#include "qemu/coroutine.h"
-#include "qemu/id.h"
#include "qemu/timer.h"
-/* Right now, this mutex is only needed to synchronize accesses to job->busy
- * and job->sleep_timer, such as concurrent calls to block_job_do_yield and
- * block_job_enter. */
-static QemuMutex block_job_mutex;
-
-/* BlockJob State Transition Table */
-bool BlockJobSTT[BLOCK_JOB_STATUS__MAX][BLOCK_JOB_STATUS__MAX] = {
- /* U, C, R, P, Y, S, W, D, X, E, N */
- /* U: */ [BLOCK_JOB_STATUS_UNDEFINED] = {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- /* C: */ [BLOCK_JOB_STATUS_CREATED] = {0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1},
- /* R: */ [BLOCK_JOB_STATUS_RUNNING] = {0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0},
- /* P: */ [BLOCK_JOB_STATUS_PAUSED] = {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
- /* Y: */ [BLOCK_JOB_STATUS_READY] = {0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0},
- /* S: */ [BLOCK_JOB_STATUS_STANDBY] = {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
- /* W: */ [BLOCK_JOB_STATUS_WAITING] = {0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0},
- /* D: */ [BLOCK_JOB_STATUS_PENDING] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0},
- /* X: */ [BLOCK_JOB_STATUS_ABORTING] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0},
- /* E: */ [BLOCK_JOB_STATUS_CONCLUDED] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
- /* N: */ [BLOCK_JOB_STATUS_NULL] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
-};
-
-bool BlockJobVerbTable[BLOCK_JOB_VERB__MAX][BLOCK_JOB_STATUS__MAX] = {
- /* U, C, R, P, Y, S, W, D, X, E, N */
- [BLOCK_JOB_VERB_CANCEL] = {0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0},
- [BLOCK_JOB_VERB_PAUSE] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
- [BLOCK_JOB_VERB_RESUME] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
- [BLOCK_JOB_VERB_SET_SPEED] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
- [BLOCK_JOB_VERB_COMPLETE] = {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
- [BLOCK_JOB_VERB_FINALIZE] = {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0},
- [BLOCK_JOB_VERB_DISMISS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
-};
-
-static void block_job_state_transition(BlockJob *job, BlockJobStatus s1)
-{
- BlockJobStatus s0 = job->status;
- assert(s1 >= 0 && s1 <= BLOCK_JOB_STATUS__MAX);
- trace_block_job_state_transition(job, job->ret, BlockJobSTT[s0][s1] ?
- "allowed" : "disallowed",
- BlockJobStatus_str(s0),
- BlockJobStatus_str(s1));
- assert(BlockJobSTT[s0][s1]);
- job->status = s1;
-}
-
-static int block_job_apply_verb(BlockJob *job, BlockJobVerb bv, Error **errp)
-{
- assert(bv >= 0 && bv <= BLOCK_JOB_VERB__MAX);
- trace_block_job_apply_verb(job, BlockJobStatus_str(job->status),
- BlockJobVerb_str(bv),
- BlockJobVerbTable[bv][job->status] ?
- "allowed" : "prohibited");
- if (BlockJobVerbTable[bv][job->status]) {
- return 0;
- }
- error_setg(errp, "Job '%s' in state '%s' cannot accept command verb '%s'",
- job->id, BlockJobStatus_str(job->status), BlockJobVerb_str(bv));
- return -EPERM;
-}
-
-static void block_job_lock(void)
-{
- qemu_mutex_lock(&block_job_mutex);
-}
-
-static void block_job_unlock(void)
-{
- qemu_mutex_unlock(&block_job_mutex);
-}
-
-static void __attribute__((__constructor__)) block_job_init(void)
-{
- qemu_mutex_init(&block_job_mutex);
-}
-
-static void block_job_event_cancelled(BlockJob *job);
-static void block_job_event_completed(BlockJob *job, const char *msg);
-static int block_job_event_pending(BlockJob *job);
-static void block_job_enter_cond(BlockJob *job, bool(*fn)(BlockJob *job));
-
-/* Transactional group of block jobs */
-struct BlockJobTxn {
-
- /* Is this txn being cancelled? */
- bool aborting;
-
- /* List of jobs */
- QLIST_HEAD(, BlockJob) jobs;
-
- /* Reference count */
- int refcnt;
-};
-
-static QLIST_HEAD(, BlockJob) block_jobs = QLIST_HEAD_INITIALIZER(block_jobs);
-
/*
* The block job API is composed of two categories of functions.
*
@@ -146,147 +51,78 @@ static QLIST_HEAD(, BlockJob) block_jobs = QLIST_HEAD_INITIALIZER(block_jobs);
* blockjob_int.h.
*/
-BlockJob *block_job_next(BlockJob *job)
+static bool is_block_job(Job *job)
{
- if (!job) {
- return QLIST_FIRST(&block_jobs);
- }
- return QLIST_NEXT(job, job_list);
-}
-
-BlockJob *block_job_get(const char *id)
-{
- BlockJob *job;
-
- QLIST_FOREACH(job, &block_jobs, job_list) {
- if (job->id && !strcmp(id, job->id)) {
- return job;
- }
- }
-
- return NULL;
+ return job_type(job) == JOB_TYPE_BACKUP ||
+ job_type(job) == JOB_TYPE_COMMIT ||
+ job_type(job) == JOB_TYPE_MIRROR ||
+ job_type(job) == JOB_TYPE_STREAM;
}
-BlockJobTxn *block_job_txn_new(void)
+BlockJob *block_job_next(BlockJob *bjob)
{
- BlockJobTxn *txn = g_new0(BlockJobTxn, 1);
- QLIST_INIT(&txn->jobs);
- txn->refcnt = 1;
- return txn;
-}
-
-static void block_job_txn_ref(BlockJobTxn *txn)
-{
- txn->refcnt++;
-}
-
-void block_job_txn_unref(BlockJobTxn *txn)
-{
- if (txn && --txn->refcnt == 0) {
- g_free(txn);
- }
-}
-
-void block_job_txn_add_job(BlockJobTxn *txn, BlockJob *job)
-{
- if (!txn) {
- return;
- }
+ Job *job = bjob ? &bjob->job : NULL;
- assert(!job->txn);
- job->txn = txn;
+ do {
+ job = job_next(job);
+ } while (job && !is_block_job(job));
- QLIST_INSERT_HEAD(&txn->jobs, job, txn_list);
- block_job_txn_ref(txn);
+ return job ? container_of(job, BlockJob, job) : NULL;
}
-static void block_job_txn_del_job(BlockJob *job)
-{
- if (job->txn) {
- QLIST_REMOVE(job, txn_list);
- block_job_txn_unref(job->txn);
- job->txn = NULL;
- }
-}
-
-/* Assumes the block_job_mutex is held */
-static bool block_job_timer_pending(BlockJob *job)
-{
- return timer_pending(&job->sleep_timer);
-}
-
-/* Assumes the block_job_mutex is held */
-static bool block_job_timer_not_pending(BlockJob *job)
-{
- return !block_job_timer_pending(job);
-}
-
-static void block_job_pause(BlockJob *job)
+BlockJob *block_job_get(const char *id)
{
- job->pause_count++;
-}
+ Job *job = job_get(id);
-static void block_job_resume(BlockJob *job)
-{
- assert(job->pause_count > 0);
- job->pause_count--;
- if (job->pause_count) {
- return;
+ if (job && is_block_job(job)) {
+ return container_of(job, BlockJob, job);
+ } else {
+ return NULL;
}
-
- /* kick only if no timer is pending */
- block_job_enter_cond(job, block_job_timer_not_pending);
-}
-
-void block_job_ref(BlockJob *job)
-{
- ++job->refcnt;
}
static void block_job_attached_aio_context(AioContext *new_context,
void *opaque);
static void block_job_detach_aio_context(void *opaque);
-void block_job_unref(BlockJob *job)
+void block_job_free(Job *job)
{
- if (--job->refcnt == 0) {
- assert(job->status == BLOCK_JOB_STATUS_NULL);
- assert(!job->txn);
- BlockDriverState *bs = blk_bs(job->blk);
- QLIST_REMOVE(job, job_list);
- bs->job = NULL;
- block_job_remove_all_bdrv(job);
- blk_remove_aio_context_notifier(job->blk,
- block_job_attached_aio_context,
- block_job_detach_aio_context, job);
- blk_unref(job->blk);
- error_free(job->blocker);
- g_free(job->id);
- assert(!timer_pending(&job->sleep_timer));
- g_free(job);
- }
+ BlockJob *bjob = container_of(job, BlockJob, job);
+ BlockDriverState *bs = blk_bs(bjob->blk);
+
+ bs->job = NULL;
+ block_job_remove_all_bdrv(bjob);
+ blk_remove_aio_context_notifier(bjob->blk,
+ block_job_attached_aio_context,
+ block_job_detach_aio_context, bjob);
+ blk_unref(bjob->blk);
+ error_free(bjob->blocker);
}
static void block_job_attached_aio_context(AioContext *new_context,
void *opaque)
{
BlockJob *job = opaque;
+ const JobDriver *drv = job->job.driver;
+ BlockJobDriver *bjdrv = container_of(drv, BlockJobDriver, job_driver);
- if (job->driver->attached_aio_context) {
- job->driver->attached_aio_context(job, new_context);
+ job->job.aio_context = new_context;
+ if (bjdrv->attached_aio_context) {
+ bjdrv->attached_aio_context(job, new_context);
}
- block_job_resume(job);
+ job_resume(&job->job);
}
-static void block_job_drain(BlockJob *job)
+void block_job_drain(Job *job)
{
- /* If job is !job->busy this kicks it into the next pause point. */
- block_job_enter(job);
+ BlockJob *bjob = container_of(job, BlockJob, job);
+ const JobDriver *drv = job->driver;
+ BlockJobDriver *bjdrv = container_of(drv, BlockJobDriver, job_driver);
- blk_drain(job->blk);
- if (job->driver->drain) {
- job->driver->drain(job);
+ blk_drain(bjob->blk);
+ if (bjdrv->drain) {
+ bjdrv->drain(bjob);
}
}
@@ -295,35 +131,34 @@ static void block_job_detach_aio_context(void *opaque)
BlockJob *job = opaque;
/* In case the job terminates during aio_poll()... */
- block_job_ref(job);
+ job_ref(&job->job);
- block_job_pause(job);
+ job_pause(&job->job);
- while (!job->paused && !job->completed) {
- block_job_drain(job);
+ while (!job->job.paused && !job_is_completed(&job->job)) {
+ job_drain(&job->job);
}
- block_job_unref(job);
+ job->job.aio_context = NULL;
+ job_unref(&job->job);
}
static char *child_job_get_parent_desc(BdrvChild *c)
{
BlockJob *job = c->opaque;
- return g_strdup_printf("%s job '%s'",
- BlockJobType_str(job->driver->job_type),
- job->id);
+ return g_strdup_printf("%s job '%s'", job_type_str(&job->job), job->job.id);
}
static void child_job_drained_begin(BdrvChild *c)
{
BlockJob *job = c->opaque;
- block_job_pause(job);
+ job_pause(&job->job);
}
static void child_job_drained_end(BdrvChild *c)
{
BlockJob *job = c->opaque;
- block_job_resume(job);
+ job_resume(&job->job);
}
static const BdrvChildRole child_job = {
@@ -365,316 +200,25 @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs,
bool block_job_is_internal(BlockJob *job)
{
- return (job->id == NULL);
-}
-
-static bool block_job_started(BlockJob *job)
-{
- return job->co;
+ return (job->job.id == NULL);
}
const BlockJobDriver *block_job_driver(BlockJob *job)
{
- return job->driver;
-}
-
-/**
- * All jobs must allow a pause point before entering their job proper. This
- * ensures that jobs can be paused prior to being started, then resumed later.
- */
-static void coroutine_fn block_job_co_entry(void *opaque)
-{
- BlockJob *job = opaque;
-
- assert(job && job->driver && job->driver->start);
- block_job_pause_point(job);
- job->driver->start(job);
-}
-
-static void block_job_sleep_timer_cb(void *opaque)
-{
- BlockJob *job = opaque;
-
- block_job_enter(job);
-}
-
-void block_job_start(BlockJob *job)
-{
- assert(job && !block_job_started(job) && job->paused &&
- job->driver && job->driver->start);
- job->co = qemu_coroutine_create(block_job_co_entry, job);
- job->pause_count--;
- job->busy = true;
- job->paused = false;
- block_job_state_transition(job, BLOCK_JOB_STATUS_RUNNING);
- bdrv_coroutine_enter(blk_bs(job->blk), job->co);
-}
-
-static void block_job_decommission(BlockJob *job)
-{
- assert(job);
- job->completed = true;
- job->busy = false;
- job->paused = false;
- job->deferred_to_main_loop = true;
- block_job_txn_del_job(job);
- block_job_state_transition(job, BLOCK_JOB_STATUS_NULL);
- block_job_unref(job);
+ return container_of(job->job.driver, BlockJobDriver, job_driver);
}
-static void block_job_do_dismiss(BlockJob *job)
+/* Assumes the job_mutex is held */
+static bool job_timer_pending(Job *job)
{
- block_job_decommission(job);
-}
-
-static void block_job_conclude(BlockJob *job)
-{
- block_job_state_transition(job, BLOCK_JOB_STATUS_CONCLUDED);
- if (job->auto_dismiss || !block_job_started(job)) {
- block_job_do_dismiss(job);
- }
-}
-
-static void block_job_update_rc(BlockJob *job)
-{
- if (!job->ret && block_job_is_cancelled(job)) {
- job->ret = -ECANCELED;
- }
- if (job->ret) {
- block_job_state_transition(job, BLOCK_JOB_STATUS_ABORTING);
- }
-}
-
-static int block_job_prepare(BlockJob *job)
-{
- if (job->ret == 0 && job->driver->prepare) {
- job->ret = job->driver->prepare(job);
- }
- return job->ret;
-}
-
-static void block_job_commit(BlockJob *job)
-{
- assert(!job->ret);
- if (job->driver->commit) {
- job->driver->commit(job);
- }
-}
-
-static void block_job_abort(BlockJob *job)
-{
- assert(job->ret);
- if (job->driver->abort) {
- job->driver->abort(job);
- }
-}
-
-static void block_job_clean(BlockJob *job)
-{
- if (job->driver->clean) {
- job->driver->clean(job);
- }
-}
-
-static int block_job_finalize_single(BlockJob *job)
-{
- assert(job->completed);
-
- /* Ensure abort is called for late-transactional failures */
- block_job_update_rc(job);
-
- if (!job->ret) {
- block_job_commit(job);
- } else {
- block_job_abort(job);
- }
- block_job_clean(job);
-
- if (job->cb) {
- job->cb(job->opaque, job->ret);
- }
-
- /* Emit events only if we actually started */
- if (block_job_started(job)) {
- if (block_job_is_cancelled(job)) {
- block_job_event_cancelled(job);
- } else {
- const char *msg = NULL;
- if (job->ret < 0) {
- msg = strerror(-job->ret);
- }
- block_job_event_completed(job, msg);
- }
- }
-
- block_job_txn_del_job(job);
- block_job_conclude(job);
- return 0;
-}
-
-static void block_job_cancel_async(BlockJob *job, bool force)
-{
- if (job->iostatus != BLOCK_DEVICE_IO_STATUS_OK) {
- block_job_iostatus_reset(job);
- }
- if (job->user_paused) {
- /* Do not call block_job_enter here, the caller will handle it. */
- job->user_paused = false;
- job->pause_count--;
- }
- job->cancelled = true;
- /* To prevent 'force == false' overriding a previous 'force == true' */
- job->force |= force;
-}
-
-static int block_job_txn_apply(BlockJobTxn *txn, int fn(BlockJob *), bool lock)
-{
- AioContext *ctx;
- BlockJob *job, *next;
- int rc = 0;
-
- QLIST_FOREACH_SAFE(job, &txn->jobs, txn_list, next) {
- if (lock) {
- ctx = blk_get_aio_context(job->blk);
- aio_context_acquire(ctx);
- }
- rc = fn(job);
- if (lock) {
- aio_context_release(ctx);
- }
- if (rc) {
- break;
- }
- }
- return rc;
-}
-
-static int block_job_finish_sync(BlockJob *job,
- void (*finish)(BlockJob *, Error **errp),
- Error **errp)
-{
- Error *local_err = NULL;
- int ret;
-
- assert(blk_bs(job->blk)->job == job);
-
- block_job_ref(job);
-
- if (finish) {
- finish(job, &local_err);
- }
- if (local_err) {
- error_propagate(errp, local_err);
- block_job_unref(job);
- return -EBUSY;
- }
- /* block_job_drain calls block_job_enter, and it should be enough to
- * induce progress until the job completes or moves to the main thread.
- */
- while (!job->deferred_to_main_loop && !job->completed) {
- block_job_drain(job);
- }
- while (!job->completed) {
- aio_poll(qemu_get_aio_context(), true);
- }
- ret = (job->cancelled && job->ret == 0) ? -ECANCELED : job->ret;
- block_job_unref(job);
- return ret;
-}
-
-static void block_job_completed_txn_abort(BlockJob *job)
-{
- AioContext *ctx;
- BlockJobTxn *txn = job->txn;
- BlockJob *other_job;
-
- if (txn->aborting) {
- /*
- * We are cancelled by another job, which will handle everything.
- */
- return;
- }
- txn->aborting = true;
- block_job_txn_ref(txn);
-
- /* We are the first failed job. Cancel other jobs. */
- QLIST_FOREACH(other_job, &txn->jobs, txn_list) {
- ctx = blk_get_aio_context(other_job->blk);
- aio_context_acquire(ctx);
- }
-
- /* Other jobs are effectively cancelled by us, set the status for
- * them; this job, however, may or may not be cancelled, depending
- * on the caller, so leave it. */
- QLIST_FOREACH(other_job, &txn->jobs, txn_list) {
- if (other_job != job) {
- block_job_cancel_async(other_job, false);
- }
- }
- while (!QLIST_EMPTY(&txn->jobs)) {
- other_job = QLIST_FIRST(&txn->jobs);
- ctx = blk_get_aio_context(other_job->blk);
- if (!other_job->completed) {
- assert(other_job->cancelled);
- block_job_finish_sync(other_job, NULL, NULL);
- }
- block_job_finalize_single(other_job);
- aio_context_release(ctx);
- }
-
- block_job_txn_unref(txn);
-}
-
-static int block_job_needs_finalize(BlockJob *job)
-{
- return !job->auto_finalize;
-}
-
-static void block_job_do_finalize(BlockJob *job)
-{
- int rc;
- assert(job && job->txn);
-
- /* prepare the transaction to complete */
- rc = block_job_txn_apply(job->txn, block_job_prepare, true);
- if (rc) {
- block_job_completed_txn_abort(job);
- } else {
- block_job_txn_apply(job->txn, block_job_finalize_single, true);
- }
-}
-
-static void block_job_completed_txn_success(BlockJob *job)
-{
- BlockJobTxn *txn = job->txn;
- BlockJob *other_job;
-
- block_job_state_transition(job, BLOCK_JOB_STATUS_WAITING);
-
- /*
- * Successful completion, see if there are other running jobs in this
- * txn.
- */
- QLIST_FOREACH(other_job, &txn->jobs, txn_list) {
- if (!other_job->completed) {
- return;
- }
- assert(other_job->ret == 0);
- }
-
- block_job_txn_apply(txn, block_job_event_pending, false);
-
- /* If no jobs need manual finalization, automatically do so */
- if (block_job_txn_apply(txn, block_job_needs_finalize, false) == 0) {
- block_job_do_finalize(job);
- }
+ return timer_pending(&job->sleep_timer);
}
void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
{
int64_t old_speed = job->speed;
- if (block_job_apply_verb(job, BLOCK_JOB_VERB_SET_SPEED, errp)) {
+ if (job_apply_verb(&job->job, JOB_VERB_SET_SPEED, errp)) {
return;
}
if (speed < 0) {
@@ -690,7 +234,7 @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
}
/* kick only if a timer is pending */
- block_job_enter_cond(job, block_job_timer_pending);
+ job_enter_cond(&job->job, job_timer_pending);
}
int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n)
@@ -702,142 +246,6 @@ int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n)
return ratelimit_calculate_delay(&job->limit, n);
}
-void block_job_complete(BlockJob *job, Error **errp)
-{
- /* Should not be reachable via external interface for internal jobs */
- assert(job->id);
- if (block_job_apply_verb(job, BLOCK_JOB_VERB_COMPLETE, errp)) {
- return;
- }
- if (job->pause_count || job->cancelled || !job->driver->complete) {
- error_setg(errp, "The active block job '%s' cannot be completed",
- job->id);
- return;
- }
-
- job->driver->complete(job, errp);
-}
-
-void block_job_finalize(BlockJob *job, Error **errp)
-{
- assert(job && job->id);
- if (block_job_apply_verb(job, BLOCK_JOB_VERB_FINALIZE, errp)) {
- return;
- }
- block_job_do_finalize(job);
-}
-
-void block_job_dismiss(BlockJob **jobptr, Error **errp)
-{
- BlockJob *job = *jobptr;
- /* similarly to _complete, this is QMP-interface only. */
- assert(job->id);
- if (block_job_apply_verb(job, BLOCK_JOB_VERB_DISMISS, errp)) {
- return;
- }
-
- block_job_do_dismiss(job);
- *jobptr = NULL;
-}
-
-void block_job_user_pause(BlockJob *job, Error **errp)
-{
- if (block_job_apply_verb(job, BLOCK_JOB_VERB_PAUSE, errp)) {
- return;
- }
- if (job->user_paused) {
- error_setg(errp, "Job is already paused");
- return;
- }
- job->user_paused = true;
- block_job_pause(job);
-}
-
-bool block_job_user_paused(BlockJob *job)
-{
- return job->user_paused;
-}
-
-void block_job_user_resume(BlockJob *job, Error **errp)
-{
- assert(job);
- if (!job->user_paused || job->pause_count <= 0) {
- error_setg(errp, "Can't resume a job that was not paused");
- return;
- }
- if (block_job_apply_verb(job, BLOCK_JOB_VERB_RESUME, errp)) {
- return;
- }
- block_job_iostatus_reset(job);
- job->user_paused = false;
- block_job_resume(job);
-}
-
-void block_job_cancel(BlockJob *job, bool force)
-{
- if (job->status == BLOCK_JOB_STATUS_CONCLUDED) {
- block_job_do_dismiss(job);
- return;
- }
- block_job_cancel_async(job, force);
- if (!block_job_started(job)) {
- block_job_completed(job, -ECANCELED);
- } else if (job->deferred_to_main_loop) {
- block_job_completed_txn_abort(job);
- } else {
- block_job_enter(job);
- }
-}
-
-void block_job_user_cancel(BlockJob *job, bool force, Error **errp)
-{
- if (block_job_apply_verb(job, BLOCK_JOB_VERB_CANCEL, errp)) {
- return;
- }
- block_job_cancel(job, force);
-}
-
-/* A wrapper around block_job_cancel() taking an Error ** parameter so it may be
- * used with block_job_finish_sync() without the need for (rather nasty)
- * function pointer casts there. */
-static void block_job_cancel_err(BlockJob *job, Error **errp)
-{
- block_job_cancel(job, false);
-}
-
-int block_job_cancel_sync(BlockJob *job)
-{
- return block_job_finish_sync(job, &block_job_cancel_err, NULL);
-}
-
-void block_job_cancel_sync_all(void)
-{
- BlockJob *job;
- AioContext *aio_context;
-
- while ((job = QLIST_FIRST(&block_jobs))) {
- aio_context = blk_get_aio_context(job->blk);
- aio_context_acquire(aio_context);
- block_job_cancel_sync(job);
- aio_context_release(aio_context);
- }
-}
-
-int block_job_complete_sync(BlockJob *job, Error **errp)
-{
- return block_job_finish_sync(job, &block_job_complete, errp);
-}
-
-void block_job_progress_update(BlockJob *job, uint64_t done)
-{
- job->offset += done;
-}
-
-void block_job_progress_set_remaining(BlockJob *job, uint64_t remaining)
-{
- job->len = job->offset + remaining;
-}
-
BlockJobInfo *block_job_query(BlockJob *job, Error **errp)
{
BlockJobInfo *info;
@@ -847,20 +255,20 @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp)
return NULL;
}
info = g_new0(BlockJobInfo, 1);
- info->type = g_strdup(BlockJobType_str(job->driver->job_type));
- info->device = g_strdup(job->id);
- info->len = job->len;
- info->busy = atomic_read(&job->busy);
- info->paused = job->pause_count > 0;
- info->offset = job->offset;
+ info->type = g_strdup(job_type_str(&job->job));
+ info->device = g_strdup(job->job.id);
+ info->busy = atomic_read(&job->job.busy);
+ info->paused = job->job.pause_count > 0;
+ info->offset = job->job.progress_current;
+ info->len = job->job.progress_total;
info->speed = job->speed;
info->io_status = job->iostatus;
- info->ready = job->ready;
- info->status = job->status;
- info->auto_finalize = job->auto_finalize;
- info->auto_dismiss = job->auto_dismiss;
- info->has_error = job->ret != 0;
- info->error = job->ret ? g_strdup(strerror(-job->ret)) : NULL;
+ info->ready = job_is_ready(&job->job),
+ info->status = job->job.status;
+ info->auto_finalize = job->job.auto_finalize;
+ info->auto_dismiss = job->job.auto_dismiss;
+ info->has_error = job->job.ret != 0;
+ info->error = job->job.ret ? g_strdup(strerror(-job->job.ret)) : NULL;
return info;
}
@@ -872,54 +280,81 @@ static void block_job_iostatus_set_err(BlockJob *job, int error)
}
}
-static void block_job_event_cancelled(BlockJob *job)
+static void block_job_event_cancelled(Notifier *n, void *opaque)
{
+ BlockJob *job = opaque;
+
if (block_job_is_internal(job)) {
return;
}
- qapi_event_send_block_job_cancelled(job->driver->job_type,
- job->id,
- job->len,
- job->offset,
+ qapi_event_send_block_job_cancelled(job_type(&job->job),
+ job->job.id,
+ job->job.progress_total,
+ job->job.progress_current,
job->speed,
&error_abort);
}
-static void block_job_event_completed(BlockJob *job, const char *msg)
+static void block_job_event_completed(Notifier *n, void *opaque)
{
+ BlockJob *job = opaque;
+ const char *msg = NULL;
+
if (block_job_is_internal(job)) {
return;
}
- qapi_event_send_block_job_completed(job->driver->job_type,
- job->id,
- job->len,
- job->offset,
+ if (job->job.ret < 0) {
+ msg = strerror(-job->job.ret);
+ }
+
+ qapi_event_send_block_job_completed(job_type(&job->job),
+ job->job.id,
+ job->job.progress_total,
+ job->job.progress_current,
job->speed,
!!msg,
msg,
&error_abort);
}
-static int block_job_event_pending(BlockJob *job)
+static void block_job_event_pending(Notifier *n, void *opaque)
{
- block_job_state_transition(job, BLOCK_JOB_STATUS_PENDING);
- if (!job->auto_finalize && !block_job_is_internal(job)) {
- qapi_event_send_block_job_pending(job->driver->job_type,
- job->id,
- &error_abort);
+ BlockJob *job = opaque;
+
+ if (block_job_is_internal(job)) {
+ return;
}
- return 0;
+
+ qapi_event_send_block_job_pending(job_type(&job->job),
+ job->job.id,
+ &error_abort);
}
+static void block_job_event_ready(Notifier *n, void *opaque)
+{
+ BlockJob *job = opaque;
+
+ if (block_job_is_internal(job)) {
+ return;
+ }
+
+ qapi_event_send_block_job_ready(job_type(&job->job),
+ job->job.id,
+ job->job.progress_total,
+ job->job.progress_current,
+ job->speed, &error_abort);
+}
+
+
/*
* API for block job drivers and the block layer. These functions are
* declared in blockjob_int.h.
*/
void *block_job_create(const char *job_id, const BlockJobDriver *driver,
- BlockJobTxn *txn, BlockDriverState *bs, uint64_t perm,
+ JobTxn *txn, BlockDriverState *bs, uint64_t perm,
uint64_t shared_perm, int64_t speed, int flags,
BlockCompletionFunc *cb, void *opaque, Error **errp)
{
@@ -932,29 +367,8 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
return NULL;
}
- if (job_id == NULL && !(flags & BLOCK_JOB_INTERNAL)) {
+ if (job_id == NULL && !(flags & JOB_INTERNAL)) {
job_id = bdrv_get_device_name(bs);
- if (!*job_id) {
- error_setg(errp, "An explicit job ID is required for this node");
- return NULL;
- }
- }
-
- if (job_id) {
- if (flags & BLOCK_JOB_INTERNAL) {
- error_setg(errp, "Cannot specify job ID for internal block job");
- return NULL;
- }
-
- if (!id_wellformed(job_id)) {
- error_setg(errp, "Invalid job ID '%s'", job_id);
- return NULL;
- }
-
- if (block_job_get(job_id)) {
- error_setg(errp, "Job ID '%s' already in use", job_id);
- return NULL;
- }
}
blk = blk_new(perm, shared_perm);
@@ -964,32 +378,39 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
return NULL;
}
- job = g_malloc0(driver->instance_size);
- job->driver = driver;
- job->id = g_strdup(job_id);
- job->blk = blk;
- job->cb = cb;
- job->opaque = opaque;
- job->busy = false;
- job->paused = true;
- job->pause_count = 1;
- job->refcnt = 1;
- job->auto_finalize = !(flags & BLOCK_JOB_MANUAL_FINALIZE);
- job->auto_dismiss = !(flags & BLOCK_JOB_MANUAL_DISMISS);
- block_job_state_transition(job, BLOCK_JOB_STATUS_CREATED);
- aio_timer_init(qemu_get_aio_context(), &job->sleep_timer,
- QEMU_CLOCK_REALTIME, SCALE_NS,
- block_job_sleep_timer_cb, job);
+ job = job_create(job_id, &driver->job_driver, txn, blk_get_aio_context(blk),
+ flags, cb, opaque, errp);
+ if (job == NULL) {
+ blk_unref(blk);
+ return NULL;
+ }
+
+ assert(is_block_job(&job->job));
+ assert(job->job.driver->free == &block_job_free);
+ assert(job->job.driver->user_resume == &block_job_user_resume);
+ assert(job->job.driver->drain == &block_job_drain);
+
+ job->blk = blk;
+
+ job->finalize_cancelled_notifier.notify = block_job_event_cancelled;
+ job->finalize_completed_notifier.notify = block_job_event_completed;
+ job->pending_notifier.notify = block_job_event_pending;
+ job->ready_notifier.notify = block_job_event_ready;
+
+ notifier_list_add(&job->job.on_finalize_cancelled,
+ &job->finalize_cancelled_notifier);
+ notifier_list_add(&job->job.on_finalize_completed,
+ &job->finalize_completed_notifier);
+ notifier_list_add(&job->job.on_pending, &job->pending_notifier);
+ notifier_list_add(&job->job.on_ready, &job->ready_notifier);
error_setg(&job->blocker, "block device is in use by block job: %s",
- BlockJobType_str(driver->job_type));
+ job_type_str(&job->job));
block_job_add_bdrv(job, "main node", bs, 0, BLK_PERM_ALL, &error_abort);
bs->job = job;
bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker);
- QLIST_INSERT_HEAD(&block_jobs, job, job_list);
-
blk_add_aio_context_notifier(blk, block_job_attached_aio_context,
block_job_detach_aio_context, job);
@@ -999,198 +420,28 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
block_job_set_speed(job, speed, &local_err);
if (local_err) {
- block_job_early_fail(job);
+ job_early_fail(&job->job);
error_propagate(errp, local_err);
return NULL;
}
}
- /* Single jobs are modeled as single-job transactions for sake of
- * consolidating the job management logic */
- if (!txn) {
- txn = block_job_txn_new();
- block_job_txn_add_job(txn, job);
- block_job_txn_unref(txn);
- } else {
- block_job_txn_add_job(txn, job);
- }
-
return job;
}
-void block_job_early_fail(BlockJob *job)
-{
- assert(job->status == BLOCK_JOB_STATUS_CREATED);
- block_job_decommission(job);
-}
-
-void block_job_completed(BlockJob *job, int ret)
-{
- assert(job && job->txn && !job->completed);
- assert(blk_bs(job->blk)->job == job);
- job->completed = true;
- job->ret = ret;
- block_job_update_rc(job);
- trace_block_job_completed(job, ret, job->ret);
- if (job->ret) {
- block_job_completed_txn_abort(job);
- } else {
- block_job_completed_txn_success(job);
- }
-}
-
-static bool block_job_should_pause(BlockJob *job)
-{
- return job->pause_count > 0;
-}
-
-/* Yield, and schedule a timer to reenter the coroutine after @ns nanoseconds.
- * Reentering the job coroutine with block_job_enter() before the timer has
- * expired is allowed and cancels the timer.
- *
- * If @ns is (uint64_t) -1, no timer is scheduled and block_job_enter() must be
- * called explicitly. */
-static void block_job_do_yield(BlockJob *job, uint64_t ns)
-{
- block_job_lock();
- if (ns != -1) {
- timer_mod(&job->sleep_timer, ns);
- }
- job->busy = false;
- block_job_unlock();
- qemu_coroutine_yield();
-
- /* Set by block_job_enter before re-entering the coroutine. */
- assert(job->busy);
-}
-
-void coroutine_fn block_job_pause_point(BlockJob *job)
-{
- assert(job && block_job_started(job));
-
- if (!block_job_should_pause(job)) {
- return;
- }
- if (block_job_is_cancelled(job)) {
- return;
- }
-
- if (job->driver->pause) {
- job->driver->pause(job);
- }
-
- if (block_job_should_pause(job) && !block_job_is_cancelled(job)) {
- BlockJobStatus status = job->status;
- block_job_state_transition(job, status == BLOCK_JOB_STATUS_READY ? \
- BLOCK_JOB_STATUS_STANDBY : \
- BLOCK_JOB_STATUS_PAUSED);
- job->paused = true;
- block_job_do_yield(job, -1);
- job->paused = false;
- block_job_state_transition(job, status);
- }
-
- if (job->driver->resume) {
- job->driver->resume(job);
- }
-}
-
-/*
- * Conditionally enter a block_job pending a call to fn() while
- * under the block_job_lock critical section.
- */
-static void block_job_enter_cond(BlockJob *job, bool(*fn)(BlockJob *job))
-{
- if (!block_job_started(job)) {
- return;
- }
- if (job->deferred_to_main_loop) {
- return;
- }
-
- block_job_lock();
- if (job->busy) {
- block_job_unlock();
- return;
- }
-
- if (fn && !fn(job)) {
- block_job_unlock();
- return;
- }
-
- assert(!job->deferred_to_main_loop);
- timer_del(&job->sleep_timer);
- job->busy = true;
- block_job_unlock();
- aio_co_wake(job->co);
-}
-
-void block_job_enter(BlockJob *job)
-{
- block_job_enter_cond(job, NULL);
-}
-
-bool block_job_is_cancelled(BlockJob *job)
-{
- return job->cancelled;
-}
-
-void block_job_sleep_ns(BlockJob *job, int64_t ns)
-{
- assert(job->busy);
-
- /* Check cancellation *before* setting busy = false, too! */
- if (block_job_is_cancelled(job)) {
- return;
- }
-
- if (!block_job_should_pause(job)) {
- block_job_do_yield(job, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + ns);
- }
-
- block_job_pause_point(job);
-}
-
-void block_job_yield(BlockJob *job)
-{
- assert(job->busy);
-
- /* Check cancellation *before* setting busy = false, too! */
- if (block_job_is_cancelled(job)) {
- return;
- }
-
- if (!block_job_should_pause(job)) {
- block_job_do_yield(job, -1);
- }
-
- block_job_pause_point(job);
-}
-
void block_job_iostatus_reset(BlockJob *job)
{
if (job->iostatus == BLOCK_DEVICE_IO_STATUS_OK) {
return;
}
- assert(job->user_paused && job->pause_count > 0);
+ assert(job->job.user_paused && job->job.pause_count > 0);
job->iostatus = BLOCK_DEVICE_IO_STATUS_OK;
}
-void block_job_event_ready(BlockJob *job)
+void block_job_user_resume(Job *job)
{
- block_job_state_transition(job, BLOCK_JOB_STATUS_READY);
- job->ready = true;
-
- if (block_job_is_internal(job)) {
- return;
- }
-
- qapi_event_send_block_job_ready(job->driver->job_type,
- job->id,
- job->len,
- job->offset,
- job->speed, &error_abort);
+ BlockJob *bjob = container_of(job, BlockJob, job);
+ block_job_iostatus_reset(bjob);
}
BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err,
@@ -1217,63 +468,16 @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err,
abort();
}
if (!block_job_is_internal(job)) {
- qapi_event_send_block_job_error(job->id,
+ qapi_event_send_block_job_error(job->job.id,
is_read ? IO_OPERATION_TYPE_READ :
IO_OPERATION_TYPE_WRITE,
action, &error_abort);
}
if (action == BLOCK_ERROR_ACTION_STOP) {
- block_job_pause(job);
+ job_pause(&job->job);
/* make the pause user visible, which will be resumed from QMP. */
- job->user_paused = true;
+ job->job.user_paused = true;
block_job_iostatus_set_err(job, error);
}
return action;
}
-
-typedef struct {
- BlockJob *job;
- AioContext *aio_context;
- BlockJobDeferToMainLoopFn *fn;
- void *opaque;
-} BlockJobDeferToMainLoopData;
-
-static void block_job_defer_to_main_loop_bh(void *opaque)
-{
- BlockJobDeferToMainLoopData *data = opaque;
- AioContext *aio_context;
-
- /* Prevent race with block_job_defer_to_main_loop() */
- aio_context_acquire(data->aio_context);
-
- /* Fetch BDS AioContext again, in case it has changed */
- aio_context = blk_get_aio_context(data->job->blk);
- if (aio_context != data->aio_context) {
- aio_context_acquire(aio_context);
- }
-
- data->fn(data->job, data->opaque);
-
- if (aio_context != data->aio_context) {
- aio_context_release(aio_context);
- }
-
- aio_context_release(data->aio_context);
-
- g_free(data);
-}
-
-void block_job_defer_to_main_loop(BlockJob *job,
- BlockJobDeferToMainLoopFn *fn,
- void *opaque)
-{
- BlockJobDeferToMainLoopData *data = g_malloc(sizeof(*data));
- data->job = job;
- data->aio_context = blk_get_aio_context(job->blk);
- data->fn = fn;
- data->opaque = opaque;
- job->deferred_to_main_loop = true;
-
- aio_bh_schedule_oneshot(qemu_get_aio_context(),
- block_job_defer_to_main_loop_bh, data);
-}
diff --git a/bsd-user/main.c b/bsd-user/main.c
index 283dc6fd25..da3b833975 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -898,9 +898,10 @@ int main(int argc, char **argv)
cpu_model = "any";
#endif
}
+
+ /* init tcg before creating CPUs and to get qemu_host_page_size */
tcg_exec_init(0);
- /* NOTE: we need to init the CPU at this stage to get
- qemu_host_page_size */
+
cpu_type = parse_cpu_model(cpu_model);
cpu = cpu_create(cpu_type);
env = cpu->env_ptr;
@@ -917,7 +918,7 @@ int main(int argc, char **argv)
envlist_free(envlist);
/*
- * Now that page sizes are configured in cpu_init() we can do
+ * Now that page sizes are configured in tcg_exec_init() we can do
* proper page alignment for guest_base.
*/
guest_base = HOST_PAGE_ALIGN(guest_base);
diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c
index 20cd29d145..17f4cd80aa 100644
--- a/bsd-user/mmap.c
+++ b/bsd-user/mmap.c
@@ -21,6 +21,7 @@
#include "qemu.h"
#include "qemu-common.h"
#include "bsd-mman.h"
+#include "exec/exec-all.h"
//#define DEBUG_MMAP
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index 19b2b8fecb..09e8aed9c7 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -19,7 +19,6 @@
#include "cpu.h"
-#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
#undef DEBUG_REMAP
diff --git a/chardev/char-mux.c b/chardev/char-mux.c
index 1b925c8dec..6055e76293 100644
--- a/chardev/char-mux.c
+++ b/chardev/char-mux.c
@@ -304,6 +304,7 @@ void mux_set_focus(Chardev *chr, int focus)
}
d->focus = focus;
+ chr->be = d->backends[focus];
mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN);
}
diff --git a/chardev/char-serial.c b/chardev/char-serial.c
index feb52e559d..ae548d28da 100644
--- a/chardev/char-serial.c
+++ b/chardev/char-serial.c
@@ -139,7 +139,7 @@ static void tty_serial_init(int fd, int speed,
tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
| INLCR | IGNCR | ICRNL | IXON);
- tty.c_oflag |= OPOST;
+ tty.c_oflag &= ~OPOST;
tty.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);
tty.c_cflag &= ~(CSIZE | PARENB | PARODD | CRTSCTS | CSTOPB);
switch (data_bits) {
diff --git a/chardev/char-stdio.c b/chardev/char-stdio.c
index 96375f2ab8..d83e60e787 100644
--- a/chardev/char-stdio.c
+++ b/chardev/char-stdio.c
@@ -59,7 +59,7 @@ static void qemu_chr_set_echo_stdio(Chardev *chr, bool echo)
if (!echo) {
tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
| INLCR | IGNCR | ICRNL | IXON);
- tty.c_oflag |= OPOST;
+ tty.c_oflag &= ~OPOST;
tty.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN);
tty.c_cflag &= ~(CSIZE | PARENB);
tty.c_cflag |= CS8;
diff --git a/configure b/configure
index 59f91ab3f9..a71bf9b00b 100755
--- a/configure
+++ b/configure
@@ -1588,7 +1588,7 @@ disabled with --disable-FEATURE, default is enabled if available:
virtfs VirtFS
mpath Multipath persistent reservation passthrough
xen xen backend driver support
- xen-pci-passthrough
+ xen-pci-passthrough PCI passthrough support for Xen
brlapi BrlAPI (Braile)
curl curl connectivity
membarrier membarrier system call (for Linux 4.14+ or Windows)
@@ -2231,12 +2231,17 @@ EOF
#undef XC_WANT_COMPAT_DEVICEMODEL_API
#define __XEN_TOOLS__
#include <xendevicemodel.h>
+#include <xenforeignmemory.h>
int main(void) {
xendevicemodel_handle *xd;
+ xenforeignmemory_handle *xfmem;
xd = xendevicemodel_open(0, 0);
xendevicemodel_pin_memory_cacheattr(xd, 0, 0, 0, 0);
+ xfmem = xenforeignmemory_open(0, 0);
+ xenforeignmemory_map_resource(xfmem, 0, 0, 0, 0, 0, NULL, 0, 0);
+
return 0;
}
EOF
@@ -2524,20 +2529,7 @@ fi
##########################################
# Windows Hypervisor Platform accelerator (WHPX) check
if test "$whpx" != "no" ; then
- cat > $TMPC << EOF
-#include <windows.h>
-#include <WinHvPlatform.h>
-#include <WinHvEmulation.h>
-int main(void) {
- WHV_CAPABILITY whpx_cap;
- UINT32 writtenSize;
- WHvGetCapability(WHvCapabilityCodeFeatures, &whpx_cap, sizeof(whpx_cap),
- &writtenSize);
- return 0;
-}
-EOF
- if compile_prog "" "-lWinHvPlatform -lWinHvEmulation" ; then
- libs_softmmu="$libs_softmmu -lWinHvPlatform -lWinHvEmulation"
+ if check_include "WinHvPlatform.h" && check_include "WinHvEmulation.h"; then
whpx="yes"
else
if test "$whpx" = "yes"; then
@@ -6844,6 +6836,7 @@ case "$target_name" in
microblaze|microblazeel)
TARGET_ARCH=microblaze
bflt="yes"
+ echo "TARGET_ABI32=y" >> $config_target_mak
;;
mips|mipsel)
TARGET_ARCH=mips
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index dd29e741c2..8ba2558b36 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -41,6 +41,7 @@ CONFIG_USB=y
CONFIG_USB_MUSB=y
CONFIG_USB_EHCI_SYSBUS=y
CONFIG_PLATFORM_BUS=y
+CONFIG_VIRTIO_MMIO=y
CONFIG_ARM11MPCORE=y
CONFIG_A9MPCORE=y
diff --git a/default-configs/hppa-softmmu.mak b/default-configs/hppa-softmmu.mak
index 013e5f046f..4badc0521e 100644
--- a/default-configs/hppa-softmmu.mak
+++ b/default-configs/hppa-softmmu.mak
@@ -4,8 +4,6 @@ CONFIG_SERIAL=y
CONFIG_SERIAL_ISA=y
CONFIG_ISA_BUS=y
CONFIG_I8259=y
-CONFIG_VIRTIO_PCI=$(CONFIG_PCI)
-CONFIG_VIRTIO=y
CONFIG_E1000_PCI=y
CONFIG_IDE_ISA=y
CONFIG_IDE_CMD646=y
diff --git a/default-configs/mips-softmmu-common.mak b/default-configs/mips-softmmu-common.mak
index e31f046b3b..fae2347ee7 100644
--- a/default-configs/mips-softmmu-common.mak
+++ b/default-configs/mips-softmmu-common.mak
@@ -4,6 +4,7 @@ include pci.mak
include sound.mak
include usb.mak
CONFIG_ESP=y
+CONFIG_SCSI=y
CONFIG_VGA_ISA=y
CONFIG_VGA_ISA_MM=y
CONFIG_VGA_CIRRUS=y
diff --git a/default-configs/pci.mak b/default-configs/pci.mak
index 35e7596949..de53d20ac6 100644
--- a/default-configs/pci.mak
+++ b/default-configs/pci.mak
@@ -2,7 +2,7 @@ CONFIG_PCI=y
# For now, CONFIG_IDE_CORE requires ISA, so we enable it here
CONFIG_ISA_BUS=y
CONFIG_VIRTIO_PCI=y
-CONFIG_VIRTIO=y
+include virtio.mak
CONFIG_USB_UHCI=y
CONFIG_USB_OHCI=y
CONFIG_USB_EHCI=y
@@ -15,6 +15,7 @@ CONFIG_PCNET_COMMON=y
CONFIG_AC97=y
CONFIG_HDA=y
CONFIG_ES1370=y
+CONFIG_SCSI=y
CONFIG_LSI_SCSI_PCI=y
CONFIG_VMW_PVSCSI_SCSI_PCI=y
CONFIG_MEGASAS_SCSI_PCI=y
@@ -45,5 +46,3 @@ CONFIG_VGA=y
CONFIG_VGA_PCI=y
CONFIG_IVSHMEM_DEVICE=$(CONFIG_IVSHMEM)
CONFIG_ROCKER=y
-CONFIG_VHOST_USER_SCSI=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX))
-CONFIG_VHOST_USER_BLK=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX))
diff --git a/default-configs/riscv32-softmmu.mak b/default-configs/riscv32-softmmu.mak
index f9e742120c..20e670d99c 100644
--- a/default-configs/riscv32-softmmu.mak
+++ b/default-configs/riscv32-softmmu.mak
@@ -1,4 +1,5 @@
# Default configuration for riscv-softmmu
CONFIG_SERIAL=y
-CONFIG_VIRTIO=y
+CONFIG_VIRTIO_MMIO=y
+include virtio.mak
diff --git a/default-configs/riscv64-softmmu.mak b/default-configs/riscv64-softmmu.mak
index f9e742120c..20e670d99c 100644
--- a/default-configs/riscv64-softmmu.mak
+++ b/default-configs/riscv64-softmmu.mak
@@ -1,4 +1,5 @@
# Default configuration for riscv-softmmu
CONFIG_SERIAL=y
-CONFIG_VIRTIO=y
+CONFIG_VIRTIO_MMIO=y
+include virtio.mak
diff --git a/default-configs/s390x-softmmu.mak b/default-configs/s390x-softmmu.mak
index 2f4bfe73b4..d6b67d50f0 100644
--- a/default-configs/s390x-softmmu.mak
+++ b/default-configs/s390x-softmmu.mak
@@ -1,8 +1,6 @@
CONFIG_PCI=y
CONFIG_VIRTIO_PCI=$(CONFIG_PCI)
-CONFIG_VHOST_USER_SCSI=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX))
-CONFIG_VHOST_USER_BLK=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX))
-CONFIG_VIRTIO=y
+include virtio.mak
CONFIG_SCLPCONSOLE=y
CONFIG_TERMINAL3270=y
CONFIG_S390_FLIC=y
diff --git a/default-configs/sparc-softmmu.mak b/default-configs/sparc-softmmu.mak
index 004b0f4e77..12f97eeb20 100644
--- a/default-configs/sparc-softmmu.mak
+++ b/default-configs/sparc-softmmu.mak
@@ -2,6 +2,7 @@
CONFIG_ISA_BUS=y
CONFIG_ECC=y
+CONFIG_SCSI=y
CONFIG_ESP=y
CONFIG_ESCC=y
CONFIG_M48T59=y
diff --git a/default-configs/usb.mak b/default-configs/usb.mak
index f4b85684f0..e42cfeabbe 100644
--- a/default-configs/usb.mak
+++ b/default-configs/usb.mak
@@ -3,6 +3,7 @@ CONFIG_USB_TABLET_WACOM=y
CONFIG_USB_STORAGE_BOT=y
CONFIG_USB_STORAGE_UAS=y
CONFIG_USB_STORAGE_MTP=y
+CONFIG_SCSI=y
CONFIG_USB_SMARTCARD=y
CONFIG_USB_AUDIO=y
CONFIG_USB_SERIAL=y
diff --git a/default-configs/virtio.mak b/default-configs/virtio.mak
new file mode 100644
index 0000000000..1304849018
--- /dev/null
+++ b/default-configs/virtio.mak
@@ -0,0 +1,14 @@
+CONFIG_VHOST_USER_SCSI=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX))
+CONFIG_VHOST_USER_BLK=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX))
+CONFIG_VIRTIO=y
+CONFIG_VIRTIO_9P=y
+CONFIG_VIRTIO_BALLOON=y
+CONFIG_VIRTIO_BLK=y
+CONFIG_VIRTIO_CRYPTO=y
+CONFIG_VIRTIO_GPU=y
+CONFIG_VIRTIO_INPUT=y
+CONFIG_VIRTIO_NET=y
+CONFIG_VIRTIO_RNG=y
+CONFIG_SCSI=y
+CONFIG_VIRTIO_SCSI=y
+CONFIG_VIRTIO_SERIAL=y
diff --git a/docs/devel/memory.txt b/docs/devel/memory.txt
index 8ed810f8b9..c1dee1252c 100644
--- a/docs/devel/memory.txt
+++ b/docs/devel/memory.txt
@@ -77,9 +77,8 @@ MemoryRegion):
- reservation region: a reservation region is primarily for debugging.
It claims I/O space that is not supposed to be handled by QEMU itself.
The typical use is to track parts of the address space which will be
- handled by the host kernel when KVM is enabled.
- You initialize these with memory_region_init_reservation(), or by
- passing a NULL callback parameter to memory_region_init_io().
+ handled by the host kernel when KVM is enabled. You initialize these
+ by passing a NULL callback parameter to memory_region_init_io().
It is valid to add subregions to a region which is not a pure container
(that is, to an MMIO, RAM or ROM region). This means that the region
diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
index b9b6eabd08..1366228b2a 100644
--- a/docs/devel/qapi-code-gen.txt
+++ b/docs/devel/qapi-code-gen.txt
@@ -559,7 +559,7 @@ following example objects:
Usage: { 'command': STRING, '*data': COMPLEX-TYPE-NAME-OR-DICT,
'*returns': TYPE-NAME, '*boxed': true,
'*gen': false, '*success-response': false,
- '*allow-oob': true }
+ '*allow-oob': true, '*allow-preconfig': true }
Commands are defined by using a dictionary containing several members,
where three members are most common. The 'command' member is a
@@ -683,6 +683,15 @@ OOB command handlers must satisfy the following conditions:
If in doubt, do not implement OOB execution support.
+A command may use the optional 'allow-preconfig' key to permit its execution
+at early runtime configuration stage (preconfig runstate).
+If not specified then a command defaults to 'allow-preconfig': false.
+
+An example of declaring a command that is enabled during preconfig:
+ { 'command': 'qmp_capabilities',
+ 'data': { '*enable': [ 'QMPCapability' ] },
+ 'allow-preconfig': true }
+
=== Events ===
Usage: { 'event': STRING, '*data': COMPLEX-TYPE-NAME-OR-DICT,
diff --git a/docs/interop/firmware.json b/docs/interop/firmware.json
new file mode 100644
index 0000000000..28f9bc1591
--- /dev/null
+++ b/docs/interop/firmware.json
@@ -0,0 +1,540 @@
+# -*- Mode: Python -*-
+#
+# Copyright (C) 2018 Red Hat, Inc.
+#
+# Authors:
+# Daniel P. Berrange <berrange@redhat.com>
+# Laszlo Ersek <lersek@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+##
+# = Firmware
+##
+
+{ 'include' : 'common.json' }
+{ 'include' : 'block-core.json' }
+
+##
+# @FirmwareOSInterface:
+#
+# Lists the firmware-OS interface types provided by various firmware
+# that is commonly used with QEMU virtual machines.
+#
+# @bios: Traditional x86 BIOS interface. For example, firmware built
+# from the SeaBIOS project usually provides this interface.
+#
+# @openfirmware: The interface is defined by the (historical) IEEE
+# 1275-1994 standard. Examples for firmware projects that
+# provide this interface are: OpenBIOS, OpenHackWare,
+# SLOF.
+#
+# @uboot: Firmware interface defined by the U-Boot project.
+#
+# @uefi: Firmware interface defined by the UEFI specification. For
+# example, firmware built from the edk2 (EFI Development Kit II)
+# project usually provides this interface.
+#
+# Since: 3.0
+##
+{ 'enum' : 'FirmwareOSInterface',
+ 'data' : [ 'bios', 'openfirmware', 'uboot', 'uefi' ] }
+
+##
+# @FirmwareDevice:
+#
+# Defines the device types that firmware can be mapped into.
+#
+# @flash: The firmware executable and its accompanying NVRAM file are to
+# be mapped into a pflash chip each.
+#
+# @kernel: The firmware is to be loaded like a Linux kernel. This is
+# similar to @memory but may imply additional processing that
+# is specific to the target architecture and machine type.
+#
+# @memory: The firmware is to be mapped into memory.
+#
+# Since: 3.0
+##
+{ 'enum' : 'FirmwareDevice',
+ 'data' : [ 'flash', 'kernel', 'memory' ] }
+
+##
+# @FirmwareTarget:
+#
+# Defines the machine types that firmware may execute on.
+#
+# @architecture: Determines the emulation target (the QEMU system
+# emulator) that can execute the firmware.
+#
+# @machines: Lists the machine types (known by the emulator that is
+# specified through @architecture) that can execute the
+# firmware. Elements of @machines are supposed to be concrete
+# machine types, not aliases. Glob patterns are understood,
+# which is especially useful for versioned machine types.
+# (For example, the glob pattern "pc-i440fx-*" matches
+# "pc-i440fx-2.12".) On the QEMU command line, "-machine
+# type=..." specifies the requested machine type (but that
+# option does not accept glob patterns).
+#
+# Since: 3.0
+##
+{ 'struct' : 'FirmwareTarget',
+ 'data' : { 'architecture' : 'SysEmuTarget',
+ 'machines' : [ 'str' ] } }
+
+##
+# @FirmwareFeature:
+#
+# Defines the features that firmware may support, and the platform
+# requirements that firmware may present.
+#
+# @acpi-s3: The firmware supports S3 sleep (suspend to RAM), as defined
+# in the ACPI specification. On the "pc-i440fx-*" machine
+# types of the @i386 and @x86_64 emulation targets, S3 can be
+# enabled with "-global PIIX4_PM.disable_s3=0" and disabled
+# with "-global PIIX4_PM.disable_s3=1". On the "pc-q35-*"
+# machine types of the @i386 and @x86_64 emulation targets, S3
+# can be enabled with "-global ICH9-LPC.disable_s3=0" and
+# disabled with "-global ICH9-LPC.disable_s3=1".
+#
+# @acpi-s4: The firmware supports S4 hibernation (suspend to disk), as
+# defined in the ACPI specification. On the "pc-i440fx-*"
+# machine types of the @i386 and @x86_64 emulation targets, S4
+# can be enabled with "-global PIIX4_PM.disable_s4=0" and
+# disabled with "-global PIIX4_PM.disable_s4=1". On the
+# "pc-q35-*" machine types of the @i386 and @x86_64 emulation
+# targets, S4 can be enabled with "-global
+# ICH9-LPC.disable_s4=0" and disabled with "-global
+# ICH9-LPC.disable_s4=1".
+#
+# @amd-sev: The firmware supports running under AMD Secure Encrypted
+# Virtualization, as specified in the AMD64 Architecture
+# Programmer's Manual. QEMU command line options related to
+# this feature are documented in
+# "docs/amd-memory-encryption.txt".
+#
+# @enrolled-keys: The variable store (NVRAM) template associated with
+# the firmware binary has the UEFI Secure Boot
+# operational mode turned on, with certificates
+# enrolled.
+#
+# @requires-smm: The firmware requires the platform to emulate SMM
+# (System Management Mode), as defined in the AMD64
+# Architecture Programmer's Manual, and in the Intel(R)64
+# and IA-32 Architectures Software Developer's Manual. On
+# the "pc-q35-*" machine types of the @i386 and @x86_64
+# emulation targets, SMM emulation can be enabled with
+# "-machine smm=on". (On the "pc-q35-*" machine types of
+# the @i386 emulation target, @requires-smm presents
+# further CPU requirements; one combination known to work
+# is "-cpu coreduo,-nx".) If the firmware is marked as
+# both @secure-boot and @requires-smm, then write
+# accesses to the pflash chip (NVRAM) that holds the UEFI
+# variable store must be restricted to code that executes
+# in SMM, using the additional option "-global
+# driver=cfi.pflash01,property=secure,value=on".
+# Furthermore, a large guest-physical address space
+# (comprising guest RAM, memory hotplug range, and 64-bit
+# PCI MMIO aperture), and/or a high VCPU count, may
+# present high SMRAM requirements from the firmware. On
+# the "pc-q35-*" machine types of the @i386 and @x86_64
+# emulation targets, the SMRAM size may be increased
+# above the default 16MB with the "-global
+# mch.extended-tseg-mbytes=uint16" option. As a rule of
+# thumb, the default 16MB size suffices for 1TB of
+# guest-phys address space and a few tens of VCPUs; for
+# every further TB of guest-phys address space, add 8MB
+# of SMRAM. 48MB should suffice for 4TB of guest-phys
+# address space and 2-3 hundred VCPUs.
+#
+# @secure-boot: The firmware implements the software interfaces for UEFI
+# Secure Boot, as defined in the UEFI specification. Note
+# that without @requires-smm, guest code running with
+# kernel privileges can undermine the security of Secure
+# Boot.
+#
+# @verbose-dynamic: When firmware log capture is enabled, the firmware
+# logs a large amount of debug messages, which may
+# impact boot performance. With log capture disabled,
+# there is no boot performance impact. On the
+# "pc-i440fx-*" and "pc-q35-*" machine types of the
+# @i386 and @x86_64 emulation targets, firmware log
+# capture can be enabled with the QEMU command line
+# options "-chardev file,id=fwdebug,path=LOGFILEPATH
+# -device isa-debugcon,iobase=0x402,chardev=fwdebug".
+# @verbose-dynamic is mutually exclusive with
+# @verbose-static.
+#
+# @verbose-static: The firmware unconditionally produces a large amount
+# of debug messages, which may impact boot performance.
+# This feature may typically be carried by certain UEFI
+# firmware for the "virt-*" machine types of the @arm
+# and @aarch64 emulation targets, where the debug
+# messages are written to the first (always present)
+# PL011 UART. @verbose-static is mutually exclusive
+# with @verbose-dynamic.
+#
+# Since: 3.0
+##
+{ 'enum' : 'FirmwareFeature',
+ 'data' : [ 'acpi-s3', 'acpi-s4', 'amd-sev', 'enrolled-keys',
+ 'requires-smm', 'secure-boot', 'verbose-dynamic',
+ 'verbose-static' ] }
+
+##
+# @FirmwareFlashFile:
+#
+# Defines common properties that are necessary for loading a firmware
+# file into a pflash chip. The corresponding QEMU command line option is
+# "-drive file=@filename,format=@format". Note however that the
+# option-argument shown here is incomplete; it is completed under
+# @FirmwareMappingFlash.
+#
+# @filename: Specifies the filename on the host filesystem where the
+# firmware file can be found.
+#
+# @format: Specifies the block format of the file pointed-to by
+# @filename, such as @raw or @qcow2.
+#
+# Since: 3.0
+##
+{ 'struct' : 'FirmwareFlashFile',
+ 'data' : { 'filename' : 'str',
+ 'format' : 'BlockdevDriver' } }
+
+##
+# @FirmwareMappingFlash:
+#
+# Describes loading and mapping properties for the firmware executable
+# and its accompanying NVRAM file, when @FirmwareDevice is @flash.
+#
+# @executable: Identifies the firmware executable. The firmware
+# executable may be shared by multiple virtual machine
+# definitions. The corresponding QEMU command line option
+# is "-drive
+# if=pflash,unit=0,readonly=on,file=@executable.@filename,format=@executable.@format".
+#
+# @nvram-template: Identifies the NVRAM template compatible with
+# @executable. Management software instantiates an
+# individual copy -- a specific NVRAM file -- from
+# @nvram-template.@filename for each new virtual
+# machine definition created. @nvram-template.@filename
+# itself is never mapped into virtual machines, only
+# individual copies of it are. An NVRAM file is
+# typically used for persistently storing the
+# non-volatile UEFI variables of a virtual machine
+# definition. The corresponding QEMU command line
+# option is "-drive
+# if=pflash,unit=1,readonly=off,file=FILENAME_OF_PRIVATE_NVRAM_FILE,format=@nvram-template.@format".
+#
+# Since: 3.0
+##
+{ 'struct' : 'FirmwareMappingFlash',
+ 'data' : { 'executable' : 'FirmwareFlashFile',
+ 'nvram-template' : 'FirmwareFlashFile' } }
+
+##
+# @FirmwareMappingKernel:
+#
+# Describes loading and mapping properties for the firmware executable,
+# when @FirmwareDevice is @kernel.
+#
+# @filename: Identifies the firmware executable. The firmware executable
+# may be shared by multiple virtual machine definitions. The
+# corresponding QEMU command line option is "-kernel
+# @filename".
+#
+# Since: 3.0
+##
+{ 'struct' : 'FirmwareMappingKernel',
+ 'data' : { 'filename' : 'str' } }
+
+##
+# @FirmwareMappingMemory:
+#
+# Describes loading and mapping properties for the firmware executable,
+# when @FirmwareDevice is @memory.
+#
+# @filename: Identifies the firmware executable. The firmware executable
+# may be shared by multiple virtual machine definitions. The
+# corresponding QEMU command line option is "-bios
+# @filename".
+#
+# Since: 3.0
+##
+{ 'struct' : 'FirmwareMappingMemory',
+ 'data' : { 'filename' : 'str' } }
+
+##
+# @FirmwareMapping:
+#
+# Provides a discriminated structure for firmware to describe its
+# loading / mapping properties.
+#
+# @device: Selects the device type that the firmware must be mapped
+# into.
+#
+# Since: 3.0
+##
+{ 'union' : 'FirmwareMapping',
+ 'base' : { 'device' : 'FirmwareDevice' },
+ 'discriminator' : 'device',
+ 'data' : { 'flash' : 'FirmwareMappingFlash',
+ 'kernel' : 'FirmwareMappingKernel',
+ 'memory' : 'FirmwareMappingMemory' } }
+
+##
+# @Firmware:
+#
+# Describes a firmware (or a firmware use case) to management software.
+#
+# It is possible for multiple @Firmware elements to match the search
+# criteria of management software. Applications thus need rules to pick
+# one of the many matches, and users need the ability to override distro
+# defaults.
+#
+# It is recommended to create firmware JSON files (each containing a
+# single @Firmware root element) with a double-digit prefix, for example
+# "50-ovmf.json", "50-seabios-256k.json", etc, so they can be sorted in
+# predictable order. The firmware JSON files should be searched for in
+# three directories:
+#
+# - /usr/share/qemu/firmware -- populated by distro-provided firmware
+# packages (XDG_DATA_DIRS covers
+# /usr/share by default),
+#
+# - /etc/qemu/firmware -- exclusively for sysadmins' local additions,
+#
+# - $XDG_CONFIG_HOME/qemu/firmware -- exclusively for per-user local
+# additions (XDG_CONFIG_HOME
+# defaults to $HOME/.config).
+#
+# Top-down, the list of directories goes from general to specific.
+#
+# Management software should build a list of files from all three
+# locations, then sort the list by filename (i.e., last pathname
+# component). Management software should choose the first JSON file on
+# the sorted list that matches the search criteria. If a more specific
+# directory has a file with same name as a less specific directory, then
+# the file in the more specific directory takes effect. If the more
+# specific file is zero length, it hides the less specific one.
+#
+# For example, if a distro ships
+#
+# - /usr/share/qemu/firmware/50-ovmf.json
+#
+# - /usr/share/qemu/firmware/50-seabios-256k.json
+#
+# then the sysadmin can prevent the default OVMF being used at all with
+#
+# $ touch /etc/qemu/firmware/50-ovmf.json
+#
+# The sysadmin can replace/alter the distro default OVMF with
+#
+# $ vim /etc/qemu/firmware/50-ovmf.json
+#
+# or they can provide a parallel OVMF with higher priority
+#
+# $ vim /etc/qemu/firmware/10-ovmf.json
+#
+# or they can provide a parallel OVMF with lower priority
+#
+# $ vim /etc/qemu/firmware/99-ovmf.json
+#
+# @description: Provides a human-readable description of the firmware.
+# Management software may or may not display @description.
+#
+# @interface-types: Lists the types of interfaces that the firmware can
+# expose to the guest OS. This is a non-empty, ordered
+# list; entries near the beginning of @interface-types
+# are considered more native to the firmware, and/or
+# to have a higher quality implementation in the
+# firmware, than entries near the end of
+# @interface-types.
+#
+# @mapping: Describes the loading / mapping properties of the firmware.
+#
+# @targets: Collects the target architectures (QEMU system emulators)
+# and their machine types that may execute the firmware.
+#
+# @features: Lists the features that the firmware supports, and the
+# platform requirements it presents.
+#
+# @tags: A list of auxiliary strings associated with the firmware for
+# which @description is not appropriate, due to the latter's
+# possible exposure to the end-user. @tags serves development and
+# debugging purposes only, and management software shall
+# explicitly ignore it.
+#
+# Since: 3.0
+#
+# Examples:
+#
+# {
+# "description": "SeaBIOS",
+# "interface-types": [
+# "bios"
+# ],
+# "mapping": {
+# "device": "memory",
+# "filename": "/usr/share/seabios/bios-256k.bin"
+# },
+# "targets": [
+# {
+# "architecture": "i386",
+# "machines": [
+# "pc-i440fx-*",
+# "pc-q35-*"
+# ]
+# },
+# {
+# "architecture": "x86_64",
+# "machines": [
+# "pc-i440fx-*",
+# "pc-q35-*"
+# ]
+# }
+# ],
+# "features": [
+# "acpi-s3",
+# "acpi-s4"
+# ],
+# "tags": [
+# "CONFIG_BOOTSPLASH=n",
+# "CONFIG_ROM_SIZE=256",
+# "CONFIG_USE_SMM=n"
+# ]
+# }
+#
+# {
+# "description": "OVMF with SB+SMM, empty varstore",
+# "interface-types": [
+# "uefi"
+# ],
+# "mapping": {
+# "device": "flash",
+# "executable": {
+# "filename": "/usr/share/OVMF/OVMF_CODE.secboot.fd",
+# "format": "raw"
+# },
+# "nvram-template": {
+# "filename": "/usr/share/OVMF/OVMF_VARS.fd",
+# "format": "raw"
+# }
+# },
+# "targets": [
+# {
+# "architecture": "x86_64",
+# "machines": [
+# "pc-q35-*"
+# ]
+# }
+# ],
+# "features": [
+# "acpi-s3",
+# "amd-sev",
+# "requires-smm",
+# "secure-boot",
+# "verbose-dynamic"
+# ],
+# "tags": [
+# "-a IA32",
+# "-a X64",
+# "-p OvmfPkg/OvmfPkgIa32X64.dsc",
+# "-t GCC48",
+# "-b DEBUG",
+# "-D SMM_REQUIRE",
+# "-D SECURE_BOOT_ENABLE",
+# "-D FD_SIZE_4MB"
+# ]
+# }
+#
+# {
+# "description": "OVMF with SB+SMM, SB enabled, MS certs enrolled",
+# "interface-types": [
+# "uefi"
+# ],
+# "mapping": {
+# "device": "flash",
+# "executable": {
+# "filename": "/usr/share/OVMF/OVMF_CODE.secboot.fd",
+# "format": "raw"
+# },
+# "nvram-template": {
+# "filename": "/usr/share/OVMF/OVMF_VARS.secboot.fd",
+# "format": "raw"
+# }
+# },
+# "targets": [
+# {
+# "architecture": "x86_64",
+# "machines": [
+# "pc-q35-*"
+# ]
+# }
+# ],
+# "features": [
+# "acpi-s3",
+# "amd-sev",
+# "enrolled-keys",
+# "requires-smm",
+# "secure-boot",
+# "verbose-dynamic"
+# ],
+# "tags": [
+# "-a IA32",
+# "-a X64",
+# "-p OvmfPkg/OvmfPkgIa32X64.dsc",
+# "-t GCC48",
+# "-b DEBUG",
+# "-D SMM_REQUIRE",
+# "-D SECURE_BOOT_ENABLE",
+# "-D FD_SIZE_4MB"
+# ]
+# }
+#
+# {
+# "description": "UEFI firmware for ARM64 virtual machines",
+# "interface-types": [
+# "uefi"
+# ],
+# "mapping": {
+# "device": "flash",
+# "executable": {
+# "filename": "/usr/share/AAVMF/AAVMF_CODE.fd",
+# "format": "raw"
+# },
+# "nvram-template": {
+# "filename": "/usr/share/AAVMF/AAVMF_VARS.fd",
+# "format": "raw"
+# }
+# },
+# "targets": [
+# {
+# "architecture": "aarch64",
+# "machines": [
+# "virt-*"
+# ]
+# }
+# ],
+# "features": [
+#
+# ],
+# "tags": [
+# "-a AARCH64",
+# "-p ArmVirtPkg/ArmVirtQemu.dsc",
+# "-t GCC48",
+# "-b DEBUG",
+# "-D DEBUG_PRINT_ERROR_LEVEL=0x80000000"
+# ]
+# }
+##
+{ 'struct' : 'Firmware',
+ 'data' : { 'description' : 'str',
+ 'interface-types' : [ 'FirmwareOSInterface' ],
+ 'mapping' : 'FirmwareMapping',
+ 'targets' : [ 'FirmwareTarget' ],
+ 'features' : [ 'FirmwareFeature' ],
+ 'tags' : [ 'str' ] } }
diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt
index d1d71571e9..c230c4c93e 100644
--- a/docs/specs/tpm.txt
+++ b/docs/specs/tpm.txt
@@ -200,3 +200,109 @@ crw-------. 1 root root 10, 224 Jul 11 10:11 /dev/tpm0
PCR-00: 35 4E 3B CE 23 9F 38 59 ...
...
PCR-23: 00 00 00 00 00 00 00 00 ...
+
+
+=== Migration with the TPM emulator ===
+
+The TPM emulator supports the following types of virtual machine migration:
+
+- VM save / restore (migration into a file)
+- Network migration
+- Snapshotting (migration into storage like QoW2 or QED)
+
+The following command sequences can be used to test VM save / restore.
+
+
+In a 1st terminal start an instance of a swtpm using the following command:
+
+mkdir /tmp/mytpm1
+swtpm socket --tpmstate dir=/tmp/mytpm1 \
+ --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \
+ --log level=20 --tpm2
+
+In a 2nd terminal start the VM:
+
+qemu-system-x86_64 -display sdl -enable-kvm \
+ -m 1024 -boot d -bios bios-256k.bin -boot menu=on \
+ -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \
+ -tpmdev emulator,id=tpm0,chardev=chrtpm \
+ -device tpm-tis,tpmdev=tpm0 \
+ -monitor stdio \
+ test.img
+
+Verify that the attached TPM is working as expected using applications inside
+the VM.
+
+To store the state of the VM use the following command in the QEMU monitor in
+the 2nd terminal:
+
+(qemu) migrate "exec:cat > testvm.bin"
+(qemu) quit
+
+At this point a file called 'testvm.bin' should exists and the swtpm and QEMU
+processes should have ended.
+
+To test 'VM restore' you have to start the swtpm with the same parameters
+as before. If previously a TPM 2 [--tpm2] was saved, --tpm2 must now be
+passed again on the command line.
+
+In the 1st terminal restart the swtpm with the same command line as before:
+
+swtpm socket --tpmstate dir=/tmp/mytpm1 \
+ --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \
+ --log level=20 --tpm2
+
+In the 2nd terminal restore the state of the VM using the additonal
+'-incoming' option.
+
+qemu-system-x86_64 -display sdl -enable-kvm \
+ -m 1024 -boot d -bios bios-256k.bin -boot menu=on \
+ -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \
+ -tpmdev emulator,id=tpm0,chardev=chrtpm \
+ -device tpm-tis,tpmdev=tpm0 \
+ -incoming "exec:cat < testvm.bin" \
+ test.img
+
+
+Troubleshooting migration:
+
+There are several reasons why migration may fail. In case of problems,
+please ensure that the command lines adhere to the following rules and,
+if possible, that identical versions of QEMU and swtpm are used at all
+times.
+
+VM save and restore:
+ - QEMU command line parameters should be identical apart from the
+ '-incoming' option on VM restore
+ - swtpm command line parameters should be identical
+
+VM migration to 'localhost':
+ - QEMU command line parameters should be identical apart from the
+ '-incoming' option on the destination side
+ - swtpm command line parameters should point to two different
+ directories on the source and destination swtpm (--tpmstate dir=...)
+ (especially if different versions of libtpms were to be used on the
+ same machine).
+
+VM migration across the network:
+ - QEMU command line parameters should be identical apart from the
+ '-incoming' option on the destination side
+ - swtpm command line parameters should be identical
+
+VM Snapshotting:
+ - QEMU command line parameters should be identical
+ - swtpm command line parameters should be identical
+
+
+Besides that, migration failure reasons on the swtpm level may include
+the following:
+
+ - the versions of the swtpm on the source and destination sides are
+ incompatible
+ - downgrading of TPM state may not be supported
+ - the source and destination libtpms were compiled with different
+ compile-time options and the destination side refuses to accept the
+ state
+ - different migration keys are used on the source and destination side
+ and the destination side cannot decrypt the migrated state
+ (swtpm ... --migration-key ... )
diff --git a/exec.c b/exec.c
index ffa1099547..f3fa4e9117 100644
--- a/exec.c
+++ b/exec.c
@@ -478,6 +478,7 @@ address_space_translate_internal(AddressSpaceDispatch *d, hwaddr addr, hwaddr *x
* @is_write: whether the translation operation is for write
* @is_mmio: whether this can be MMIO, set true if it can
* @target_as: the address space targeted by the IOMMU
+ * @attrs: transaction attributes
*
* This function is called from RCU critical section. It is the common
* part of flatview_do_translate and address_space_translate_cached.
@@ -488,7 +489,8 @@ static MemoryRegionSection address_space_translate_iommu(IOMMUMemoryRegion *iomm
hwaddr *page_mask_out,
bool is_write,
bool is_mmio,
- AddressSpace **target_as)
+ AddressSpace **target_as,
+ MemTxAttrs attrs)
{
MemoryRegionSection *section;
hwaddr page_mask = (hwaddr)-1;
@@ -541,6 +543,7 @@ unassigned:
* @is_write: whether the translation operation is for write
* @is_mmio: whether this can be MMIO, set true if it can
* @target_as: the address space targeted by the IOMMU
+ * @attrs: memory transaction attributes
*
* This function is called from RCU critical section
*/
@@ -551,7 +554,8 @@ static MemoryRegionSection flatview_do_translate(FlatView *fv,
hwaddr *page_mask_out,
bool is_write,
bool is_mmio,
- AddressSpace **target_as)
+ AddressSpace **target_as,
+ MemTxAttrs attrs)
{
MemoryRegionSection *section;
IOMMUMemoryRegion *iommu_mr;
@@ -570,7 +574,7 @@ static MemoryRegionSection flatview_do_translate(FlatView *fv,
return address_space_translate_iommu(iommu_mr, xlat,
plen_out, page_mask_out,
is_write, is_mmio,
- target_as);
+ target_as, attrs);
}
if (page_mask_out) {
/* Not behind an IOMMU, use default page size. */
@@ -582,7 +586,7 @@ static MemoryRegionSection flatview_do_translate(FlatView *fv,
/* Called from RCU critical section */
IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr,
- bool is_write)
+ bool is_write, MemTxAttrs attrs)
{
MemoryRegionSection section;
hwaddr xlat, page_mask;
@@ -592,7 +596,8 @@ IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr,
* but page mask.
*/
section = flatview_do_translate(address_space_to_flatview(as), addr, &xlat,
- NULL, &page_mask, is_write, false, &as);
+ NULL, &page_mask, is_write, false, &as,
+ attrs);
/* Illegal translation */
if (section.mr == &io_mem_unassigned) {
@@ -618,7 +623,8 @@ iotlb_fail:
/* Called from RCU critical section */
MemoryRegion *flatview_translate(FlatView *fv, hwaddr addr, hwaddr *xlat,
- hwaddr *plen, bool is_write)
+ hwaddr *plen, bool is_write,
+ MemTxAttrs attrs)
{
MemoryRegion *mr;
MemoryRegionSection section;
@@ -626,7 +632,7 @@ MemoryRegion *flatview_translate(FlatView *fv, hwaddr addr, hwaddr *xlat,
/* This can be MMIO, so setup MMIO bit. */
section = flatview_do_translate(fv, addr, xlat, plen, NULL,
- is_write, true, &as);
+ is_write, true, &as, attrs);
mr = section.mr;
if (xen_enabled() && memory_access_is_direct(mr, is_write)) {
@@ -898,7 +904,7 @@ static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
if (phys != -1) {
/* Locks grabbed by tb_invalidate_phys_addr */
tb_invalidate_phys_addr(cpu->cpu_ases[asidx].as,
- phys | (pc & ~TARGET_PAGE_MASK));
+ phys | (pc & ~TARGET_PAGE_MASK), attrs);
}
}
#endif
@@ -1124,6 +1130,7 @@ void cpu_abort(CPUState *cpu, const char *fmt, ...)
struct sigaction act;
sigfillset(&act.sa_mask);
act.sa_handler = SIG_DFL;
+ act.sa_flags = 0;
sigaction(SIGABRT, &act, NULL);
}
#endif
@@ -2539,7 +2546,8 @@ static void notdirty_mem_write(void *opaque, hwaddr ram_addr,
}
static bool notdirty_mem_accepts(void *opaque, hwaddr addr,
- unsigned size, bool is_write)
+ unsigned size, bool is_write,
+ MemTxAttrs attrs)
{
return is_write;
}
@@ -2696,7 +2704,7 @@ static MemTxResult flatview_read(FlatView *fv, hwaddr addr,
static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs,
const uint8_t *buf, int len);
static bool flatview_access_valid(FlatView *fv, hwaddr addr, int len,
- bool is_write);
+ bool is_write, MemTxAttrs attrs);
static MemTxResult subpage_read(void *opaque, hwaddr addr, uint64_t *data,
unsigned len, MemTxAttrs attrs)
@@ -2762,7 +2770,8 @@ static MemTxResult subpage_write(void *opaque, hwaddr addr,
}
static bool subpage_accepts(void *opaque, hwaddr addr,
- unsigned len, bool is_write)
+ unsigned len, bool is_write,
+ MemTxAttrs attrs)
{
subpage_t *subpage = opaque;
#if defined(DEBUG_SUBPAGE)
@@ -2771,7 +2780,7 @@ static bool subpage_accepts(void *opaque, hwaddr addr,
#endif
return flatview_access_valid(subpage->fv, addr + subpage->base,
- len, is_write);
+ len, is_write, attrs);
}
static const MemoryRegionOps subpage_ops = {
@@ -2845,7 +2854,8 @@ static void readonly_mem_write(void *opaque, hwaddr addr,
}
static bool readonly_mem_accepts(void *opaque, hwaddr addr,
- unsigned size, bool is_write)
+ unsigned size, bool is_write,
+ MemTxAttrs attrs)
{
return is_write;
}
@@ -3149,7 +3159,7 @@ static MemTxResult flatview_write_continue(FlatView *fv, hwaddr addr,
}
l = len;
- mr = flatview_translate(fv, addr, &addr1, &l, true);
+ mr = flatview_translate(fv, addr, &addr1, &l, true, attrs);
}
return result;
@@ -3165,7 +3175,7 @@ static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs,
MemTxResult result = MEMTX_OK;
l = len;
- mr = flatview_translate(fv, addr, &addr1, &l, true);
+ mr = flatview_translate(fv, addr, &addr1, &l, true, attrs);
result = flatview_write_continue(fv, addr, attrs, buf, len,
addr1, l, mr);
@@ -3236,7 +3246,7 @@ MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr,
}
l = len;
- mr = flatview_translate(fv, addr, &addr1, &l, false);
+ mr = flatview_translate(fv, addr, &addr1, &l, false, attrs);
}
return result;
@@ -3251,7 +3261,7 @@ static MemTxResult flatview_read(FlatView *fv, hwaddr addr,
MemoryRegion *mr;
l = len;
- mr = flatview_translate(fv, addr, &addr1, &l, false);
+ mr = flatview_translate(fv, addr, &addr1, &l, false, attrs);
return flatview_read_continue(fv, addr, attrs, buf, len,
addr1, l, mr);
}
@@ -3322,7 +3332,8 @@ static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
rcu_read_lock();
while (len > 0) {
l = len;
- mr = address_space_translate(as, addr, &addr1, &l, true);
+ mr = address_space_translate(as, addr, &addr1, &l, true,
+ MEMTXATTRS_UNSPECIFIED);
if (!(memory_region_is_ram(mr) ||
memory_region_is_romd(mr))) {
@@ -3457,17 +3468,17 @@ static void cpu_notify_map_clients(void)
}
static bool flatview_access_valid(FlatView *fv, hwaddr addr, int len,
- bool is_write)
+ bool is_write, MemTxAttrs attrs)
{
MemoryRegion *mr;
hwaddr l, xlat;
while (len > 0) {
l = len;
- mr = flatview_translate(fv, addr, &xlat, &l, is_write);
+ mr = flatview_translate(fv, addr, &xlat, &l, is_write, attrs);
if (!memory_access_is_direct(mr, is_write)) {
l = memory_access_size(mr, l, addr);
- if (!memory_region_access_valid(mr, xlat, l, is_write)) {
+ if (!memory_region_access_valid(mr, xlat, l, is_write, attrs)) {
return false;
}
}
@@ -3479,23 +3490,24 @@ static bool flatview_access_valid(FlatView *fv, hwaddr addr, int len,
}
bool address_space_access_valid(AddressSpace *as, hwaddr addr,
- int len, bool is_write)
+ int len, bool is_write,
+ MemTxAttrs attrs)
{
FlatView *fv;
bool result;
rcu_read_lock();
fv = address_space_to_flatview(as);
- result = flatview_access_valid(fv, addr, len, is_write);
+ result = flatview_access_valid(fv, addr, len, is_write, attrs);
rcu_read_unlock();
return result;
}
static hwaddr
flatview_extend_translation(FlatView *fv, hwaddr addr,
- hwaddr target_len,
- MemoryRegion *mr, hwaddr base, hwaddr len,
- bool is_write)
+ hwaddr target_len,
+ MemoryRegion *mr, hwaddr base, hwaddr len,
+ bool is_write, MemTxAttrs attrs)
{
hwaddr done = 0;
hwaddr xlat;
@@ -3511,7 +3523,7 @@ flatview_extend_translation(FlatView *fv, hwaddr addr,
len = target_len;
this_mr = flatview_translate(fv, addr, &xlat,
- &len, is_write);
+ &len, is_write, attrs);
if (this_mr != mr || xlat != base + done) {
return done;
}
@@ -3528,7 +3540,8 @@ flatview_extend_translation(FlatView *fv, hwaddr addr,
void *address_space_map(AddressSpace *as,
hwaddr addr,
hwaddr *plen,
- bool is_write)
+ bool is_write,
+ MemTxAttrs attrs)
{
hwaddr len = *plen;
hwaddr l, xlat;
@@ -3543,7 +3556,7 @@ void *address_space_map(AddressSpace *as,
l = len;
rcu_read_lock();
fv = address_space_to_flatview(as);
- mr = flatview_translate(fv, addr, &xlat, &l, is_write);
+ mr = flatview_translate(fv, addr, &xlat, &l, is_write, attrs);
if (!memory_access_is_direct(mr, is_write)) {
if (atomic_xchg(&bounce.in_use, true)) {
@@ -3571,7 +3584,7 @@ void *address_space_map(AddressSpace *as,
memory_region_ref(mr);
*plen = flatview_extend_translation(fv, addr, len, mr, xlat,
- l, is_write);
+ l, is_write, attrs);
ptr = qemu_ram_ptr_length(mr->ram_block, xlat, plen, true);
rcu_read_unlock();
@@ -3615,7 +3628,8 @@ void *cpu_physical_memory_map(hwaddr addr,
hwaddr *plen,
int is_write)
{
- return address_space_map(&address_space_memory, addr, plen, is_write);
+ return address_space_map(&address_space_memory, addr, plen, is_write,
+ MEMTXATTRS_UNSPECIFIED);
}
void cpu_physical_memory_unmap(void *buffer, hwaddr len,
@@ -3655,8 +3669,13 @@ int64_t address_space_cache_init(MemoryRegionCache *cache,
mr = cache->mrs.mr;
memory_region_ref(mr);
if (memory_access_is_direct(mr, is_write)) {
+ /* We don't care about the memory attributes here as we're only
+ * doing this if we found actual RAM, which behaves the same
+ * regardless of attributes; so UNSPECIFIED is fine.
+ */
l = flatview_extend_translation(cache->fv, addr, len, mr,
- cache->xlat, l, is_write);
+ cache->xlat, l, is_write,
+ MEMTXATTRS_UNSPECIFIED);
cache->ptr = qemu_ram_ptr_length(mr->ram_block, cache->xlat, &l, true);
} else {
cache->ptr = NULL;
@@ -3699,7 +3718,7 @@ void address_space_cache_destroy(MemoryRegionCache *cache)
*/
static inline MemoryRegion *address_space_translate_cached(
MemoryRegionCache *cache, hwaddr addr, hwaddr *xlat,
- hwaddr *plen, bool is_write)
+ hwaddr *plen, bool is_write, MemTxAttrs attrs)
{
MemoryRegionSection section;
MemoryRegion *mr;
@@ -3718,7 +3737,7 @@ static inline MemoryRegion *address_space_translate_cached(
section = address_space_translate_iommu(iommu_mr, xlat, plen,
NULL, is_write, true,
- &target_as);
+ &target_as, attrs);
return section.mr;
}
@@ -3733,7 +3752,8 @@ address_space_read_cached_slow(MemoryRegionCache *cache, hwaddr addr,
MemoryRegion *mr;
l = len;
- mr = address_space_translate_cached(cache, addr, &addr1, &l, false);
+ mr = address_space_translate_cached(cache, addr, &addr1, &l, false,
+ MEMTXATTRS_UNSPECIFIED);
flatview_read_continue(cache->fv,
addr, MEMTXATTRS_UNSPECIFIED, buf, len,
addr1, l, mr);
@@ -3750,7 +3770,8 @@ address_space_write_cached_slow(MemoryRegionCache *cache, hwaddr addr,
MemoryRegion *mr;
l = len;
- mr = address_space_translate_cached(cache, addr, &addr1, &l, true);
+ mr = address_space_translate_cached(cache, addr, &addr1, &l, true,
+ MEMTXATTRS_UNSPECIFIED);
flatview_write_continue(cache->fv,
addr, MEMTXATTRS_UNSPECIFIED, buf, len,
addr1, l, mr);
@@ -3848,7 +3869,8 @@ bool cpu_physical_memory_is_io(hwaddr phys_addr)
rcu_read_lock();
mr = address_space_translate(&address_space_memory,
- phys_addr, &phys_addr, &l, false);
+ phys_addr, &phys_addr, &l, false,
+ MEMTXATTRS_UNSPECIFIED);
res = !(memory_region_is_ram(mr) || memory_region_is_romd(mr));
rcu_read_unlock();
diff --git a/gdbstub.c b/gdbstub.c
index e4ece2f5bc..d6ab95006c 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1558,6 +1558,12 @@ void gdb_do_syscallv(gdb_syscall_complete_cb cb, const char *fmt, va_list va)
*p = 0;
#ifdef CONFIG_USER_ONLY
put_packet(s, s->syscall_buf);
+ /* Return control to gdb for it to process the syscall request.
+ * Since the protocol requires that gdb hands control back to us
+ * using a "here are the results" F packet, we don't need to check
+ * gdb_handlesig's return value (which is the signal to deliver if
+ * execution was resumed via a continue packet).
+ */
gdb_handlesig(s->c_cpu, 0);
#else
/* In this case wait to send the syscall packet until notification that
@@ -1836,6 +1842,7 @@ static bool gdb_accept(void)
/* set short latency */
if (socket_set_nodelay(fd)) {
perror("setsockopt");
+ close(fd);
return false;
}
diff --git a/hw/9pfs/Makefile.objs b/hw/9pfs/Makefile.objs
index fd90b62900..e3fa673665 100644
--- a/hw/9pfs/Makefile.objs
+++ b/hw/9pfs/Makefile.objs
@@ -1,3 +1,4 @@
+ifeq ($(call lor,$(CONFIG_VIRTIO_9P),$(CONFIG_XEN)),y)
common-obj-y = 9p.o 9p-util.o
common-obj-y += 9p-local.o 9p-xattr.o
common-obj-y += 9p-xattr-user.o 9p-posix-acl.o
@@ -5,6 +6,7 @@ common-obj-y += coth.o cofs.o codir.o cofile.o
common-obj-y += coxattr.o 9p-synth.o
common-obj-$(CONFIG_OPEN_BY_HANDLE) += 9p-handle.o
common-obj-y += 9p-proxy.o
-common-obj-$(CONFIG_XEN) += xen-9p-backend.o
+endif
-obj-$(CONFIG_VIRTIO) += virtio-9p-device.o
+common-obj-$(CONFIG_XEN) += xen-9p-backend.o
+obj-$(CONFIG_VIRTIO_9P) += virtio-9p-device.o
diff --git a/hw/9pfs/xen-9p-backend.c b/hw/9pfs/xen-9p-backend.c
index 95e50c4dfc..6026780f95 100644
--- a/hw/9pfs/xen-9p-backend.c
+++ b/hw/9pfs/xen-9p-backend.c
@@ -331,14 +331,14 @@ static int xen_9pfs_free(struct XenDevice *xendev)
for (i = 0; i < xen_9pdev->num_rings; i++) {
if (xen_9pdev->rings[i].data != NULL) {
- xengnttab_unmap(xen_9pdev->xendev.gnttabdev,
- xen_9pdev->rings[i].data,
- (1 << xen_9pdev->rings[i].ring_order));
+ xen_be_unmap_grant_refs(&xen_9pdev->xendev,
+ xen_9pdev->rings[i].data,
+ (1 << xen_9pdev->rings[i].ring_order));
}
if (xen_9pdev->rings[i].intf != NULL) {
- xengnttab_unmap(xen_9pdev->xendev.gnttabdev,
- xen_9pdev->rings[i].intf,
- 1);
+ xen_be_unmap_grant_refs(&xen_9pdev->xendev,
+ xen_9pdev->rings[i].intf,
+ 1);
}
if (xen_9pdev->rings[i].bh != NULL) {
qemu_bh_delete(xen_9pdev->rings[i].bh);
@@ -390,11 +390,10 @@ static int xen_9pfs_connect(struct XenDevice *xendev)
}
g_free(str);
- xen_9pdev->rings[i].intf = xengnttab_map_grant_ref(
- xen_9pdev->xendev.gnttabdev,
- xen_9pdev->xendev.dom,
- xen_9pdev->rings[i].ref,
- PROT_READ | PROT_WRITE);
+ xen_9pdev->rings[i].intf =
+ xen_be_map_grant_ref(&xen_9pdev->xendev,
+ xen_9pdev->rings[i].ref,
+ PROT_READ | PROT_WRITE);
if (!xen_9pdev->rings[i].intf) {
goto out;
}
@@ -403,12 +402,11 @@ static int xen_9pfs_connect(struct XenDevice *xendev)
goto out;
}
xen_9pdev->rings[i].ring_order = ring_order;
- xen_9pdev->rings[i].data = xengnttab_map_domain_grant_refs(
- xen_9pdev->xendev.gnttabdev,
- (1 << ring_order),
- xen_9pdev->xendev.dom,
- xen_9pdev->rings[i].intf->ref,
- PROT_READ | PROT_WRITE);
+ xen_9pdev->rings[i].data =
+ xen_be_map_grant_refs(&xen_9pdev->xendev,
+ xen_9pdev->rings[i].intf->ref,
+ (1 << ring_order),
+ PROT_READ | PROT_WRITE);
if (!xen_9pdev->rings[i].data) {
goto out;
}
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index 6a0ffe0afd..a19c1417ed 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -23,7 +23,7 @@ devices-dirs-$(CONFIG_SOFTMMU) += nvram/
devices-dirs-$(CONFIG_SOFTMMU) += pci/
devices-dirs-$(CONFIG_PCI) += pci-bridge/ pci-host/
devices-dirs-$(CONFIG_SOFTMMU) += pcmcia/
-devices-dirs-$(CONFIG_SOFTMMU) += scsi/
+devices-dirs-$(CONFIG_SCSI) += scsi/
devices-dirs-$(CONFIG_SOFTMMU) += sd/
devices-dirs-$(CONFIG_SOFTMMU) += ssi/
devices-dirs-$(CONFIG_SOFTMMU) += timer/
diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c
index 91c82fdc7a..80d42e12ff 100644
--- a/hw/acpi/pcihp.c
+++ b/hw/acpi/pcihp.c
@@ -32,7 +32,6 @@
#include "hw/pci/pci.h"
#include "hw/acpi/acpi.h"
#include "sysemu/sysemu.h"
-#include "exec/ioport.h"
#include "exec/address-spaces.h"
#include "hw/pci/pci_bus.h"
#include "qapi/error.h"
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index 8b703455b7..6404af5f33 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -28,7 +28,6 @@
#include "sysemu/sysemu.h"
#include "qapi/error.h"
#include "qemu/range.h"
-#include "exec/ioport.h"
#include "hw/nvram/fw_cfg.h"
#include "exec/address-spaces.h"
#include "hw/acpi/piix4.h"
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index aecb3c1e75..a7110a712f 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -19,7 +19,6 @@
#include "hw/boards.h"
#include "qemu/log.h"
#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
#include "hw/loader.h"
#include "qemu/error-report.h"
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
index 3c4b44a53e..6805a7d7c8 100644
--- a/hw/arm/bcm2836.c
+++ b/hw/arm/bcm2836.c
@@ -15,7 +15,6 @@
#include "hw/arm/bcm2836.h"
#include "hw/arm/raspi_platform.h"
#include "hw/sysbus.h"
-#include "exec/address-spaces.h"
/* Peripheral base address seen by the CPU */
#define BCM2836_PERI_BASE 0x3F000000
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index 9496f331a8..1e481662ad 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -926,6 +926,15 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
static const ARMInsnFixup *primary_loader;
AddressSpace *as = arm_boot_address_space(cpu, info);
+ /* CPU objects (unlike devices) are not automatically reset on system
+ * reset, so we must always register a handler to do so. If we're
+ * actually loading a kernel, the handler is also responsible for
+ * arranging that we start it correctly.
+ */
+ for (cs = first_cpu; cs; cs = CPU_NEXT(cs)) {
+ qemu_register_reset(do_cpu_reset, ARM_CPU(cs));
+ }
+
/* The board code is not supposed to set secure_board_setup unless
* running its code in secure mode is actually possible, and KVM
* doesn't support secure.
@@ -1143,15 +1152,6 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
ARM_CPU(cs)->env.boot_info = info;
}
- /* CPU objects (unlike devices) are not automatically reset on system
- * reset, so we must always register a handler to do so. If we're
- * actually loading a kernel, the handler is also responsible for
- * arranging that we start it correctly.
- */
- for (cs = first_cpu; cs; cs = CPU_NEXT(cs)) {
- qemu_register_reset(do_cpu_reset, ARM_CPU(cs));
- }
-
if (!info->skip_dtb_autoload && have_dtb(info)) {
if (arm_load_dtb(info->dtb_start, info, info->dtb_limit, as) < 0) {
exit(1);
diff --git a/hw/arm/collie.c b/hw/arm/collie.c
index f8c566e2e5..48b732c176 100644
--- a/hw/arm/collie.c
+++ b/hw/arm/collie.c
@@ -16,7 +16,6 @@
#include "strongarm.h"
#include "hw/arm/arm.h"
#include "hw/block/flash.h"
-#include "sysemu/block-backend.h"
#include "exec/address-spaces.h"
#include "cpu.h"
diff --git a/hw/arm/gumstix.c b/hw/arm/gumstix.c
index ea2a3c532d..56cb763c4e 100644
--- a/hw/arm/gumstix.c
+++ b/hw/arm/gumstix.c
@@ -42,7 +42,6 @@
#include "hw/block/flash.h"
#include "hw/devices.h"
#include "hw/boards.h"
-#include "sysemu/block-backend.h"
#include "exec/address-spaces.h"
#include "sysemu/qtest.h"
#include "cpu.h"
diff --git a/hw/arm/mainstone.c b/hw/arm/mainstone.c
index 4215c025fc..0beb5c426b 100644
--- a/hw/arm/mainstone.c
+++ b/hw/arm/mainstone.c
@@ -21,7 +21,6 @@
#include "hw/devices.h"
#include "hw/boards.h"
#include "hw/block/flash.h"
-#include "sysemu/block-backend.h"
#include "hw/sysbus.h"
#include "exec/address-spaces.h"
#include "sysemu/qtest.h"
diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c
index 32687afced..906b7ca22d 100644
--- a/hw/arm/nseries.c
+++ b/hw/arm/nseries.c
@@ -35,7 +35,6 @@
#include "hw/hw.h"
#include "hw/bt.h"
#include "hw/loader.h"
-#include "sysemu/block-backend.h"
#include "hw/sysbus.h"
#include "qemu/log.h"
#include "exec/address-spaces.h"
diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c
index e54c1f8f99..9af04728e3 100644
--- a/hw/arm/omap1.c
+++ b/hw/arm/omap1.c
@@ -28,8 +28,6 @@
#include "hw/arm/omap.h"
#include "sysemu/sysemu.h"
#include "hw/arm/soc_dma.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
#include "sysemu/qtest.h"
#include "qemu/range.h"
#include "hw/sysbus.h"
diff --git a/hw/arm/omap2.c b/hw/arm/omap2.c
index b8d0910a1f..3c7d1364a9 100644
--- a/hw/arm/omap2.c
+++ b/hw/arm/omap2.c
@@ -23,8 +23,6 @@
#include "qapi/error.h"
#include "qemu-common.h"
#include "cpu.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
#include "sysemu/qtest.h"
#include "hw/boards.h"
#include "hw/hw.h"
diff --git a/hw/arm/omap_sx1.c b/hw/arm/omap_sx1.c
index eccc19c77b..84550f0236 100644
--- a/hw/arm/omap_sx1.c
+++ b/hw/arm/omap_sx1.c
@@ -33,7 +33,6 @@
#include "hw/boards.h"
#include "hw/arm/arm.h"
#include "hw/block/flash.h"
-#include "sysemu/block-backend.h"
#include "sysemu/qtest.h"
#include "exec/address-spaces.h"
#include "cpu.h"
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index a2803fdee4..b67b0cefb6 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -19,7 +19,6 @@
#include "hw/i2c/i2c.h"
#include "hw/ssi/ssi.h"
#include "chardev/char-fe.h"
-#include "sysemu/block-backend.h"
#include "sysemu/blockdev.h"
#include "sysemu/qtest.h"
#include "qemu/cutils.h"
diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c
index e419e3c00e..3cc27a1e44 100644
--- a/hw/arm/spitz.c
+++ b/hw/arm/spitz.c
@@ -27,7 +27,6 @@
#include "hw/audio/wm8750.h"
#include "audio/audio.h"
#include "hw/boards.h"
-#include "sysemu/block-backend.h"
#include "hw/sysbus.h"
#include "exec/address-spaces.h"
#include "cpu.h"
diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c
index e01e3192ff..a5a06b6d40 100644
--- a/hw/arm/versatilepb.c
+++ b/hw/arm/versatilepb.c
@@ -19,7 +19,6 @@
#include "hw/pci/pci.h"
#include "hw/i2c/i2c.h"
#include "hw/boards.h"
-#include "sysemu/block-backend.h"
#include "exec/address-spaces.h"
#include "hw/block/flash.h"
#include "qemu/error-report.h"
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
index f1e33c8a36..5bfe2e4348 100644
--- a/hw/arm/vexpress.c
+++ b/hw/arm/vexpress.c
@@ -35,7 +35,6 @@
#include "hw/boards.h"
#include "hw/loader.h"
#include "exec/address-spaces.h"
-#include "sysemu/block-backend.h"
#include "hw/block/flash.h"
#include "sysemu/device_tree.h"
#include "qemu/error-report.h"
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 92ceee9c0f..74f5744e87 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -400,7 +400,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
AcpiIortItsGroup *its;
AcpiIortTable *iort;
AcpiIortSmmu3 *smmu;
- size_t node_size, iort_length, smmu_offset = 0;
+ size_t node_size, iort_node_offset, iort_length, smmu_offset = 0;
AcpiIortRC *rc;
iort = acpi_data_push(table_data, sizeof(*iort));
@@ -413,7 +413,12 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
iort_length = sizeof(*iort);
iort->node_count = cpu_to_le32(nb_nodes);
- iort->node_offset = cpu_to_le32(sizeof(*iort));
+ /*
+ * Use a copy in case table_data->data moves during acpi_data_push
+ * operations.
+ */
+ iort_node_offset = sizeof(*iort);
+ iort->node_offset = cpu_to_le32(iort_node_offset);
/* ITS group node */
node_size = sizeof(*its) + sizeof(uint32_t);
@@ -429,7 +434,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
int irq = vms->irqmap[VIRT_SMMU];
/* SMMUv3 node */
- smmu_offset = iort->node_offset + node_size;
+ smmu_offset = iort_node_offset + node_size;
node_size = sizeof(*smmu) + sizeof(*idmap);
iort_length += node_size;
smmu = acpi_data_push(table_data, node_size);
@@ -450,7 +455,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
idmap->id_count = cpu_to_le32(0xFFFF);
idmap->output_base = 0;
/* output IORT node is the ITS group node (the first node) */
- idmap->output_reference = cpu_to_le32(iort->node_offset);
+ idmap->output_reference = cpu_to_le32(iort_node_offset);
}
/* Root Complex Node */
@@ -479,9 +484,14 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
idmap->output_reference = cpu_to_le32(smmu_offset);
} else {
/* output IORT node is the ITS group node (the first node) */
- idmap->output_reference = cpu_to_le32(iort->node_offset);
+ idmap->output_reference = cpu_to_le32(iort_node_offset);
}
+ /*
+ * Update the pointer address in case table_data->data moves during above
+ * acpi_data_push operations.
+ */
+ iort = (AcpiIortTable *)(table_data->data + iort_start);
iort->length = cpu_to_le32(iort_length);
build_header(linker, table_data, (void *)(table_data->data + iort_start),
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index a3a28e20e8..3aa19b2935 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -38,7 +38,6 @@
#include "hw/vfio/vfio-amd-xgbe.h"
#include "hw/devices.h"
#include "net/net.h"
-#include "sysemu/block-backend.h"
#include "sysemu/device_tree.h"
#include "sysemu/numa.h"
#include "sysemu/sysemu.h"
diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index 899a26326f..f1496d2927 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -26,7 +26,6 @@
#include "sysemu/sysemu.h"
#include "hw/boards.h"
#include "hw/block/flash.h"
-#include "sysemu/block-backend.h"
#include "hw/loader.h"
#include "hw/misc/zynq-xadc.h"
#include "hw/ssi/ssi.h"
diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c
index b126cf148b..c70278c8c1 100644
--- a/hw/arm/xlnx-zcu102.c
+++ b/hw/arm/xlnx-zcu102.c
@@ -22,7 +22,6 @@
#include "hw/arm/xlnx-zynqmp.h"
#include "hw/boards.h"
#include "qemu/error-report.h"
-#include "exec/address-spaces.h"
#include "qemu/log.h"
#include "sysemu/qtest.h"
diff --git a/hw/arm/z2.c b/hw/arm/z2.c
index 730a5392e9..697a822f1e 100644
--- a/hw/arm/z2.c
+++ b/hw/arm/z2.c
@@ -21,7 +21,6 @@
#include "hw/boards.h"
#include "sysemu/sysemu.h"
#include "hw/block/flash.h"
-#include "sysemu/block-backend.h"
#include "ui/console.h"
#include "hw/audio/wm8750.h"
#include "audio/audio.h"
diff --git a/hw/audio/wm8750.c b/hw/audio/wm8750.c
index 416a78e869..f4aa838f62 100644
--- a/hw/audio/wm8750.c
+++ b/hw/audio/wm8750.c
@@ -617,14 +617,12 @@ static const VMStateDescription vmstate_wm8750 = {
}
};
-static int wm8750_init(I2CSlave *i2c)
+static void wm8750_realize(DeviceState *dev, Error **errp)
{
- WM8750State *s = WM8750(i2c);
+ WM8750State *s = WM8750(dev);
AUD_register_card(CODEC, &s->card);
wm8750_reset(I2C_SLAVE(s));
-
- return 0;
}
#if 0
@@ -707,7 +705,7 @@ static void wm8750_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
- sc->init = wm8750_init;
+ dc->realize = wm8750_realize;
sc->event = wm8750_event;
sc->recv = wm8750_rx;
sc->send = wm8750_tx;
diff --git a/hw/block/Makefile.objs b/hw/block/Makefile.objs
index 4c19a583c8..53ce5751ae 100644
--- a/hw/block/Makefile.objs
+++ b/hw/block/Makefile.objs
@@ -11,8 +11,6 @@ common-obj-$(CONFIG_NVME_PCI) += nvme.o
obj-$(CONFIG_SH4) += tc58128.o
-obj-$(CONFIG_VIRTIO) += virtio-blk.o
-obj-$(CONFIG_VIRTIO) += dataplane/
-ifeq ($(CONFIG_VIRTIO),y)
+obj-$(CONFIG_VIRTIO_BLK) += virtio-blk.o
+obj-$(CONFIG_VIRTIO_BLK) += dataplane/
obj-$(CONFIG_VHOST_USER_BLK) += vhost-user-blk.o
-endif
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
index 101f32cf66..d648aeb73b 100644
--- a/hw/block/dataplane/virtio-blk.c
+++ b/hw/block/dataplane/virtio-blk.c
@@ -19,7 +19,6 @@
#include "qemu/thread.h"
#include "qemu/error-report.h"
#include "hw/virtio/virtio-access.h"
-#include "sysemu/block-backend.h"
#include "hw/virtio/virtio-blk.h"
#include "virtio-blk.h"
#include "block/aio.h"
diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index b49c8e9caa..a5ccffb4aa 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -24,7 +24,6 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
#include "hw/ssi/ssi.h"
#include "qemu/bitops.h"
#include "qemu/log.h"
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 85d2406400..811084b6a7 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -35,6 +35,7 @@
#include "sysemu/block-backend.h"
#include "qemu/log.h"
+#include "qemu/cutils.h"
#include "trace.h"
#include "nvme.h"
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
index 8f3981121d..cabcf20c32 100644
--- a/hw/block/nvme.h
+++ b/hw/block/nvme.h
@@ -1,6 +1,5 @@
#ifndef HW_NVME_H
#define HW_NVME_H
-#include "qemu/cutils.h"
#include "block/nvme.h"
typedef struct NvmeAsyncEvent {
diff --git a/hw/block/onenand.c b/hw/block/onenand.c
index ed77f859e9..0cb8d7fa13 100644
--- a/hw/block/onenand.c
+++ b/hw/block/onenand.c
@@ -25,9 +25,7 @@
#include "hw/block/flash.h"
#include "hw/irq.h"
#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
#include "exec/memory.h"
-#include "exec/address-spaces.h"
#include "hw/sysbus.h"
#include "qemu/error-report.h"
diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
index 2e8284001d..e4b5b3c273 100644
--- a/hw/block/pflash_cfi01.c
+++ b/hw/block/pflash_cfi01.c
@@ -43,7 +43,6 @@
#include "qapi/error.h"
#include "qemu/timer.h"
#include "qemu/bitops.h"
-#include "exec/address-spaces.h"
#include "qemu/host-utils.h"
#include "qemu/log.h"
#include "hw/sysbus.h"
diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index 75d1ae1026..a8b3f7f978 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -41,7 +41,6 @@
#include "qapi/error.h"
#include "qemu/timer.h"
#include "sysemu/block-backend.h"
-#include "exec/address-spaces.h"
#include "qemu/host-utils.h"
#include "hw/sysbus.h"
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index b1532e4e91..50b5c869e3 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -18,7 +18,6 @@
#include "qemu/error-report.h"
#include "trace.h"
#include "hw/block/block.h"
-#include "sysemu/block-backend.h"
#include "sysemu/blockdev.h"
#include "hw/virtio/virtio-blk.h"
#include "dataplane/virtio-blk.h"
diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c
index f74fcd42d1..9fbc0cdb87 100644
--- a/hw/block/xen_disk.c
+++ b/hw/block/xen_disk.c
@@ -36,27 +36,9 @@
/* ------------------------------------------------------------- */
-static int batch_maps = 0;
-
-/* ------------------------------------------------------------- */
-
#define BLOCK_SIZE 512
#define IOCB_COUNT (BLKIF_MAX_SEGMENTS_PER_REQUEST + 2)
-struct PersistentGrant {
- void *page;
- struct XenBlkDev *blkdev;
-};
-
-typedef struct PersistentGrant PersistentGrant;
-
-struct PersistentRegion {
- void *addr;
- int num;
-};
-
-typedef struct PersistentRegion PersistentRegion;
-
struct ioreq {
blkif_request_t req;
int16_t status;
@@ -64,16 +46,9 @@ struct ioreq {
/* parsed request */
off_t start;
QEMUIOVector v;
+ void *buf;
+ size_t size;
int presync;
- uint8_t mapped;
-
- /* grant mapping */
- uint32_t domids[BLKIF_MAX_SEGMENTS_PER_REQUEST];
- uint32_t refs[BLKIF_MAX_SEGMENTS_PER_REQUEST];
- int prot;
- void *page[BLKIF_MAX_SEGMENTS_PER_REQUEST];
- void *pages;
- int num_unmap;
/* aio status */
int aio_inflight;
@@ -104,7 +79,6 @@ struct XenBlkDev {
int protocol;
blkif_back_rings_t rings;
int more_work;
- int cnt_map;
/* request lists */
QLIST_HEAD(inflight_head, ioreq) inflight;
@@ -115,13 +89,7 @@ struct XenBlkDev {
int requests_finished;
unsigned int max_requests;
- /* Persistent grants extension */
gboolean feature_discard;
- gboolean feature_persistent;
- GTree *persistent_gnts;
- GSList *persistent_regions;
- unsigned int persistent_gnt_count;
- unsigned int max_grants;
/* qemu block driver */
DriveInfo *dinfo;
@@ -139,14 +107,9 @@ static void ioreq_reset(struct ioreq *ioreq)
memset(&ioreq->req, 0, sizeof(ioreq->req));
ioreq->status = 0;
ioreq->start = 0;
+ ioreq->buf = NULL;
+ ioreq->size = 0;
ioreq->presync = 0;
- ioreq->mapped = 0;
-
- memset(ioreq->domids, 0, sizeof(ioreq->domids));
- memset(ioreq->refs, 0, sizeof(ioreq->refs));
- ioreq->prot = 0;
- memset(ioreq->page, 0, sizeof(ioreq->page));
- ioreq->pages = NULL;
ioreq->aio_inflight = 0;
ioreq->aio_errors = 0;
@@ -158,46 +121,6 @@ static void ioreq_reset(struct ioreq *ioreq)
qemu_iovec_reset(&ioreq->v);
}
-static gint int_cmp(gconstpointer a, gconstpointer b, gpointer user_data)
-{
- uint ua = GPOINTER_TO_UINT(a);
- uint ub = GPOINTER_TO_UINT(b);
- return (ua > ub) - (ua < ub);
-}
-
-static void destroy_grant(gpointer pgnt)
-{
- PersistentGrant *grant = pgnt;
- xengnttab_handle *gnt = grant->blkdev->xendev.gnttabdev;
-
- if (xengnttab_unmap(gnt, grant->page, 1) != 0) {
- xen_pv_printf(&grant->blkdev->xendev, 0,
- "xengnttab_unmap failed: %s\n",
- strerror(errno));
- }
- grant->blkdev->persistent_gnt_count--;
- xen_pv_printf(&grant->blkdev->xendev, 3,
- "unmapped grant %p\n", grant->page);
- g_free(grant);
-}
-
-static void remove_persistent_region(gpointer data, gpointer dev)
-{
- PersistentRegion *region = data;
- struct XenBlkDev *blkdev = dev;
- xengnttab_handle *gnt = blkdev->xendev.gnttabdev;
-
- if (xengnttab_unmap(gnt, region->addr, region->num) != 0) {
- xen_pv_printf(&blkdev->xendev, 0,
- "xengnttab_unmap region %p failed: %s\n",
- region->addr, strerror(errno));
- }
- xen_pv_printf(&blkdev->xendev, 3,
- "unmapped grant region %p with %d pages\n",
- region->addr, region->num);
- g_free(region);
-}
-
static struct ioreq *ioreq_start(struct XenBlkDev *blkdev)
{
struct ioreq *ioreq = NULL;
@@ -210,7 +133,7 @@ static struct ioreq *ioreq_start(struct XenBlkDev *blkdev)
ioreq = g_malloc0(sizeof(*ioreq));
ioreq->blkdev = blkdev;
blkdev->requests_total++;
- qemu_iovec_init(&ioreq->v, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+ qemu_iovec_init(&ioreq->v, 1);
} else {
/* get one from freelist */
ioreq = QLIST_FIRST(&blkdev->freelist);
@@ -255,17 +178,16 @@ static void ioreq_release(struct ioreq *ioreq, bool finish)
static int ioreq_parse(struct ioreq *ioreq)
{
struct XenBlkDev *blkdev = ioreq->blkdev;
- uintptr_t mem;
+ struct XenDevice *xendev = &blkdev->xendev;
size_t len;
int i;
- xen_pv_printf(&blkdev->xendev, 3,
+ xen_pv_printf(xendev, 3,
"op %d, nr %d, handle %d, id %" PRId64 ", sector %" PRId64 "\n",
ioreq->req.operation, ioreq->req.nr_segments,
ioreq->req.handle, ioreq->req.id, ioreq->req.sector_number);
switch (ioreq->req.operation) {
case BLKIF_OP_READ:
- ioreq->prot = PROT_WRITE; /* to memory */
break;
case BLKIF_OP_FLUSH_DISKCACHE:
ioreq->presync = 1;
@@ -274,45 +196,40 @@ static int ioreq_parse(struct ioreq *ioreq)
}
/* fall through */
case BLKIF_OP_WRITE:
- ioreq->prot = PROT_READ; /* from memory */
break;
case BLKIF_OP_DISCARD:
return 0;
default:
- xen_pv_printf(&blkdev->xendev, 0, "error: unknown operation (%d)\n",
+ xen_pv_printf(xendev, 0, "error: unknown operation (%d)\n",
ioreq->req.operation);
goto err;
};
if (ioreq->req.operation != BLKIF_OP_READ && blkdev->mode[0] != 'w') {
- xen_pv_printf(&blkdev->xendev, 0, "error: write req for ro device\n");
+ xen_pv_printf(xendev, 0, "error: write req for ro device\n");
goto err;
}
ioreq->start = ioreq->req.sector_number * blkdev->file_blk;
for (i = 0; i < ioreq->req.nr_segments; i++) {
if (i == BLKIF_MAX_SEGMENTS_PER_REQUEST) {
- xen_pv_printf(&blkdev->xendev, 0, "error: nr_segments too big\n");
+ xen_pv_printf(xendev, 0, "error: nr_segments too big\n");
goto err;
}
if (ioreq->req.seg[i].first_sect > ioreq->req.seg[i].last_sect) {
- xen_pv_printf(&blkdev->xendev, 0, "error: first > last sector\n");
+ xen_pv_printf(xendev, 0, "error: first > last sector\n");
goto err;
}
if (ioreq->req.seg[i].last_sect * BLOCK_SIZE >= XC_PAGE_SIZE) {
- xen_pv_printf(&blkdev->xendev, 0, "error: page crossing\n");
+ xen_pv_printf(xendev, 0, "error: page crossing\n");
goto err;
}
- ioreq->domids[i] = blkdev->xendev.dom;
- ioreq->refs[i] = ioreq->req.seg[i].gref;
-
- mem = ioreq->req.seg[i].first_sect * blkdev->file_blk;
len = (ioreq->req.seg[i].last_sect - ioreq->req.seg[i].first_sect + 1) * blkdev->file_blk;
- qemu_iovec_add(&ioreq->v, (void*)mem, len);
+ ioreq->size += len;
}
- if (ioreq->start + ioreq->v.size > blkdev->file_size) {
- xen_pv_printf(&blkdev->xendev, 0, "error: access beyond end of file\n");
+ if (ioreq->start + ioreq->size > blkdev->file_size) {
+ xen_pv_printf(xendev, 0, "error: access beyond end of file\n");
goto err;
}
return 0;
@@ -322,279 +239,48 @@ err:
return -1;
}
-static void ioreq_unmap(struct ioreq *ioreq)
-{
- xengnttab_handle *gnt = ioreq->blkdev->xendev.gnttabdev;
- int i;
-
- if (ioreq->num_unmap == 0 || ioreq->mapped == 0) {
- return;
- }
- if (batch_maps) {
- if (!ioreq->pages) {
- return;
- }
- if (xengnttab_unmap(gnt, ioreq->pages, ioreq->num_unmap) != 0) {
- xen_pv_printf(&ioreq->blkdev->xendev, 0,
- "xengnttab_unmap failed: %s\n",
- strerror(errno));
- }
- ioreq->blkdev->cnt_map -= ioreq->num_unmap;
- ioreq->pages = NULL;
- } else {
- for (i = 0; i < ioreq->num_unmap; i++) {
- if (!ioreq->page[i]) {
- continue;
- }
- if (xengnttab_unmap(gnt, ioreq->page[i], 1) != 0) {
- xen_pv_printf(&ioreq->blkdev->xendev, 0,
- "xengnttab_unmap failed: %s\n",
- strerror(errno));
- }
- ioreq->blkdev->cnt_map--;
- ioreq->page[i] = NULL;
- }
- }
- ioreq->mapped = 0;
-}
-
-static int ioreq_map(struct ioreq *ioreq)
-{
- xengnttab_handle *gnt = ioreq->blkdev->xendev.gnttabdev;
- uint32_t domids[BLKIF_MAX_SEGMENTS_PER_REQUEST];
- uint32_t refs[BLKIF_MAX_SEGMENTS_PER_REQUEST];
- void *page[BLKIF_MAX_SEGMENTS_PER_REQUEST];
- int i, j, new_maps = 0;
- PersistentGrant *grant;
- PersistentRegion *region;
- /* domids and refs variables will contain the information necessary
- * to map the grants that are needed to fulfill this request.
- *
- * After mapping the needed grants, the page array will contain the
- * memory address of each granted page in the order specified in ioreq
- * (disregarding if it's a persistent grant or not).
- */
-
- if (ioreq->v.niov == 0 || ioreq->mapped == 1) {
- return 0;
- }
- if (ioreq->blkdev->feature_persistent) {
- for (i = 0; i < ioreq->v.niov; i++) {
- grant = g_tree_lookup(ioreq->blkdev->persistent_gnts,
- GUINT_TO_POINTER(ioreq->refs[i]));
-
- if (grant != NULL) {
- page[i] = grant->page;
- xen_pv_printf(&ioreq->blkdev->xendev, 3,
- "using persistent-grant %" PRIu32 "\n",
- ioreq->refs[i]);
- } else {
- /* Add the grant to the list of grants that
- * should be mapped
- */
- domids[new_maps] = ioreq->domids[i];
- refs[new_maps] = ioreq->refs[i];
- page[i] = NULL;
- new_maps++;
- }
- }
- /* Set the protection to RW, since grants may be reused later
- * with a different protection than the one needed for this request
- */
- ioreq->prot = PROT_WRITE | PROT_READ;
- } else {
- /* All grants in the request should be mapped */
- memcpy(refs, ioreq->refs, sizeof(refs));
- memcpy(domids, ioreq->domids, sizeof(domids));
- memset(page, 0, sizeof(page));
- new_maps = ioreq->v.niov;
- }
-
- if (batch_maps && new_maps) {
- ioreq->pages = xengnttab_map_grant_refs
- (gnt, new_maps, domids, refs, ioreq->prot);
- if (ioreq->pages == NULL) {
- xen_pv_printf(&ioreq->blkdev->xendev, 0,
- "can't map %d grant refs (%s, %d maps)\n",
- new_maps, strerror(errno), ioreq->blkdev->cnt_map);
- return -1;
- }
- for (i = 0, j = 0; i < ioreq->v.niov; i++) {
- if (page[i] == NULL) {
- page[i] = ioreq->pages + (j++) * XC_PAGE_SIZE;
- }
- }
- ioreq->blkdev->cnt_map += new_maps;
- } else if (new_maps) {
- for (i = 0; i < new_maps; i++) {
- ioreq->page[i] = xengnttab_map_grant_ref
- (gnt, domids[i], refs[i], ioreq->prot);
- if (ioreq->page[i] == NULL) {
- xen_pv_printf(&ioreq->blkdev->xendev, 0,
- "can't map grant ref %d (%s, %d maps)\n",
- refs[i], strerror(errno), ioreq->blkdev->cnt_map);
- ioreq->mapped = 1;
- ioreq_unmap(ioreq);
- return -1;
- }
- ioreq->blkdev->cnt_map++;
- }
- for (i = 0, j = 0; i < ioreq->v.niov; i++) {
- if (page[i] == NULL) {
- page[i] = ioreq->page[j++];
- }
- }
- }
- if (ioreq->blkdev->feature_persistent && new_maps != 0 &&
- (!batch_maps || (ioreq->blkdev->persistent_gnt_count + new_maps <=
- ioreq->blkdev->max_grants))) {
- /*
- * If we are using persistent grants and batch mappings only
- * add the new maps to the list of persistent grants if the whole
- * area can be persistently mapped.
- */
- if (batch_maps) {
- region = g_malloc0(sizeof(*region));
- region->addr = ioreq->pages;
- region->num = new_maps;
- ioreq->blkdev->persistent_regions = g_slist_append(
- ioreq->blkdev->persistent_regions,
- region);
- }
- while ((ioreq->blkdev->persistent_gnt_count < ioreq->blkdev->max_grants)
- && new_maps) {
- /* Go through the list of newly mapped grants and add as many
- * as possible to the list of persistently mapped grants.
- *
- * Since we start at the end of ioreq->page(s), we only need
- * to decrease new_maps to prevent this granted pages from
- * being unmapped in ioreq_unmap.
- */
- grant = g_malloc0(sizeof(*grant));
- new_maps--;
- if (batch_maps) {
- grant->page = ioreq->pages + (new_maps) * XC_PAGE_SIZE;
- } else {
- grant->page = ioreq->page[new_maps];
- }
- grant->blkdev = ioreq->blkdev;
- xen_pv_printf(&ioreq->blkdev->xendev, 3,
- "adding grant %" PRIu32 " page: %p\n",
- refs[new_maps], grant->page);
- g_tree_insert(ioreq->blkdev->persistent_gnts,
- GUINT_TO_POINTER(refs[new_maps]),
- grant);
- ioreq->blkdev->persistent_gnt_count++;
- }
- assert(!batch_maps || new_maps == 0);
- }
- for (i = 0; i < ioreq->v.niov; i++) {
- ioreq->v.iov[i].iov_base += (uintptr_t)page[i];
- }
- ioreq->mapped = 1;
- ioreq->num_unmap = new_maps;
- return 0;
-}
-
-#if CONFIG_XEN_CTRL_INTERFACE_VERSION >= 40800
-
-static void ioreq_free_copy_buffers(struct ioreq *ioreq)
-{
- int i;
-
- for (i = 0; i < ioreq->v.niov; i++) {
- ioreq->page[i] = NULL;
- }
-
- qemu_vfree(ioreq->pages);
-}
-
-static int ioreq_init_copy_buffers(struct ioreq *ioreq)
-{
- int i;
-
- if (ioreq->v.niov == 0) {
- return 0;
- }
-
- ioreq->pages = qemu_memalign(XC_PAGE_SIZE, ioreq->v.niov * XC_PAGE_SIZE);
-
- for (i = 0; i < ioreq->v.niov; i++) {
- ioreq->page[i] = ioreq->pages + i * XC_PAGE_SIZE;
- ioreq->v.iov[i].iov_base = ioreq->page[i];
- }
-
- return 0;
-}
-
static int ioreq_grant_copy(struct ioreq *ioreq)
{
- xengnttab_handle *gnt = ioreq->blkdev->xendev.gnttabdev;
- xengnttab_grant_copy_segment_t segs[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+ struct XenBlkDev *blkdev = ioreq->blkdev;
+ struct XenDevice *xendev = &blkdev->xendev;
+ XenGrantCopySegment segs[BLKIF_MAX_SEGMENTS_PER_REQUEST];
int i, count, rc;
- int64_t file_blk = ioreq->blkdev->file_blk;
+ int64_t file_blk = blkdev->file_blk;
+ bool to_domain = (ioreq->req.operation == BLKIF_OP_READ);
+ void *virt = ioreq->buf;
- if (ioreq->v.niov == 0) {
+ if (ioreq->req.nr_segments == 0) {
return 0;
}
- count = ioreq->v.niov;
+ count = ioreq->req.nr_segments;
for (i = 0; i < count; i++) {
- if (ioreq->req.operation == BLKIF_OP_READ) {
- segs[i].flags = GNTCOPY_dest_gref;
- segs[i].dest.foreign.ref = ioreq->refs[i];
- segs[i].dest.foreign.domid = ioreq->domids[i];
+ if (to_domain) {
+ segs[i].dest.foreign.ref = ioreq->req.seg[i].gref;
segs[i].dest.foreign.offset = ioreq->req.seg[i].first_sect * file_blk;
- segs[i].source.virt = ioreq->v.iov[i].iov_base;
+ segs[i].source.virt = virt;
} else {
- segs[i].flags = GNTCOPY_source_gref;
- segs[i].source.foreign.ref = ioreq->refs[i];
- segs[i].source.foreign.domid = ioreq->domids[i];
+ segs[i].source.foreign.ref = ioreq->req.seg[i].gref;
segs[i].source.foreign.offset = ioreq->req.seg[i].first_sect * file_blk;
- segs[i].dest.virt = ioreq->v.iov[i].iov_base;
+ segs[i].dest.virt = virt;
}
segs[i].len = (ioreq->req.seg[i].last_sect
- ioreq->req.seg[i].first_sect + 1) * file_blk;
+ virt += segs[i].len;
}
- rc = xengnttab_grant_copy(gnt, count, segs);
+ rc = xen_be_copy_grant_refs(xendev, to_domain, segs, count);
if (rc) {
- xen_pv_printf(&ioreq->blkdev->xendev, 0,
+ xen_pv_printf(xendev, 0,
"failed to copy data %d\n", rc);
ioreq->aio_errors++;
return -1;
}
- for (i = 0; i < count; i++) {
- if (segs[i].status != GNTST_okay) {
- xen_pv_printf(&ioreq->blkdev->xendev, 3,
- "failed to copy data %d for gref %d, domid %d\n",
- segs[i].status, ioreq->refs[i], ioreq->domids[i]);
- ioreq->aio_errors++;
- rc = -1;
- }
- }
-
return rc;
}
-#else
-static void ioreq_free_copy_buffers(struct ioreq *ioreq)
-{
- abort();
-}
-
-static int ioreq_init_copy_buffers(struct ioreq *ioreq)
-{
- abort();
-}
-
-static int ioreq_grant_copy(struct ioreq *ioreq)
-{
- abort();
-}
-#endif
static int ioreq_runio_qemu_aio(struct ioreq *ioreq);
@@ -602,11 +288,12 @@ static void qemu_aio_complete(void *opaque, int ret)
{
struct ioreq *ioreq = opaque;
struct XenBlkDev *blkdev = ioreq->blkdev;
+ struct XenDevice *xendev = &blkdev->xendev;
aio_context_acquire(blkdev->ctx);
if (ret != 0) {
- xen_pv_printf(&blkdev->xendev, 0, "%s I/O error\n",
+ xen_pv_printf(xendev, 0, "%s I/O error\n",
ioreq->req.operation == BLKIF_OP_READ ? "read" : "write");
ioreq->aio_errors++;
}
@@ -621,32 +308,28 @@ static void qemu_aio_complete(void *opaque, int ret)
goto done;
}
- if (xen_feature_grant_copy) {
- switch (ioreq->req.operation) {
- case BLKIF_OP_READ:
- /* in case of failure ioreq->aio_errors is increased */
- if (ret == 0) {
- ioreq_grant_copy(ioreq);
- }
- ioreq_free_copy_buffers(ioreq);
- break;
- case BLKIF_OP_WRITE:
- case BLKIF_OP_FLUSH_DISKCACHE:
- if (!ioreq->req.nr_segments) {
- break;
- }
- ioreq_free_copy_buffers(ioreq);
- break;
- default:
+ switch (ioreq->req.operation) {
+ case BLKIF_OP_READ:
+ /* in case of failure ioreq->aio_errors is increased */
+ if (ret == 0) {
+ ioreq_grant_copy(ioreq);
+ }
+ qemu_vfree(ioreq->buf);
+ break;
+ case BLKIF_OP_WRITE:
+ case BLKIF_OP_FLUSH_DISKCACHE:
+ if (!ioreq->req.nr_segments) {
break;
}
+ qemu_vfree(ioreq->buf);
+ break;
+ default:
+ break;
}
ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
- if (!xen_feature_grant_copy) {
- ioreq_unmap(ioreq);
- }
ioreq_finish(ioreq);
+
switch (ioreq->req.operation) {
case BLKIF_OP_WRITE:
case BLKIF_OP_FLUSH_DISKCACHE:
@@ -706,18 +389,13 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
{
struct XenBlkDev *blkdev = ioreq->blkdev;
- if (xen_feature_grant_copy) {
- ioreq_init_copy_buffers(ioreq);
- if (ioreq->req.nr_segments && (ioreq->req.operation == BLKIF_OP_WRITE ||
- ioreq->req.operation == BLKIF_OP_FLUSH_DISKCACHE) &&
- ioreq_grant_copy(ioreq)) {
- ioreq_free_copy_buffers(ioreq);
- goto err;
- }
- } else {
- if (ioreq->req.nr_segments && ioreq_map(ioreq)) {
- goto err;
- }
+ ioreq->buf = qemu_memalign(XC_PAGE_SIZE, ioreq->size);
+ if (ioreq->req.nr_segments &&
+ (ioreq->req.operation == BLKIF_OP_WRITE ||
+ ioreq->req.operation == BLKIF_OP_FLUSH_DISKCACHE) &&
+ ioreq_grant_copy(ioreq)) {
+ qemu_vfree(ioreq->buf);
+ goto err;
}
ioreq->aio_inflight++;
@@ -728,6 +406,7 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
switch (ioreq->req.operation) {
case BLKIF_OP_READ:
+ qemu_iovec_add(&ioreq->v, ioreq->buf, ioreq->size);
block_acct_start(blk_get_stats(blkdev->blk), &ioreq->acct,
ioreq->v.size, BLOCK_ACCT_READ);
ioreq->aio_inflight++;
@@ -740,6 +419,7 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
break;
}
+ qemu_iovec_add(&ioreq->v, ioreq->buf, ioreq->size);
block_acct_start(blk_get_stats(blkdev->blk), &ioreq->acct,
ioreq->v.size,
ioreq->req.operation == BLKIF_OP_WRITE ?
@@ -758,9 +438,6 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
}
default:
/* unknown operation (shouldn't happen -- parse catches this) */
- if (!xen_feature_grant_copy) {
- ioreq_unmap(ioreq);
- }
goto err;
}
@@ -946,24 +623,21 @@ static void blk_alloc(struct XenDevice *xendev)
blkdev->ctx = iothread_get_aio_context(blkdev->iothread);
blkdev->bh = aio_bh_new(blkdev->ctx, blk_bh, blkdev);
-
- if (xen_mode != XEN_EMULATE) {
- batch_maps = 1;
- }
}
static void blk_parse_discard(struct XenBlkDev *blkdev)
{
+ struct XenDevice *xendev = &blkdev->xendev;
int enable;
blkdev->feature_discard = true;
- if (xenstore_read_be_int(&blkdev->xendev, "discard-enable", &enable) == 0) {
+ if (xenstore_read_be_int(xendev, "discard-enable", &enable) == 0) {
blkdev->feature_discard = !!enable;
}
if (blkdev->feature_discard) {
- xenstore_write_be_int(&blkdev->xendev, "feature-discard", 1);
+ xenstore_write_be_int(xendev, "feature-discard", 1);
}
}
@@ -978,7 +652,7 @@ static int blk_init(struct XenDevice *xendev)
/* read xenstore entries */
if (blkdev->params == NULL) {
char *h = NULL;
- blkdev->params = xenstore_read_be_str(&blkdev->xendev, "params");
+ blkdev->params = xenstore_read_be_str(xendev, "params");
if (blkdev->params != NULL) {
h = strchr(blkdev->params, ':');
}
@@ -998,18 +672,18 @@ static int blk_init(struct XenDevice *xendev)
blkdev->fileproto = "vpc";
}
if (blkdev->mode == NULL) {
- blkdev->mode = xenstore_read_be_str(&blkdev->xendev, "mode");
+ blkdev->mode = xenstore_read_be_str(xendev, "mode");
}
if (blkdev->type == NULL) {
- blkdev->type = xenstore_read_be_str(&blkdev->xendev, "type");
+ blkdev->type = xenstore_read_be_str(xendev, "type");
}
if (blkdev->dev == NULL) {
- blkdev->dev = xenstore_read_be_str(&blkdev->xendev, "dev");
+ blkdev->dev = xenstore_read_be_str(xendev, "dev");
}
if (blkdev->devtype == NULL) {
- blkdev->devtype = xenstore_read_be_str(&blkdev->xendev, "device-type");
+ blkdev->devtype = xenstore_read_be_str(xendev, "device-type");
}
- directiosafe = xenstore_read_be_str(&blkdev->xendev, "direct-io-safe");
+ directiosafe = xenstore_read_be_str(xendev, "direct-io-safe");
blkdev->directiosafe = (directiosafe && atoi(directiosafe));
/* do we have all we need? */
@@ -1032,18 +706,13 @@ static int blk_init(struct XenDevice *xendev)
blkdev->file_blk = BLOCK_SIZE;
- xen_pv_printf(&blkdev->xendev, 3, "grant copy operation %s\n",
- xen_feature_grant_copy ? "enabled" : "disabled");
-
/* fill info
* blk_connect supplies sector-size and sectors
*/
- xenstore_write_be_int(&blkdev->xendev, "feature-flush-cache", 1);
- xenstore_write_be_int(&blkdev->xendev, "feature-persistent",
- !xen_feature_grant_copy);
- xenstore_write_be_int(&blkdev->xendev, "info", info);
+ xenstore_write_be_int(xendev, "feature-flush-cache", 1);
+ xenstore_write_be_int(xendev, "info", info);
- xenstore_write_be_int(&blkdev->xendev, "max-ring-page-order",
+ xenstore_write_be_int(xendev, "max-ring-page-order",
MAX_RING_PAGE_ORDER);
blk_parse_discard(blkdev);
@@ -1067,25 +736,15 @@ out_error:
return -1;
}
-/*
- * We need to account for the grant allocations requiring contiguous
- * chunks; the worst case number would be
- * max_req * max_seg + (max_req - 1) * (max_seg - 1) + 1,
- * but in order to keep things simple just use
- * 2 * max_req * max_seg.
- */
-#define MAX_GRANTS(max_req, max_seg) (2 * (max_req) * (max_seg))
-
static int blk_connect(struct XenDevice *xendev)
{
struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
- int pers, index, qflags;
+ int index, qflags;
bool readonly = true;
bool writethrough = true;
int order, ring_ref;
unsigned int ring_size, max_grants;
unsigned int i;
- uint32_t *domids;
trace_xen_disk_connect(xendev->name);
@@ -1105,7 +764,7 @@ static int blk_connect(struct XenDevice *xendev)
}
/* init qemu block driver */
- index = (blkdev->xendev.dev - 202 * 256) / 16;
+ index = (xendev->dev - 202 * 256) / 16;
blkdev->dinfo = drive_get(IF_XEN, 0, index);
if (!blkdev->dinfo) {
Error *local_err = NULL;
@@ -1117,11 +776,11 @@ static int blk_connect(struct XenDevice *xendev)
}
/* setup via xenbus -> create new block driver instance */
- xen_pv_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
+ xen_pv_printf(xendev, 2, "create new bdrv (xenbus setup)\n");
blkdev->blk = blk_new_open(blkdev->filename, NULL, options,
qflags, &local_err);
if (!blkdev->blk) {
- xen_pv_printf(&blkdev->xendev, 0, "error: %s\n",
+ xen_pv_printf(xendev, 0, "error: %s\n",
error_get_pretty(local_err));
error_free(local_err);
return -1;
@@ -1129,11 +788,11 @@ static int blk_connect(struct XenDevice *xendev)
blk_set_enable_write_cache(blkdev->blk, !writethrough);
} else {
/* setup via qemu cmdline -> already setup for us */
- xen_pv_printf(&blkdev->xendev, 2,
+ xen_pv_printf(xendev, 2,
"get configured bdrv (cmdline setup)\n");
blkdev->blk = blk_by_legacy_dinfo(blkdev->dinfo);
if (blk_is_read_only(blkdev->blk) && !readonly) {
- xen_pv_printf(&blkdev->xendev, 0, "Unexpected read-only drive");
+ xen_pv_printf(xendev, 0, "Unexpected read-only drive");
blkdev->blk = NULL;
return -1;
}
@@ -1146,7 +805,7 @@ static int blk_connect(struct XenDevice *xendev)
if (blkdev->file_size < 0) {
BlockDriverState *bs = blk_bs(blkdev->blk);
const char *drv_name = bs ? bdrv_get_format_name(bs) : NULL;
- xen_pv_printf(&blkdev->xendev, 1, "blk_getlength: %d (%s) | drv %s\n",
+ xen_pv_printf(xendev, 1, "blk_getlength: %d (%s) | drv %s\n",
(int)blkdev->file_size, strerror(-blkdev->file_size),
drv_name ?: "-");
blkdev->file_size = 0;
@@ -1158,15 +817,15 @@ static int blk_connect(struct XenDevice *xendev)
blkdev->file_size, blkdev->file_size >> 20);
/* Fill in number of sector size and number of sectors */
- xenstore_write_be_int(&blkdev->xendev, "sector-size", blkdev->file_blk);
- xenstore_write_be_int64(&blkdev->xendev, "sectors",
+ xenstore_write_be_int(xendev, "sector-size", blkdev->file_blk);
+ xenstore_write_be_int64(xendev, "sectors",
blkdev->file_size / blkdev->file_blk);
- if (xenstore_read_fe_int(&blkdev->xendev, "ring-page-order",
+ if (xenstore_read_fe_int(xendev, "ring-page-order",
&order) == -1) {
blkdev->nr_ring_ref = 1;
- if (xenstore_read_fe_int(&blkdev->xendev, "ring-ref",
+ if (xenstore_read_fe_int(xendev, "ring-ref",
&ring_ref) == -1) {
return -1;
}
@@ -1183,7 +842,7 @@ static int blk_connect(struct XenDevice *xendev)
return -1;
}
- if (xenstore_read_fe_int(&blkdev->xendev, key,
+ if (xenstore_read_fe_int(xendev, key,
&ring_ref) == -1) {
g_free(key);
return -1;
@@ -1198,23 +857,18 @@ static int blk_connect(struct XenDevice *xendev)
return -1;
}
- if (xenstore_read_fe_int(&blkdev->xendev, "event-channel",
- &blkdev->xendev.remote_port) == -1) {
+ if (xenstore_read_fe_int(xendev, "event-channel",
+ &xendev->remote_port) == -1) {
return -1;
}
- if (xenstore_read_fe_int(&blkdev->xendev, "feature-persistent", &pers)) {
- blkdev->feature_persistent = FALSE;
- } else {
- blkdev->feature_persistent = !!pers;
- }
- if (!blkdev->xendev.protocol) {
+ if (!xendev->protocol) {
blkdev->protocol = BLKIF_PROTOCOL_NATIVE;
- } else if (strcmp(blkdev->xendev.protocol, XEN_IO_PROTO_ABI_NATIVE) == 0) {
+ } else if (strcmp(xendev->protocol, XEN_IO_PROTO_ABI_NATIVE) == 0) {
blkdev->protocol = BLKIF_PROTOCOL_NATIVE;
- } else if (strcmp(blkdev->xendev.protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
+ } else if (strcmp(xendev->protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
blkdev->protocol = BLKIF_PROTOCOL_X86_32;
- } else if (strcmp(blkdev->xendev.protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
+ } else if (strcmp(xendev->protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
blkdev->protocol = BLKIF_PROTOCOL_X86_64;
} else {
blkdev->protocol = BLKIF_PROTOCOL_NATIVE;
@@ -1241,43 +895,17 @@ static int blk_connect(struct XenDevice *xendev)
return -1;
}
- /* Calculate the maximum number of grants needed by ioreqs */
- max_grants = MAX_GRANTS(blkdev->max_requests,
- BLKIF_MAX_SEGMENTS_PER_REQUEST);
/* Add on the number needed for the ring pages */
- max_grants += blkdev->nr_ring_ref;
-
- blkdev->xendev.gnttabdev = xengnttab_open(NULL, 0);
- if (blkdev->xendev.gnttabdev == NULL) {
- xen_pv_printf(xendev, 0, "xengnttab_open failed: %s\n",
- strerror(errno));
- return -1;
- }
- if (xengnttab_set_max_grants(blkdev->xendev.gnttabdev, max_grants)) {
- xen_pv_printf(xendev, 0, "xengnttab_set_max_grants failed: %s\n",
- strerror(errno));
- return -1;
- }
-
- domids = g_new0(uint32_t, blkdev->nr_ring_ref);
- for (i = 0; i < blkdev->nr_ring_ref; i++) {
- domids[i] = blkdev->xendev.dom;
- }
-
- blkdev->sring = xengnttab_map_grant_refs(blkdev->xendev.gnttabdev,
- blkdev->nr_ring_ref,
- domids,
- blkdev->ring_ref,
- PROT_READ | PROT_WRITE);
-
- g_free(domids);
+ max_grants = blkdev->nr_ring_ref;
+ xen_be_set_max_grant_refs(xendev, max_grants);
+ blkdev->sring = xen_be_map_grant_refs(xendev, blkdev->ring_ref,
+ blkdev->nr_ring_ref,
+ PROT_READ | PROT_WRITE);
if (!blkdev->sring) {
return -1;
}
- blkdev->cnt_map++;
-
switch (blkdev->protocol) {
case BLKIF_PROTOCOL_NATIVE:
{
@@ -1301,27 +929,14 @@ static int blk_connect(struct XenDevice *xendev)
}
}
- if (blkdev->feature_persistent) {
- /* Init persistent grants */
- blkdev->max_grants = blkdev->max_requests *
- BLKIF_MAX_SEGMENTS_PER_REQUEST;
- blkdev->persistent_gnts = g_tree_new_full((GCompareDataFunc)int_cmp,
- NULL, NULL,
- batch_maps ?
- (GDestroyNotify)g_free :
- (GDestroyNotify)destroy_grant);
- blkdev->persistent_regions = NULL;
- blkdev->persistent_gnt_count = 0;
- }
-
blk_set_aio_context(blkdev->blk, blkdev->ctx);
- xen_be_bind_evtchn(&blkdev->xendev);
+ xen_be_bind_evtchn(xendev);
- xen_pv_printf(&blkdev->xendev, 1, "ok: proto %s, nr-ring-ref %u, "
+ xen_pv_printf(xendev, 1, "ok: proto %s, nr-ring-ref %u, "
"remote port %d, local port %d\n",
- blkdev->xendev.protocol, blkdev->nr_ring_ref,
- blkdev->xendev.remote_port, blkdev->xendev.local_port);
+ xendev->protocol, blkdev->nr_ring_ref,
+ xendev->remote_port, xendev->local_port);
return 0;
}
@@ -1339,41 +954,15 @@ static void blk_disconnect(struct XenDevice *xendev)
blk_unref(blkdev->blk);
blkdev->blk = NULL;
}
- xen_pv_unbind_evtchn(&blkdev->xendev);
+ xen_pv_unbind_evtchn(xendev);
aio_context_release(blkdev->ctx);
if (blkdev->sring) {
- xengnttab_unmap(blkdev->xendev.gnttabdev, blkdev->sring,
- blkdev->nr_ring_ref);
- blkdev->cnt_map--;
+ xen_be_unmap_grant_refs(xendev, blkdev->sring,
+ blkdev->nr_ring_ref);
blkdev->sring = NULL;
}
-
- /*
- * Unmap persistent grants before switching to the closed state
- * so the frontend can free them.
- *
- * In the !batch_maps case g_tree_destroy will take care of unmapping
- * the grant, but in the batch_maps case we need to iterate over every
- * region in persistent_regions and unmap it.
- */
- if (blkdev->feature_persistent) {
- g_tree_destroy(blkdev->persistent_gnts);
- assert(batch_maps || blkdev->persistent_gnt_count == 0);
- if (batch_maps) {
- blkdev->persistent_gnt_count = 0;
- g_slist_foreach(blkdev->persistent_regions,
- (GFunc)remove_persistent_region, blkdev);
- g_slist_free(blkdev->persistent_regions);
- }
- blkdev->feature_persistent = false;
- }
-
- if (blkdev->xendev.gnttabdev) {
- xengnttab_close(blkdev->xendev.gnttabdev);
- blkdev->xendev.gnttabdev = NULL;
- }
}
static int blk_free(struct XenDevice *xendev)
@@ -1410,10 +999,11 @@ static void blk_event(struct XenDevice *xendev)
}
struct XenDevOps xen_blkdev_ops = {
+ .flags = DEVOPS_FLAG_NEED_GNTDEV,
.size = sizeof(struct XenBlkDev),
.alloc = blk_alloc,
.init = blk_init,
- .initialise = blk_connect,
+ .initialise = blk_connect,
.disconnect = blk_disconnect,
.event = blk_event,
.free = blk_free,
diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs
index 1b979100b7..b570531291 100644
--- a/hw/char/Makefile.objs
+++ b/hw/char/Makefile.objs
@@ -6,7 +6,7 @@ common-obj-$(CONFIG_PL011) += pl011.o
common-obj-$(CONFIG_SERIAL) += serial.o
common-obj-$(CONFIG_SERIAL_ISA) += serial-isa.o
common-obj-$(CONFIG_SERIAL_PCI) += serial-pci.o
-common-obj-$(CONFIG_VIRTIO) += virtio-console.o
+common-obj-$(CONFIG_VIRTIO_SERIAL) += virtio-console.o
common-obj-$(CONFIG_XILINX) += xilinx_uartlite.o
common-obj-$(CONFIG_XEN) += xen_console.o
common-obj-$(CONFIG_CADENCE) += cadence_uart.o
diff --git a/hw/char/mcf_uart.c b/hw/char/mcf_uart.c
index faae083e78..787f985db6 100644
--- a/hw/char/mcf_uart.c
+++ b/hw/char/mcf_uart.c
@@ -10,7 +10,6 @@
#include "hw/sysbus.h"
#include "hw/m68k/mcf.h"
#include "chardev/char-fe.h"
-#include "exec/address-spaces.h"
typedef struct {
SysBusDevice parent_obj;
diff --git a/hw/char/serial.c b/hw/char/serial.c
index 2c080c9862..605b0d02f9 100644
--- a/hw/char/serial.c
+++ b/hw/char/serial.c
@@ -28,7 +28,6 @@
#include "chardev/char-serial.h"
#include "qapi/error.h"
#include "qemu/timer.h"
-#include "exec/address-spaces.h"
#include "qemu/error-report.h"
//#define DEBUG_SERIAL
diff --git a/hw/char/sh_serial.c b/hw/char/sh_serial.c
index 835b5378a0..373a40595f 100644
--- a/hw/char/sh_serial.c
+++ b/hw/char/sh_serial.c
@@ -28,7 +28,6 @@
#include "hw/hw.h"
#include "hw/sh4/sh.h"
#include "chardev/char-fe.h"
-#include "exec/address-spaces.h"
#include "qapi/error.h"
//#define DEBUG_SERIAL
diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c
index bdfaa40ed3..8b4b4bf523 100644
--- a/hw/char/xen_console.c
+++ b/hw/char/xen_console.c
@@ -233,12 +233,11 @@ static int con_initialise(struct XenDevice *xendev)
if (!xendev->dev) {
xen_pfn_t mfn = con->ring_ref;
con->sring = xenforeignmemory_map(xen_fmem, con->xendev.dom,
- PROT_READ|PROT_WRITE,
+ PROT_READ | PROT_WRITE,
1, &mfn, NULL);
} else {
- con->sring = xengnttab_map_grant_ref(xendev->gnttabdev, con->xendev.dom,
- con->ring_ref,
- PROT_READ|PROT_WRITE);
+ con->sring = xen_be_map_grant_ref(xendev, con->ring_ref,
+ PROT_READ | PROT_WRITE);
}
if (!con->sring)
return -1;
@@ -267,7 +266,7 @@ static void con_disconnect(struct XenDevice *xendev)
if (!xendev->dev) {
xenforeignmemory_unmap(xen_fmem, con->sring, 1);
} else {
- xengnttab_unmap(xendev->gnttabdev, con->sring, 1);
+ xen_be_unmap_grant_ref(xendev, con->sring);
}
con->sring = NULL;
}
diff --git a/hw/core/loader-fit.c b/hw/core/loader-fit.c
index 0c4a7207f4..6387854b54 100644
--- a/hw/core/loader-fit.c
+++ b/hw/core/loader-fit.c
@@ -18,7 +18,6 @@
*/
#include "qemu/osdep.h"
-#include "exec/address-spaces.h"
#include "exec/memory.h"
#include "hw/loader.h"
#include "hw/loader-fit.h"
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 2040177664..617e5f8d75 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -737,7 +737,7 @@ static char *cpu_slot_to_string(const CPUArchId *cpu)
return g_string_free(s, false);
}
-static void machine_numa_finish_init(MachineState *machine)
+static void machine_numa_finish_cpu_init(MachineState *machine)
{
int i;
bool default_mapping;
@@ -792,7 +792,8 @@ void machine_run_board_init(MachineState *machine)
MachineClass *machine_class = MACHINE_GET_CLASS(machine);
if (nb_numa_nodes) {
- machine_numa_finish_init(machine);
+ numa_complete_configuration(machine);
+ machine_numa_finish_cpu_init(machine);
}
/* If the machine supports the valid_cpu_types check and the user
diff --git a/hw/core/platform-bus.c b/hw/core/platform-bus.c
index 807cb5ccda..e473a44746 100644
--- a/hw/core/platform-bus.c
+++ b/hw/core/platform-bus.c
@@ -21,7 +21,6 @@
#include "qemu/osdep.h"
#include "hw/platform-bus.h"
-#include "exec/address-spaces.h"
#include "qemu/error-report.h"
#include "sysemu/sysemu.h"
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index 5bbc2d98b5..989778ab7f 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -5,7 +5,6 @@
#include "hw/pci/pci.h"
#include "qapi/qmp/qerror.h"
#include "qemu/error-report.h"
-#include "sysemu/block-backend.h"
#include "hw/block/block.h"
#include "net/hub.h"
#include "qapi/visitor.h"
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index f6f92473b8..ffec461791 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -208,32 +208,6 @@ void device_listener_unregister(DeviceListener *listener)
QTAILQ_REMOVE(&device_listeners, listener, link);
}
-static void device_realize(DeviceState *dev, Error **errp)
-{
- DeviceClass *dc = DEVICE_GET_CLASS(dev);
-
- if (dc->init) {
- int rc = dc->init(dev);
- if (rc < 0) {
- error_setg(errp, "Device initialization failed.");
- return;
- }
- }
-}
-
-static void device_unrealize(DeviceState *dev, Error **errp)
-{
- DeviceClass *dc = DEVICE_GET_CLASS(dev);
-
- if (dc->exit) {
- int rc = dc->exit(dev);
- if (rc < 0) {
- error_setg(errp, "Device exit failed.");
- return;
- }
- }
-}
-
void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
int required_for_version)
{
@@ -1065,8 +1039,6 @@ static void device_class_init(ObjectClass *class, void *data)
DeviceClass *dc = DEVICE_CLASS(class);
class->unparent = device_unparent;
- dc->realize = device_realize;
- dc->unrealize = device_unrealize;
/* by default all devices were considered as hotpluggable,
* so with intent to check it in generic qdev_unplug() /
diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c
index 5d0887f499..ecfb0cfc0e 100644
--- a/hw/core/sysbus.c
+++ b/hw/core/sysbus.c
@@ -18,6 +18,7 @@
*/
#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "hw/sysbus.h"
#include "monitor/monitor.h"
#include "exec/address-spaces.h"
@@ -200,15 +201,18 @@ void sysbus_init_ioports(SysBusDevice *dev, uint32_t ioport, uint32_t size)
}
}
-static int sysbus_device_init(DeviceState *dev)
+/* TODO remove once all sysbus devices have been converted to realize */
+static void sysbus_realize(DeviceState *dev, Error **errp)
{
SysBusDevice *sd = SYS_BUS_DEVICE(dev);
SysBusDeviceClass *sbc = SYS_BUS_DEVICE_GET_CLASS(sd);
if (!sbc->init) {
- return 0;
+ return;
+ }
+ if (sbc->init(sd) < 0) {
+ error_setg(errp, "Device initialization failed");
}
- return sbc->init(sd);
}
DeviceState *sysbus_create_varargs(const char *name,
@@ -324,7 +328,7 @@ MemoryRegion *sysbus_address_space(SysBusDevice *dev)
static void sysbus_device_class_init(ObjectClass *klass, void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
- k->init = sysbus_device_init;
+ k->realize = sysbus_realize;
k->bus_type = TYPE_SYSTEM_BUS;
/*
* device_add plugs devices into a suitable bus. For "real" buses,
diff --git a/hw/cris/axis_dev88.c b/hw/cris/axis_dev88.c
index 409f3d581a..56ee398ee5 100644
--- a/hw/cris/axis_dev88.c
+++ b/hw/cris/axis_dev88.c
@@ -34,7 +34,6 @@
#include "hw/loader.h"
#include "elf.h"
#include "boot.h"
-#include "sysemu/block-backend.h"
#include "exec/address-spaces.h"
#include "sysemu/qtest.h"
#include "sysemu/sysemu.h"
diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs
index 11321e466b..b5d97ab26d 100644
--- a/hw/display/Makefile.objs
+++ b/hw/display/Makefile.objs
@@ -9,6 +9,7 @@ common-obj-$(CONFIG_SSD0323) += ssd0323.o
common-obj-$(CONFIG_XEN) += xenfb.o
common-obj-$(CONFIG_VGA_PCI) += vga-pci.o
+common-obj-$(CONFIG_VGA_PCI) += bochs-display.o
common-obj-$(CONFIG_VGA_ISA) += vga-isa.o
common-obj-$(CONFIG_VGA_ISA_MM) += vga-isa-mm.o
common-obj-$(CONFIG_VMWARE_VGA) += vmware_vga.o
@@ -35,8 +36,8 @@ obj-$(CONFIG_VGA) += vga.o
common-obj-$(CONFIG_QXL) += qxl.o qxl-logger.o qxl-render.o
-obj-$(CONFIG_VIRTIO) += virtio-gpu.o virtio-gpu-3d.o
-obj-$(CONFIG_VIRTIO_PCI) += virtio-gpu-pci.o
+obj-$(CONFIG_VIRTIO_GPU) += virtio-gpu.o virtio-gpu-3d.o
+obj-$(call land,$(CONFIG_VIRTIO_GPU),$(CONFIG_VIRTIO_PCI)) += virtio-gpu-pci.o
obj-$(CONFIG_VIRTIO_VGA) += virtio-vga.o
virtio-gpu.o-cflags := $(VIRGL_CFLAGS)
virtio-gpu.o-libs += $(VIRGL_LIBS)
diff --git a/hw/display/bochs-display.c b/hw/display/bochs-display.c
new file mode 100644
index 0000000000..c33524b558
--- /dev/null
+++ b/hw/display/bochs-display.c
@@ -0,0 +1,363 @@
+/*
+ * QEMU PCI bochs display adapter.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include "qemu/osdep.h"
+#include "hw/hw.h"
+#include "hw/pci/pci.h"
+#include "hw/display/bochs-vbe.h"
+
+#include "qapi/error.h"
+
+#include "ui/console.h"
+#include "ui/qemu-pixman.h"
+
+typedef struct BochsDisplayMode {
+ pixman_format_code_t format;
+ uint32_t bytepp;
+ uint32_t width;
+ uint32_t height;
+ uint32_t stride;
+ uint64_t offset;
+ uint64_t size;
+} BochsDisplayMode;
+
+typedef struct BochsDisplayState {
+ /* parent */
+ PCIDevice pci;
+
+ /* device elements */
+ QemuConsole *con;
+ MemoryRegion vram;
+ MemoryRegion mmio;
+ MemoryRegion vbe;
+ MemoryRegion qext;
+
+ /* device config */
+ uint64_t vgamem;
+
+ /* device registers */
+ uint16_t vbe_regs[VBE_DISPI_INDEX_NB];
+ bool big_endian_fb;
+
+ /* device state */
+ BochsDisplayMode mode;
+} BochsDisplayState;
+
+#define TYPE_BOCHS_DISPLAY "bochs-display"
+#define BOCHS_DISPLAY(obj) OBJECT_CHECK(BochsDisplayState, (obj), \
+ TYPE_BOCHS_DISPLAY)
+
+static const VMStateDescription vmstate_bochs_display = {
+ .name = "bochs-display",
+ .fields = (VMStateField[]) {
+ VMSTATE_PCI_DEVICE(pci, BochsDisplayState),
+ VMSTATE_UINT16_ARRAY(vbe_regs, BochsDisplayState, VBE_DISPI_INDEX_NB),
+ VMSTATE_BOOL(big_endian_fb, BochsDisplayState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static uint64_t bochs_display_vbe_read(void *ptr, hwaddr addr,
+ unsigned size)
+{
+ BochsDisplayState *s = ptr;
+ unsigned int index = addr >> 1;
+
+ switch (index) {
+ case VBE_DISPI_INDEX_ID:
+ return VBE_DISPI_ID5;
+ case VBE_DISPI_INDEX_VIDEO_MEMORY_64K:
+ return s->vgamem / (64 * 1024);
+ }
+
+ if (index >= ARRAY_SIZE(s->vbe_regs)) {
+ return -1;
+ }
+ return s->vbe_regs[index];
+}
+
+static void bochs_display_vbe_write(void *ptr, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ BochsDisplayState *s = ptr;
+ unsigned int index = addr >> 1;
+
+ if (index >= ARRAY_SIZE(s->vbe_regs)) {
+ return;
+ }
+ s->vbe_regs[index] = val;
+}
+
+static const MemoryRegionOps bochs_display_vbe_ops = {
+ .read = bochs_display_vbe_read,
+ .write = bochs_display_vbe_write,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 4,
+ .impl.min_access_size = 2,
+ .impl.max_access_size = 2,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static uint64_t bochs_display_qext_read(void *ptr, hwaddr addr,
+ unsigned size)
+{
+ BochsDisplayState *s = ptr;
+
+ switch (addr) {
+ case PCI_VGA_QEXT_REG_SIZE:
+ return PCI_VGA_QEXT_SIZE;
+ case PCI_VGA_QEXT_REG_BYTEORDER:
+ return s->big_endian_fb ?
+ PCI_VGA_QEXT_BIG_ENDIAN : PCI_VGA_QEXT_LITTLE_ENDIAN;
+ default:
+ return 0;
+ }
+}
+
+static void bochs_display_qext_write(void *ptr, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ BochsDisplayState *s = ptr;
+
+ switch (addr) {
+ case PCI_VGA_QEXT_REG_BYTEORDER:
+ if (val == PCI_VGA_QEXT_BIG_ENDIAN) {
+ s->big_endian_fb = true;
+ }
+ if (val == PCI_VGA_QEXT_LITTLE_ENDIAN) {
+ s->big_endian_fb = false;
+ }
+ break;
+ }
+}
+
+static const MemoryRegionOps bochs_display_qext_ops = {
+ .read = bochs_display_qext_read,
+ .write = bochs_display_qext_write,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static int bochs_display_get_mode(BochsDisplayState *s,
+ BochsDisplayMode *mode)
+{
+ uint16_t *vbe = s->vbe_regs;
+ uint32_t virt_width;
+
+ if (!(vbe[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
+ return -1;
+ }
+
+ memset(mode, 0, sizeof(*mode));
+ switch (vbe[VBE_DISPI_INDEX_BPP]) {
+ case 16:
+ /* best effort: support native endianess only */
+ mode->format = PIXMAN_r5g6b5;
+ mode->bytepp = 2;
+ case 32:
+ mode->format = s->big_endian_fb
+ ? PIXMAN_BE_x8r8g8b8
+ : PIXMAN_LE_x8r8g8b8;
+ mode->bytepp = 4;
+ break;
+ default:
+ return -1;
+ }
+
+ mode->width = vbe[VBE_DISPI_INDEX_XRES];
+ mode->height = vbe[VBE_DISPI_INDEX_YRES];
+ virt_width = vbe[VBE_DISPI_INDEX_VIRT_WIDTH];
+ if (virt_width < mode->width) {
+ virt_width = mode->width;
+ }
+ mode->stride = virt_width * mode->bytepp;
+ mode->size = (uint64_t)mode->stride * mode->height;
+ mode->offset = ((uint64_t)vbe[VBE_DISPI_INDEX_X_OFFSET] * mode->bytepp +
+ (uint64_t)vbe[VBE_DISPI_INDEX_Y_OFFSET] * mode->stride);
+
+ if (mode->width < 64 || mode->height < 64) {
+ return -1;
+ }
+ if (mode->offset + mode->size > s->vgamem) {
+ return -1;
+ }
+ return 0;
+}
+
+static void bochs_display_update(void *opaque)
+{
+ BochsDisplayState *s = opaque;
+ DirtyBitmapSnapshot *snap = NULL;
+ bool full_update = false;
+ BochsDisplayMode mode;
+ DisplaySurface *ds;
+ uint8_t *ptr;
+ bool dirty;
+ int y, ys, ret;
+
+ ret = bochs_display_get_mode(s, &mode);
+ if (ret < 0) {
+ /* no (valid) video mode */
+ return;
+ }
+
+ if (memcmp(&s->mode, &mode, sizeof(mode)) != 0) {
+ /* video mode switch */
+ s->mode = mode;
+ ptr = memory_region_get_ram_ptr(&s->vram);
+ ds = qemu_create_displaysurface_from(mode.width,
+ mode.height,
+ mode.format,
+ mode.stride,
+ ptr + mode.offset);
+ dpy_gfx_replace_surface(s->con, ds);
+ full_update = true;
+ }
+
+ if (full_update) {
+ dpy_gfx_update_full(s->con);
+ } else {
+ snap = memory_region_snapshot_and_clear_dirty(&s->vram,
+ mode.offset, mode.size,
+ DIRTY_MEMORY_VGA);
+ ys = -1;
+ for (y = 0; y < mode.height; y++) {
+ dirty = memory_region_snapshot_get_dirty(&s->vram, snap,
+ mode.offset + mode.stride * y,
+ mode.stride);
+ if (dirty && ys < 0) {
+ ys = y;
+ }
+ if (!dirty && ys >= 0) {
+ dpy_gfx_update(s->con, 0, ys,
+ mode.width, y - ys);
+ ys = -1;
+ }
+ }
+ if (ys >= 0) {
+ dpy_gfx_update(s->con, 0, ys,
+ mode.width, y - ys);
+ }
+ }
+}
+
+static const GraphicHwOps bochs_display_gfx_ops = {
+ .gfx_update = bochs_display_update,
+};
+
+static void bochs_display_realize(PCIDevice *dev, Error **errp)
+{
+ BochsDisplayState *s = BOCHS_DISPLAY(dev);
+ Object *obj = OBJECT(dev);
+ int ret;
+
+ s->con = graphic_console_init(DEVICE(dev), 0, &bochs_display_gfx_ops, s);
+
+ if (s->vgamem < (4 * 1024 * 1024)) {
+ error_setg(errp, "bochs-display: video memory too small");
+ }
+ if (s->vgamem > (256 * 1024 * 1024)) {
+ error_setg(errp, "bochs-display: video memory too big");
+ }
+ s->vgamem = pow2ceil(s->vgamem);
+
+ memory_region_init_ram(&s->vram, obj, "bochs-display-vram", s->vgamem,
+ &error_fatal);
+ memory_region_init_io(&s->vbe, obj, &bochs_display_vbe_ops, s,
+ "bochs dispi interface", PCI_VGA_BOCHS_SIZE);
+ memory_region_init_io(&s->qext, obj, &bochs_display_qext_ops, s,
+ "qemu extended regs", PCI_VGA_QEXT_SIZE);
+
+ memory_region_init(&s->mmio, obj, "bochs-display-mmio",
+ PCI_VGA_MMIO_SIZE);
+ memory_region_add_subregion(&s->mmio, PCI_VGA_BOCHS_OFFSET, &s->vbe);
+ memory_region_add_subregion(&s->mmio, PCI_VGA_QEXT_OFFSET, &s->qext);
+
+ pci_set_byte(&s->pci.config[PCI_REVISION_ID], 2);
+ pci_register_bar(&s->pci, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
+ pci_register_bar(&s->pci, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio);
+
+ if (pci_bus_is_express(pci_get_bus(dev))) {
+ dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
+ ret = pcie_endpoint_cap_init(dev, 0x80);
+ assert(ret > 0);
+ }
+
+ memory_region_set_log(&s->vram, true, DIRTY_MEMORY_VGA);
+}
+
+static bool bochs_display_get_big_endian_fb(Object *obj, Error **errp)
+{
+ BochsDisplayState *s = BOCHS_DISPLAY(obj);
+
+ return s->big_endian_fb;
+}
+
+static void bochs_display_set_big_endian_fb(Object *obj, bool value,
+ Error **errp)
+{
+ BochsDisplayState *s = BOCHS_DISPLAY(obj);
+
+ s->big_endian_fb = value;
+}
+
+static void bochs_display_init(Object *obj)
+{
+ /* Expose framebuffer byteorder via QOM */
+ object_property_add_bool(obj, "big-endian-framebuffer",
+ bochs_display_get_big_endian_fb,
+ bochs_display_set_big_endian_fb,
+ NULL);
+}
+
+static void bochs_display_exit(PCIDevice *dev)
+{
+ BochsDisplayState *s = BOCHS_DISPLAY(dev);
+
+ graphic_console_close(s->con);
+}
+
+static Property bochs_display_properties[] = {
+ DEFINE_PROP_SIZE("vgamem", BochsDisplayState, vgamem, 16 * 1024 * 1024),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void bochs_display_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->class_id = PCI_CLASS_DISPLAY_OTHER;
+ k->vendor_id = PCI_VENDOR_ID_QEMU;
+ k->device_id = PCI_DEVICE_ID_QEMU_VGA;
+
+ k->realize = bochs_display_realize;
+ k->exit = bochs_display_exit;
+ dc->vmsd = &vmstate_bochs_display;
+ dc->props = bochs_display_properties;
+ set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
+}
+
+static const TypeInfo bochs_display_type_info = {
+ .name = TYPE_BOCHS_DISPLAY,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(BochsDisplayState),
+ .instance_init = bochs_display_init,
+ .class_init = bochs_display_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { INTERFACE_PCIE_DEVICE },
+ { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+ { },
+ },
+};
+
+static void bochs_display_register_types(void)
+{
+ type_register_static(&bochs_display_type_info);
+}
+
+type_init(bochs_display_register_types)
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
index f4bb33c279..e47be99451 100644
--- a/hw/display/sm501.c
+++ b/hw/display/sm501.c
@@ -36,7 +36,6 @@
#include "hw/pci/pci.h"
#include "qemu/range.h"
#include "ui/pixel_ops.h"
-#include "exec/address-spaces.h"
/*
* Status: 2010/05/07
diff --git a/hw/display/ssd0303.c b/hw/display/ssd0303.c
index 68a80b9d64..eb90ba26be 100644
--- a/hw/display/ssd0303.c
+++ b/hw/display/ssd0303.c
@@ -297,13 +297,12 @@ static const GraphicHwOps ssd0303_ops = {
.gfx_update = ssd0303_update_display,
};
-static int ssd0303_init(I2CSlave *i2c)
+static void ssd0303_realize(DeviceState *dev, Error **errp)
{
- ssd0303_state *s = SSD0303(i2c);
+ ssd0303_state *s = SSD0303(dev);
- s->con = graphic_console_init(DEVICE(i2c), 0, &ssd0303_ops, s);
+ s->con = graphic_console_init(dev, 0, &ssd0303_ops, s);
qemu_console_resize(s->con, 96 * MAGNIFY, 16 * MAGNIFY);
- return 0;
}
static void ssd0303_class_init(ObjectClass *klass, void *data)
@@ -311,7 +310,7 @@ static void ssd0303_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
- k->init = ssd0303_init;
+ dc->realize = ssd0303_realize;
k->event = ssd0303_event;
k->recv = ssd0303_recv;
k->send = ssd0303_send;
diff --git a/hw/display/tc6393xb.c b/hw/display/tc6393xb.c
index 464465b7c2..8392e59493 100644
--- a/hw/display/tc6393xb.c
+++ b/hw/display/tc6393xb.c
@@ -18,7 +18,6 @@
#include "hw/block/flash.h"
#include "ui/console.h"
#include "ui/pixel_ops.h"
-#include "sysemu/block-backend.h"
#include "sysemu/blockdev.h"
#define IRQ_TC6393_NAND 0
diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c
index f312930664..700ac58c69 100644
--- a/hw/display/vga-pci.c
+++ b/hw/display/vga-pci.c
@@ -31,19 +31,6 @@
#include "qemu/timer.h"
#include "hw/loader.h"
-#define PCI_VGA_IOPORT_OFFSET 0x400
-#define PCI_VGA_IOPORT_SIZE (0x3e0 - 0x3c0)
-#define PCI_VGA_BOCHS_OFFSET 0x500
-#define PCI_VGA_BOCHS_SIZE (0x0b * 2)
-#define PCI_VGA_QEXT_OFFSET 0x600
-#define PCI_VGA_QEXT_SIZE (2 * 4)
-#define PCI_VGA_MMIO_SIZE 0x1000
-
-#define PCI_VGA_QEXT_REG_SIZE (0 * 4)
-#define PCI_VGA_QEXT_REG_BYTEORDER (1 * 4)
-#define PCI_VGA_QEXT_LITTLE_ENDIAN 0x1e1e1e1e
-#define PCI_VGA_QEXT_BIG_ENDIAN 0xbebebebe
-
enum vga_pci_flags {
PCI_VGA_FLAG_ENABLE_MMIO = 1,
PCI_VGA_FLAG_ENABLE_QEXT = 2,
@@ -245,7 +232,8 @@ static void pci_std_vga_realize(PCIDevice *dev, Error **errp)
/* mmio bar for vga register access */
if (d->flags & (1 << PCI_VGA_FLAG_ENABLE_MMIO)) {
- memory_region_init(&d->mmio, NULL, "vga.mmio", 4096);
+ memory_region_init(&d->mmio, NULL, "vga.mmio",
+ PCI_VGA_MMIO_SIZE);
if (d->flags & (1 << PCI_VGA_FLAG_ENABLE_QEXT)) {
qext = true;
@@ -280,7 +268,8 @@ static void pci_secondary_vga_realize(PCIDevice *dev, Error **errp)
s->con = graphic_console_init(DEVICE(dev), 0, s->hw_ops, s);
/* mmio bar */
- memory_region_init(&d->mmio, OBJECT(dev), "vga.mmio", 4096);
+ memory_region_init(&d->mmio, OBJECT(dev), "vga.mmio",
+ PCI_VGA_MMIO_SIZE);
if (d->flags & (1 << PCI_VGA_FLAG_ENABLE_QEXT)) {
qext = true;
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 72181330b8..a7794f6d1f 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -1480,13 +1480,28 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
s->get_resolution(s, &width, &height);
disp_width = width;
+ depth = s->get_bpp(s);
region_start = (s->start_addr * 4);
region_end = region_start + (ram_addr_t)s->line_offset * height;
- region_end += width * s->get_bpp(s) / 8; /* scanline length */
+ region_end += width * depth / 8; /* scanline length */
region_end -= s->line_offset;
- if (region_end > s->vbe_size) {
- /* wraps around (can happen with cirrus vbe modes) */
+ if (region_end > s->vbe_size || depth == 0 || depth == 15) {
+ /*
+ * We land here on:
+ * - wraps around (can happen with cirrus vbe modes)
+ * - depth == 0 (256 color palette video mode)
+ * - depth == 15
+ *
+ * Take the safe and slow route:
+ * - create a dirty bitmap snapshot for all vga memory.
+ * - force shadowing (so all vga memory access goes
+ * through vga_read_*() helpers).
+ *
+ * Given this affects only vga features which are pretty much
+ * unused by modern guests there should be no performance
+ * impact.
+ */
region_start = 0;
region_end = s->vbe_size;
force_shadow = true;
@@ -1520,8 +1535,6 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
}
}
- depth = s->get_bpp(s);
-
/*
* Check whether we can share the surface with the backend
* or whether we need a shadow surface. We share native
diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h
index fe23b81442..313cff84fc 100644
--- a/hw/display/vga_int.h
+++ b/hw/display/vga_int.h
@@ -29,42 +29,11 @@
#include "exec/memory.h"
#include "ui/console.h"
+#include "hw/display/bochs-vbe.h"
+
#define ST01_V_RETRACE 0x08
#define ST01_DISP_ENABLE 0x01
-#define VBE_DISPI_MAX_XRES 16000
-#define VBE_DISPI_MAX_YRES 12000
-#define VBE_DISPI_MAX_BPP 32
-
-#define VBE_DISPI_INDEX_ID 0x0
-#define VBE_DISPI_INDEX_XRES 0x1
-#define VBE_DISPI_INDEX_YRES 0x2
-#define VBE_DISPI_INDEX_BPP 0x3
-#define VBE_DISPI_INDEX_ENABLE 0x4
-#define VBE_DISPI_INDEX_BANK 0x5
-#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
-#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
-#define VBE_DISPI_INDEX_X_OFFSET 0x8
-#define VBE_DISPI_INDEX_Y_OFFSET 0x9
-#define VBE_DISPI_INDEX_NB 0xa /* size of vbe_regs[] */
-#define VBE_DISPI_INDEX_VIDEO_MEMORY_64K 0xa /* read-only, not in vbe_regs */
-
-#define VBE_DISPI_ID0 0xB0C0
-#define VBE_DISPI_ID1 0xB0C1
-#define VBE_DISPI_ID2 0xB0C2
-#define VBE_DISPI_ID3 0xB0C3
-#define VBE_DISPI_ID4 0xB0C4
-#define VBE_DISPI_ID5 0xB0C5
-
-#define VBE_DISPI_DISABLED 0x00
-#define VBE_DISPI_ENABLED 0x01
-#define VBE_DISPI_GETCAPS 0x02
-#define VBE_DISPI_8BIT_DAC 0x20
-#define VBE_DISPI_LFB_ENABLED 0x40
-#define VBE_DISPI_NOCLEARMEM 0x80
-
-#define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000
-
#define CH_ATTR_SIZE (160 * 100)
#define VGA_MAX_HEIGHT 2048
diff --git a/hw/dma/xlnx-zdma.c b/hw/dma/xlnx-zdma.c
index 14d86c254b..8eea757aff 100644
--- a/hw/dma/xlnx-zdma.c
+++ b/hw/dma/xlnx-zdma.c
@@ -302,7 +302,7 @@ static bool zdma_load_descriptor(XlnxZDMA *s, uint64_t addr, void *buf)
qemu_log_mask(LOG_GUEST_ERROR,
"zdma: unaligned descriptor at %" PRIx64,
addr);
- memset(buf, 0xdeadbeef, sizeof(XlnxZDMADescr));
+ memset(buf, 0x0, sizeof(XlnxZDMADescr));
s->error = true;
return false;
}
@@ -707,9 +707,11 @@ static uint64_t zdma_read(void *opaque, hwaddr addr, unsigned size)
RegisterInfo *r = &s->regs_info[addr / 4];
if (!r->data) {
+ gchar *path = object_get_canonical_path(OBJECT(s));
qemu_log("%s: Decode error: read from %" HWADDR_PRIx "\n",
- object_get_canonical_path(OBJECT(s)),
+ path,
addr);
+ g_free(path);
ARRAY_FIELD_DP32(s->regs, ZDMA_CH_ISR, INV_APB, true);
zdma_ch_imr_update_irq(s);
return 0;
@@ -724,9 +726,11 @@ static void zdma_write(void *opaque, hwaddr addr, uint64_t value,
RegisterInfo *r = &s->regs_info[addr / 4];
if (!r->data) {
+ gchar *path = object_get_canonical_path(OBJECT(s));
qemu_log("%s: Decode error: write to %" HWADDR_PRIx "=%" PRIx64 "\n",
- object_get_canonical_path(OBJECT(s)),
+ path,
addr, value);
+ g_free(path);
ARRAY_FIELD_DP32(s->regs, ZDMA_CH_ISR, INV_APB, true);
zdma_ch_imr_update_irq(s);
return;
diff --git a/hw/gpio/max7310.c b/hw/gpio/max7310.c
index 4c203ef5c6..a560e3afd2 100644
--- a/hw/gpio/max7310.c
+++ b/hw/gpio/max7310.c
@@ -182,14 +182,13 @@ static void max7310_gpio_set(void *opaque, int line, int level)
/* MAX7310 is SMBus-compatible (can be used with only SMBus protocols),
* but also accepts sequences that are not SMBus so return an I2C device. */
-static int max7310_init(I2CSlave *i2c)
+static void max7310_realize(DeviceState *dev, Error **errp)
{
- MAX7310State *s = MAX7310(i2c);
+ I2CSlave *i2c = I2C_SLAVE(dev);
+ MAX7310State *s = MAX7310(dev);
qdev_init_gpio_in(&i2c->qdev, max7310_gpio_set, 8);
qdev_init_gpio_out(&i2c->qdev, s->handler, 8);
-
- return 0;
}
static void max7310_class_init(ObjectClass *klass, void *data)
@@ -197,7 +196,7 @@ static void max7310_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
- k->init = max7310_init;
+ dc->realize = max7310_realize;
k->event = max7310_event;
k->recv = max7310_rx;
k->send = max7310_tx;
diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c
index c5dcf3104d..26f2704cd5 100644
--- a/hw/hppa/dino.c
+++ b/hw/hppa/dino.c
@@ -137,7 +137,8 @@ static void gsc_to_pci_forwarding(DinoState *s)
}
static bool dino_chip_mem_valid(void *opaque, hwaddr addr,
- unsigned size, bool is_write)
+ unsigned size, bool is_write,
+ MemTxAttrs attrs)
{
switch (addr) {
case DINO_IAR0:
diff --git a/hw/hppa/hppa_sys.h b/hw/hppa/hppa_sys.h
index f98cc8daad..f5f983bf4c 100644
--- a/hw/hppa/hppa_sys.h
+++ b/hw/hppa/hppa_sys.h
@@ -3,7 +3,6 @@
#ifndef HW_HPPA_SYS_H
#define HW_HPPA_SYS_H
-#include "target/hppa/cpu-qom.h"
#include "hw/pci/pci.h"
#include "hw/pci/pci_host.h"
#include "hw/ide.h"
diff --git a/hw/i2c/core.c b/hw/i2c/core.c
index cfccefca3d..ab72d5bf2b 100644
--- a/hw/i2c/core.c
+++ b/hw/i2c/core.c
@@ -258,18 +258,6 @@ const VMStateDescription vmstate_i2c_slave = {
}
};
-static int i2c_slave_qdev_init(DeviceState *dev)
-{
- I2CSlave *s = I2C_SLAVE(dev);
- I2CSlaveClass *sc = I2C_SLAVE_GET_CLASS(s);
-
- if (sc->init) {
- return sc->init(s);
- }
-
- return 0;
-}
-
DeviceState *i2c_create_slave(I2CBus *bus, const char *name, uint8_t addr)
{
DeviceState *dev;
@@ -283,7 +271,6 @@ DeviceState *i2c_create_slave(I2CBus *bus, const char *name, uint8_t addr)
static void i2c_slave_class_init(ObjectClass *klass, void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
- k->init = i2c_slave_qdev_init;
set_bit(DEVICE_CATEGORY_MISC, k->categories);
k->bus_type = TYPE_I2C_BUS;
k->props = i2c_props;
diff --git a/hw/i2c/smbus.c b/hw/i2c/smbus.c
index 2d1b79a689..587ce1ab7f 100644
--- a/hw/i2c/smbus.c
+++ b/hw/i2c/smbus.c
@@ -202,14 +202,6 @@ static int smbus_i2c_send(I2CSlave *s, uint8_t data)
return 0;
}
-static int smbus_device_init(I2CSlave *i2c)
-{
- SMBusDevice *dev = SMBUS_DEVICE(i2c);
- SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
-
- return sc->init(dev);
-}
-
/* Master device commands. */
int smbus_quick_command(I2CBus *bus, uint8_t addr, int read)
{
@@ -350,7 +342,6 @@ static void smbus_device_class_init(ObjectClass *klass, void *data)
{
I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
- sc->init = smbus_device_init;
sc->event = smbus_i2c_event;
sc->recv = smbus_i2c_recv;
sc->send = smbus_i2c_send;
diff --git a/hw/i2c/smbus_eeprom.c b/hw/i2c/smbus_eeprom.c
index b13ec0fe7a..125c887d1f 100644
--- a/hw/i2c/smbus_eeprom.c
+++ b/hw/i2c/smbus_eeprom.c
@@ -97,12 +97,11 @@ static uint8_t eeprom_read_data(SMBusDevice *dev, uint8_t cmd, int n)
return eeprom_receive_byte(dev);
}
-static int smbus_eeprom_initfn(SMBusDevice *dev)
+static void smbus_eeprom_realize(DeviceState *dev, Error **errp)
{
SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *)dev;
eeprom->offset = 0;
- return 0;
}
static Property smbus_eeprom_properties[] = {
@@ -115,7 +114,7 @@ static void smbus_eeprom_class_initfn(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(klass);
- sc->init = smbus_eeprom_initfn;
+ dc->realize = smbus_eeprom_realize;
sc->quick_cmd = eeprom_quick_cmd;
sc->send_byte = eeprom_send_byte;
sc->receive_byte = eeprom_receive_byte;
diff --git a/hw/i386/kvm/i8254.c b/hw/i386/kvm/i8254.c
index 13f20f47d9..d4d4a859f0 100644
--- a/hw/i386/kvm/i8254.c
+++ b/hw/i386/kvm/i8254.c
@@ -293,7 +293,7 @@ static void kvm_pit_realizefn(DeviceState *dev, Error **errp)
return;
}
- memory_region_init_reservation(&pit->ioports, NULL, "kvm-pit", 4);
+ memory_region_init_io(&pit->ioports, OBJECT(dev), NULL, NULL, "kvm-pit", 4);
qdev_init_gpio_in(dev, kvm_pit_irq_control, 1);
diff --git a/hw/i386/kvm/i8259.c b/hw/i386/kvm/i8259.c
index 05394cdb7b..83b6bfec77 100644
--- a/hw/i386/kvm/i8259.c
+++ b/hw/i386/kvm/i8259.c
@@ -121,8 +121,8 @@ static void kvm_pic_realize(DeviceState *dev, Error **errp)
PICCommonState *s = PIC_COMMON(dev);
KVMPICClass *kpc = KVM_PIC_GET_CLASS(dev);
- memory_region_init_reservation(&s->base_io, NULL, "kvm-pic", 2);
- memory_region_init_reservation(&s->elcr_io, NULL, "kvm-elcr", 1);
+ memory_region_init_io(&s->base_io, OBJECT(dev), NULL, NULL, "kvm-pic", 2);
+ memory_region_init_io(&s->elcr_io, OBJECT(dev), NULL, NULL, "kvm-elcr", 1);
kpc->parent_realize(dev, errp);
}
diff --git a/hw/i386/kvm/ioapic.c b/hw/i386/kvm/ioapic.c
index 98ca480792..646f6245ee 100644
--- a/hw/i386/kvm/ioapic.c
+++ b/hw/i386/kvm/ioapic.c
@@ -142,7 +142,7 @@ static void kvm_ioapic_realize(DeviceState *dev, Error **errp)
{
IOAPICCommonState *s = IOAPIC_COMMON(dev);
- memory_region_init_reservation(&s->io_memory, NULL, "kvm-ioapic", 0x1000);
+ memory_region_init_io(&s->io_memory, OBJECT(dev), NULL, NULL, "kvm-ioapic", 0x1000);
/*
* KVM ioapic only supports 0x11 now. This will only be used when
* we want to dump ioapic version.
diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c
index fc962c5fbc..70f6f26a94 100644
--- a/hw/i386/kvmvapic.c
+++ b/hw/i386/kvmvapic.c
@@ -11,7 +11,6 @@
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "cpu.h"
-#include "exec/exec-all.h"
#include "sysemu/sysemu.h"
#include "sysemu/cpus.h"
#include "sysemu/hw_accel.h"
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 1b2684c549..f3befe6721 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -64,7 +64,6 @@
#include "hw/acpi/acpi.h"
#include "hw/acpi/cpu_hotplug.h"
#include "hw/boards.h"
-#include "hw/pci/pci_host.h"
#include "acpi-build.h"
#include "hw/mem/pc-dimm.h"
#include "qapi/error.h"
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index e36c7bbb40..b4c5b03274 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -425,19 +425,19 @@ static void pc_i440fx_machine_options(MachineClass *m)
m->default_display = "std";
}
-static void pc_i440fx_2_13_machine_options(MachineClass *m)
+static void pc_i440fx_3_0_machine_options(MachineClass *m)
{
pc_i440fx_machine_options(m);
m->alias = "pc";
m->is_default = 1;
}
-DEFINE_I440FX_MACHINE(v2_13, "pc-i440fx-2.13", NULL,
- pc_i440fx_2_13_machine_options);
+DEFINE_I440FX_MACHINE(v3_0, "pc-i440fx-3.0", NULL,
+ pc_i440fx_3_0_machine_options);
static void pc_i440fx_2_12_machine_options(MachineClass *m)
{
- pc_i440fx_2_13_machine_options(m);
+ pc_i440fx_3_0_machine_options(m);
m->is_default = 0;
m->alias = NULL;
SET_MACHINE_COMPAT(m, PC_COMPAT_2_12);
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 2372457c6a..83d6d75efa 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -308,18 +308,18 @@ static void pc_q35_machine_options(MachineClass *m)
m->max_cpus = 288;
}
-static void pc_q35_2_13_machine_options(MachineClass *m)
+static void pc_q35_3_0_machine_options(MachineClass *m)
{
pc_q35_machine_options(m);
m->alias = "q35";
}
-DEFINE_Q35_MACHINE(v2_13, "pc-q35-2.13", NULL,
- pc_q35_2_13_machine_options);
+DEFINE_Q35_MACHINE(v3_0, "pc-q35-3.0", NULL,
+ pc_q35_3_0_machine_options);
static void pc_q35_2_12_machine_options(MachineClass *m)
{
- pc_q35_2_13_machine_options(m);
+ pc_q35_3_0_machine_options(m);
m->alias = NULL;
SET_MACHINE_COMPAT(m, PC_COMPAT_2_12);
}
diff --git a/hw/i386/xen/trace-events b/hw/i386/xen/trace-events
index 8dab7bcfe0..8a9077cd4e 100644
--- a/hw/i386/xen/trace-events
+++ b/hw/i386/xen/trace-events
@@ -15,6 +15,9 @@ cpu_ioreq_pio(void *req, uint32_t dir, uint32_t df, uint32_t data_is_ptr, uint64
cpu_ioreq_pio_read_reg(void *req, uint64_t data, uint64_t addr, uint32_t size) "I/O=%p pio read reg data=0x%"PRIx64" port=0x%"PRIx64" size=%d"
cpu_ioreq_pio_write_reg(void *req, uint64_t data, uint64_t addr, uint32_t size) "I/O=%p pio write reg data=0x%"PRIx64" port=0x%"PRIx64" size=%d"
cpu_ioreq_move(void *req, uint32_t dir, uint32_t df, uint32_t data_is_ptr, uint64_t addr, uint64_t data, uint32_t count, uint32_t size) "I/O=%p copy dir=%d df=%d ptr=%d port=0x%"PRIx64" data=0x%"PRIx64" count=%d size=%d"
+xen_map_resource_ioreq(uint32_t id, void *addr) "id: %u addr: %p"
+cpu_ioreq_config_read(void *req, uint32_t sbdf, uint32_t reg, uint32_t size, uint32_t data) "I/O=%p sbdf=0x%x reg=%u size=%u data=0x%x"
+cpu_ioreq_config_write(void *req, uint32_t sbdf, uint32_t reg, uint32_t size, uint32_t data) "I/O=%p sbdf=0x%x reg=%u size=%u data=0x%x"
# xen-mapcache.c
xen_map_cache(uint64_t phys_addr) "want 0x%"PRIx64
diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c
index caa563be3d..935a3676c8 100644
--- a/hw/i386/xen/xen-hvm.c
+++ b/hw/i386/xen/xen-hvm.c
@@ -12,6 +12,7 @@
#include "cpu.h"
#include "hw/pci/pci.h"
+#include "hw/pci/pci_host.h"
#include "hw/i386/pc.h"
#include "hw/i386/apic-msidef.h"
#include "hw/xen/xen_common.h"
@@ -86,6 +87,14 @@ typedef struct XenPhysmap {
QLIST_ENTRY(XenPhysmap) list;
} XenPhysmap;
+static QLIST_HEAD(, XenPhysmap) xen_physmap;
+
+typedef struct XenPciDevice {
+ PCIDevice *pci_dev;
+ uint32_t sbdf;
+ QLIST_ENTRY(XenPciDevice) entry;
+} XenPciDevice;
+
typedef struct XenIOState {
ioservid_t ioservid;
shared_iopage_t *shared_page;
@@ -95,7 +104,8 @@ typedef struct XenIOState {
CPUState **cpu_by_vcpu_id;
/* the evtchn port for polling the notification, */
evtchn_port_t *ioreq_local_port;
- /* evtchn local port for buffered io */
+ /* evtchn remote and local ports for buffered io */
+ evtchn_port_t bufioreq_remote_port;
evtchn_port_t bufioreq_local_port;
/* the evtchn fd for polling */
xenevtchn_handle *xce_handle;
@@ -105,8 +115,8 @@ typedef struct XenIOState {
struct xs_handle *xenstore;
MemoryListener memory_listener;
MemoryListener io_listener;
+ QLIST_HEAD(, XenPciDevice) dev_list;
DeviceListener device_listener;
- QLIST_HEAD(, XenPhysmap) physmap;
hwaddr free_phys_offset;
const XenPhysmap *log_for_dirtybit;
@@ -273,14 +283,13 @@ void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size, MemoryRegion *mr,
g_free(pfn_list);
}
-static XenPhysmap *get_physmapping(XenIOState *state,
- hwaddr start_addr, ram_addr_t size)
+static XenPhysmap *get_physmapping(hwaddr start_addr, ram_addr_t size)
{
XenPhysmap *physmap = NULL;
start_addr &= TARGET_PAGE_MASK;
- QLIST_FOREACH(physmap, &state->physmap, list) {
+ QLIST_FOREACH(physmap, &xen_physmap, list) {
if (range_covers_byte(physmap->start_addr, physmap->size, start_addr)) {
return physmap;
}
@@ -288,23 +297,21 @@ static XenPhysmap *get_physmapping(XenIOState *state,
return NULL;
}
-#ifdef XEN_COMPAT_PHYSMAP
-static hwaddr xen_phys_offset_to_gaddr(hwaddr start_addr,
- ram_addr_t size, void *opaque)
+static hwaddr xen_phys_offset_to_gaddr(hwaddr phys_offset, ram_addr_t size)
{
- hwaddr addr = start_addr & TARGET_PAGE_MASK;
- XenIOState *xen_io_state = opaque;
+ hwaddr addr = phys_offset & TARGET_PAGE_MASK;
XenPhysmap *physmap = NULL;
- QLIST_FOREACH(physmap, &xen_io_state->physmap, list) {
+ QLIST_FOREACH(physmap, &xen_physmap, list) {
if (range_covers_byte(physmap->phys_offset, physmap->size, addr)) {
- return physmap->start_addr;
+ return physmap->start_addr + (phys_offset - physmap->phys_offset);
}
}
- return start_addr;
+ return phys_offset;
}
+#ifdef XEN_COMPAT_PHYSMAP
static int xen_save_physmap(XenIOState *state, XenPhysmap *physmap)
{
char path[80], value[17];
@@ -354,7 +361,7 @@ static int xen_add_to_physmap(XenIOState *state,
hwaddr phys_offset = memory_region_get_ram_addr(mr);
const char *mr_name;
- if (get_physmapping(state, start_addr, size)) {
+ if (get_physmapping(start_addr, size)) {
return 0;
}
if (size <= 0) {
@@ -383,7 +390,7 @@ go_physmap:
physmap->name = mr_name;
physmap->phys_offset = phys_offset;
- QLIST_INSERT_HEAD(&state->physmap, physmap, list);
+ QLIST_INSERT_HEAD(&xen_physmap, physmap, list);
if (runstate_check(RUN_STATE_INMIGRATE)) {
/* Now when we have a physmap entry we can replace a dummy mapping with
@@ -427,7 +434,7 @@ static int xen_remove_from_physmap(XenIOState *state,
XenPhysmap *physmap = NULL;
hwaddr phys_offset = 0;
- physmap = get_physmapping(state, start_addr, size);
+ physmap = get_physmapping(start_addr, size);
if (physmap == NULL) {
return -1;
}
@@ -569,6 +576,12 @@ static void xen_device_realize(DeviceListener *listener,
if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
PCIDevice *pci_dev = PCI_DEVICE(dev);
+ XenPciDevice *xendev = g_new(XenPciDevice, 1);
+
+ xendev->pci_dev = pci_dev;
+ xendev->sbdf = PCI_BUILD_BDF(pci_dev_bus_num(pci_dev),
+ pci_dev->devfn);
+ QLIST_INSERT_HEAD(&state->dev_list, xendev, entry);
xen_map_pcidev(xen_domid, state->ioservid, pci_dev);
}
@@ -581,8 +594,17 @@ static void xen_device_unrealize(DeviceListener *listener,
if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
PCIDevice *pci_dev = PCI_DEVICE(dev);
+ XenPciDevice *xendev, *next;
xen_unmap_pcidev(xen_domid, state->ioservid, pci_dev);
+
+ QLIST_FOREACH_SAFE(xendev, &state->dev_list, entry, next) {
+ if (xendev->pci_dev == pci_dev) {
+ QLIST_REMOVE(xendev, entry);
+ g_free(xendev);
+ break;
+ }
+ }
}
}
@@ -596,7 +618,7 @@ static void xen_sync_dirty_bitmap(XenIOState *state,
int rc, i, j;
const XenPhysmap *physmap = NULL;
- physmap = get_physmapping(state, start_addr, size);
+ physmap = get_physmapping(start_addr, size);
if (physmap == NULL) {
/* not handled */
return;
@@ -903,6 +925,62 @@ static void cpu_ioreq_move(ioreq_t *req)
}
}
+static void cpu_ioreq_config(XenIOState *state, ioreq_t *req)
+{
+ uint32_t sbdf = req->addr >> 32;
+ uint32_t reg = req->addr;
+ XenPciDevice *xendev;
+
+ if (req->size != sizeof(uint8_t) && req->size != sizeof(uint16_t) &&
+ req->size != sizeof(uint32_t)) {
+ hw_error("PCI config access: bad size (%u)", req->size);
+ }
+
+ if (req->count != 1) {
+ hw_error("PCI config access: bad count (%u)", req->count);
+ }
+
+ QLIST_FOREACH(xendev, &state->dev_list, entry) {
+ if (xendev->sbdf != sbdf) {
+ continue;
+ }
+
+ if (!req->data_is_ptr) {
+ if (req->dir == IOREQ_READ) {
+ req->data = pci_host_config_read_common(
+ xendev->pci_dev, reg, PCI_CONFIG_SPACE_SIZE,
+ req->size);
+ trace_cpu_ioreq_config_read(req, xendev->sbdf, reg,
+ req->size, req->data);
+ } else if (req->dir == IOREQ_WRITE) {
+ trace_cpu_ioreq_config_write(req, xendev->sbdf, reg,
+ req->size, req->data);
+ pci_host_config_write_common(
+ xendev->pci_dev, reg, PCI_CONFIG_SPACE_SIZE,
+ req->data, req->size);
+ }
+ } else {
+ uint32_t tmp;
+
+ if (req->dir == IOREQ_READ) {
+ tmp = pci_host_config_read_common(
+ xendev->pci_dev, reg, PCI_CONFIG_SPACE_SIZE,
+ req->size);
+ trace_cpu_ioreq_config_read(req, xendev->sbdf, reg,
+ req->size, tmp);
+ write_phys_req_item(req->data, req, 0, &tmp);
+ } else if (req->dir == IOREQ_WRITE) {
+ read_phys_req_item(req->data, req, 0, &tmp);
+ trace_cpu_ioreq_config_write(req, xendev->sbdf, reg,
+ req->size, tmp);
+ pci_host_config_write_common(
+ xendev->pci_dev, reg, PCI_CONFIG_SPACE_SIZE,
+ tmp, req->size);
+ }
+ }
+ }
+}
+
static void regs_to_cpu(vmware_regs_t *vmport_regs, ioreq_t *req)
{
X86CPU *cpu;
@@ -975,27 +1053,9 @@ static void handle_ioreq(XenIOState *state, ioreq_t *req)
case IOREQ_TYPE_INVALIDATE:
xen_invalidate_map_cache();
break;
- case IOREQ_TYPE_PCI_CONFIG: {
- uint32_t sbdf = req->addr >> 32;
- uint32_t val;
-
- /* Fake a write to port 0xCF8 so that
- * the config space access will target the
- * correct device model.
- */
- val = (1u << 31) |
- ((req->addr & 0x0f00) << 16) |
- ((sbdf & 0xffff) << 8) |
- (req->addr & 0xfc);
- do_outp(0xcf8, 4, val);
-
- /* Now issue the config space access via
- * port 0xCFC
- */
- req->addr = 0xcfc | (req->addr & 0x03);
- cpu_ioreq_pio(req);
+ case IOREQ_TYPE_PCI_CONFIG:
+ cpu_ioreq_config(state, req);
break;
- }
default:
hw_error("Invalid ioreq type 0x%x\n", req->type);
}
@@ -1221,7 +1281,7 @@ static void xen_read_physmap(XenIOState *state)
xen_domid, entries[i]);
physmap->name = xs_read(state->xenstore, 0, path, &len);
- QLIST_INSERT_HEAD(&state->physmap, physmap, list);
+ QLIST_INSERT_HEAD(&xen_physmap, physmap, list);
}
free(entries);
}
@@ -1236,12 +1296,88 @@ static void xen_wakeup_notifier(Notifier *notifier, void *data)
xc_set_hvm_param(xen_xc, xen_domid, HVM_PARAM_ACPI_S_STATE, 0);
}
-void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory)
+static int xen_map_ioreq_server(XenIOState *state)
{
- int i, rc;
+ void *addr = NULL;
+ xenforeignmemory_resource_handle *fres;
xen_pfn_t ioreq_pfn;
xen_pfn_t bufioreq_pfn;
evtchn_port_t bufioreq_evtchn;
+ int rc;
+
+ /*
+ * Attempt to map using the resource API and fall back to normal
+ * foreign mapping if this is not supported.
+ */
+ QEMU_BUILD_BUG_ON(XENMEM_resource_ioreq_server_frame_bufioreq != 0);
+ QEMU_BUILD_BUG_ON(XENMEM_resource_ioreq_server_frame_ioreq(0) != 1);
+ fres = xenforeignmemory_map_resource(xen_fmem, xen_domid,
+ XENMEM_resource_ioreq_server,
+ state->ioservid, 0, 2,
+ &addr,
+ PROT_READ | PROT_WRITE, 0);
+ if (fres != NULL) {
+ trace_xen_map_resource_ioreq(state->ioservid, addr);
+ state->buffered_io_page = addr;
+ state->shared_page = addr + TARGET_PAGE_SIZE;
+ } else if (errno != EOPNOTSUPP) {
+ error_report("failed to map ioreq server resources: error %d handle=%p",
+ errno, xen_xc);
+ return -1;
+ }
+
+ rc = xen_get_ioreq_server_info(xen_domid, state->ioservid,
+ (state->shared_page == NULL) ?
+ &ioreq_pfn : NULL,
+ (state->buffered_io_page == NULL) ?
+ &bufioreq_pfn : NULL,
+ &bufioreq_evtchn);
+ if (rc < 0) {
+ error_report("failed to get ioreq server info: error %d handle=%p",
+ errno, xen_xc);
+ return rc;
+ }
+
+ if (state->shared_page == NULL) {
+ DPRINTF("shared page at pfn %lx\n", ioreq_pfn);
+
+ state->shared_page = xenforeignmemory_map(xen_fmem, xen_domid,
+ PROT_READ | PROT_WRITE,
+ 1, &ioreq_pfn, NULL);
+ if (state->shared_page == NULL) {
+ error_report("map shared IO page returned error %d handle=%p",
+ errno, xen_xc);
+ }
+ }
+
+ if (state->buffered_io_page == NULL) {
+ DPRINTF("buffered io page at pfn %lx\n", bufioreq_pfn);
+
+ state->buffered_io_page = xenforeignmemory_map(xen_fmem, xen_domid,
+ PROT_READ | PROT_WRITE,
+ 1, &bufioreq_pfn,
+ NULL);
+ if (state->buffered_io_page == NULL) {
+ error_report("map buffered IO page returned error %d", errno);
+ return -1;
+ }
+ }
+
+ if (state->shared_page == NULL || state->buffered_io_page == NULL) {
+ return -1;
+ }
+
+ DPRINTF("buffered io evtchn is %x\n", bufioreq_evtchn);
+
+ state->bufioreq_remote_port = bufioreq_evtchn;
+
+ return 0;
+}
+
+void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory)
+{
+ int i, rc;
+ xen_pfn_t ioreq_pfn;
XenIOState *state;
state = g_malloc0(sizeof (XenIOState));
@@ -1269,25 +1405,8 @@ void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory)
state->wakeup.notify = xen_wakeup_notifier;
qemu_register_wakeup_notifier(&state->wakeup);
- rc = xen_get_ioreq_server_info(xen_domid, state->ioservid,
- &ioreq_pfn, &bufioreq_pfn,
- &bufioreq_evtchn);
+ rc = xen_map_ioreq_server(state);
if (rc < 0) {
- error_report("failed to get ioreq server info: error %d handle=%p",
- errno, xen_xc);
- goto err;
- }
-
- DPRINTF("shared page at pfn %lx\n", ioreq_pfn);
- DPRINTF("buffered io page at pfn %lx\n", bufioreq_pfn);
- DPRINTF("buffered io evtchn is %x\n", bufioreq_evtchn);
-
- state->shared_page = xenforeignmemory_map(xen_fmem, xen_domid,
- PROT_READ|PROT_WRITE,
- 1, &ioreq_pfn, NULL);
- if (state->shared_page == NULL) {
- error_report("map shared IO page returned error %d handle=%p",
- errno, xen_xc);
goto err;
}
@@ -1308,14 +1427,6 @@ void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory)
goto err;
}
- state->buffered_io_page = xenforeignmemory_map(xen_fmem, xen_domid,
- PROT_READ|PROT_WRITE,
- 1, &bufioreq_pfn, NULL);
- if (state->buffered_io_page == NULL) {
- error_report("map buffered IO page returned error %d", errno);
- goto err;
- }
-
/* Note: cpus is empty at this point in init */
state->cpu_by_vcpu_id = g_malloc0(max_cpus * sizeof(CPUState *));
@@ -1340,7 +1451,7 @@ void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory)
}
rc = xenevtchn_bind_interdomain(state->xce_handle, xen_domid,
- bufioreq_evtchn);
+ state->bufioreq_remote_port);
if (rc == -1) {
error_report("buffered evtchn bind error %d", errno);
goto err;
@@ -1358,7 +1469,6 @@ void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory)
qemu_add_vm_change_state_handler(xen_hvm_change_state_handler, state);
state->memory_listener = xen_memory_listener;
- QLIST_INIT(&state->physmap);
memory_listener_register(&state->memory_listener, &address_space_memory);
state->log_for_dirtybit = NULL;
@@ -1366,6 +1476,7 @@ void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory)
memory_listener_register(&state->io_listener, &address_space_io);
state->device_listener = xen_device_listener;
+ QLIST_INIT(&state->dev_list);
device_listener_register(&state->device_listener);
/* Initialize backend core & drivers */
@@ -1374,6 +1485,8 @@ void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory)
goto err;
}
xen_be_register_common();
+
+ QLIST_INIT(&xen_physmap);
xen_read_physmap(state);
/* Disable ACPI build because Xen handles it */
@@ -1445,6 +1558,8 @@ void xen_hvm_modified_memory(ram_addr_t start, ram_addr_t length)
int rc;
ram_addr_t start_pfn, nb_pages;
+ start = xen_phys_offset_to_gaddr(start, length);
+
if (length == 0) {
length = TARGET_PAGE_SIZE;
}
diff --git a/hw/i386/xen/xen-mapcache.c b/hw/i386/xen/xen-mapcache.c
index efa35dc6e0..628b813a11 100644
--- a/hw/i386/xen/xen-mapcache.c
+++ b/hw/i386/xen/xen-mapcache.c
@@ -14,7 +14,6 @@
#include <sys/resource.h>
#include "hw/xen/xen_backend.h"
-#include "sysemu/blockdev.h"
#include "qemu/bitmap.h"
#include <xen/hvm/params.h>
@@ -319,7 +318,7 @@ tryagain:
mapcache->last_entry = NULL;
#ifdef XEN_COMPAT_PHYSMAP
if (!translated && mapcache->phys_offset_to_gaddr) {
- phys_addr = mapcache->phys_offset_to_gaddr(phys_addr, size, mapcache->opaque);
+ phys_addr = mapcache->phys_offset_to_gaddr(phys_addr, size);
translated = true;
goto tryagain;
}
diff --git a/hw/i386/xen/xen_pvdevice.c b/hw/i386/xen/xen_pvdevice.c
index f748823658..a146f1883a 100644
--- a/hw/i386/xen/xen_pvdevice.c
+++ b/hw/i386/xen/xen_pvdevice.c
@@ -71,6 +71,16 @@ static const MemoryRegionOps xen_pv_mmio_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
+static const VMStateDescription vmstate_xen_pvdevice = {
+ .name = "xen-pvdevice",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_PCI_DEVICE(parent_obj, XenPVDevice),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static void xen_pv_realize(PCIDevice *pci_dev, Error **errp)
{
XenPVDevice *d = XEN_PV_DEVICE(pci_dev);
@@ -120,6 +130,7 @@ static void xen_pv_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_SYSTEM_OTHER;
dc->desc = "Xen PV Device";
dc->props = xen_pv_props;
+ dc->vmsd = &vmstate_xen_pvdevice;
}
static const TypeInfo xen_pv_type_info = {
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 866c659498..cc9ca28c33 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -25,7 +25,6 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
-#include "hw/pci/pci.h"
#include "hw/isa/isa.h"
#include "qemu/error-report.h"
#include "qemu/timer.h"
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index 1ab0a892d0..fe1ceeb0cd 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -26,7 +26,6 @@
#include "hw/hw.h"
#include "hw/pci/pci.h"
#include "hw/isa/isa.h"
-#include "sysemu/block-backend.h"
#include "sysemu/dma.h"
#include "qemu/error-report.h"
#include "hw/ide/pci.h"
diff --git a/hw/ide/via.c b/hw/ide/via.c
index 117ac4d95e..238f038d72 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -27,7 +27,6 @@
#include "hw/hw.h"
#include "hw/pci/pci.h"
#include "hw/isa/isa.h"
-#include "sysemu/block-backend.h"
#include "sysemu/sysemu.h"
#include "sysemu/dma.h"
diff --git a/hw/input/Makefile.objs b/hw/input/Makefile.objs
index 77e53e6883..c8b00f71ec 100644
--- a/hw/input/Makefile.objs
+++ b/hw/input/Makefile.objs
@@ -7,10 +7,10 @@ common-obj-y += ps2.o
common-obj-$(CONFIG_STELLARIS_INPUT) += stellaris_input.o
common-obj-$(CONFIG_TSC2005) += tsc2005.o
-common-obj-$(CONFIG_VIRTIO) += virtio-input.o
-common-obj-$(CONFIG_VIRTIO) += virtio-input-hid.o
+common-obj-$(CONFIG_VIRTIO_INPUT) += virtio-input.o
+common-obj-$(CONFIG_VIRTIO_INPUT) += virtio-input-hid.o
ifeq ($(CONFIG_LINUX),y)
-common-obj-$(CONFIG_VIRTIO) += virtio-input-host.o
+common-obj-$(CONFIG_VIRTIO_INPUT) += virtio-input-host.o
endif
obj-$(CONFIG_MILKYMIST) += milkymist-softusb.o
diff --git a/hw/input/lm832x.c b/hw/input/lm832x.c
index d39953126b..74da30d9ca 100644
--- a/hw/input/lm832x.c
+++ b/hw/input/lm832x.c
@@ -464,20 +464,19 @@ static const VMStateDescription vmstate_lm_kbd = {
};
-static int lm8323_init(I2CSlave *i2c)
+static void lm8323_realize(DeviceState *dev, Error **errp)
{
- LM823KbdState *s = LM8323(i2c);
+ LM823KbdState *s = LM8323(dev);
s->model = 0x8323;
s->pwm.tm[0] = timer_new_ns(QEMU_CLOCK_VIRTUAL, lm_kbd_pwm0_tick, s);
s->pwm.tm[1] = timer_new_ns(QEMU_CLOCK_VIRTUAL, lm_kbd_pwm1_tick, s);
s->pwm.tm[2] = timer_new_ns(QEMU_CLOCK_VIRTUAL, lm_kbd_pwm2_tick, s);
- qdev_init_gpio_out(DEVICE(i2c), &s->nirq, 1);
+ qdev_init_gpio_out(dev, &s->nirq, 1);
lm_kbd_reset(s);
qemu_register_reset((void *) lm_kbd_reset, s);
- return 0;
}
void lm832x_key_event(DeviceState *dev, int key, int state)
@@ -505,7 +504,7 @@ static void lm8323_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
- k->init = lm8323_init;
+ dc->realize = lm8323_realize;
k->event = lm_i2c_event;
k->recv = lm_i2c_rx;
k->send = lm_i2c_tx;
diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c
index 6f467e68a8..204369d0e2 100644
--- a/hw/intc/arm_gic_kvm.c
+++ b/hw/intc/arm_gic_kvm.c
@@ -572,7 +572,6 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
if (kvm_has_gsi_routing()) {
/* set up irq routing */
- kvm_init_irq_routing(kvm_state);
for (i = 0; i < s->num_irq - GIC_INTERNAL; ++i) {
kvm_irqchip_add_irq_route(kvm_state, i, 0, i);
}
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index cb9a3a542d..5c89be1af0 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -427,7 +427,7 @@ static uint64_t icv_ap_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
GICv3CPUState *cs = icc_cs_from_env(env);
int regno = ri->opc2 & 3;
- int grp = ri->crm & 1 ? GICV3_G0 : GICV3_G1NS;
+ int grp = (ri->crm & 1) ? GICV3_G1NS : GICV3_G0;
uint64_t value = cs->ich_apr[grp][regno];
trace_gicv3_icv_ap_read(ri->crm & 1, regno, gicv3_redist_affid(cs), value);
@@ -439,7 +439,7 @@ static void icv_ap_write(CPUARMState *env, const ARMCPRegInfo *ri,
{
GICv3CPUState *cs = icc_cs_from_env(env);
int regno = ri->opc2 & 3;
- int grp = ri->crm & 1 ? GICV3_G0 : GICV3_G1NS;
+ int grp = (ri->crm & 1) ? GICV3_G1NS : GICV3_G0;
trace_gicv3_icv_ap_write(ri->crm & 1, regno, gicv3_redist_affid(cs), value);
@@ -1461,7 +1461,7 @@ static uint64_t icc_ap_read(CPUARMState *env, const ARMCPRegInfo *ri)
uint64_t value;
int regno = ri->opc2 & 3;
- int grp = ri->crm & 1 ? GICV3_G0 : GICV3_G1;
+ int grp = (ri->crm & 1) ? GICV3_G1 : GICV3_G0;
if (icv_access(env, grp == GICV3_G0 ? HCR_FMO : HCR_IMO)) {
return icv_ap_read(env, ri);
@@ -1483,7 +1483,7 @@ static void icc_ap_write(CPUARMState *env, const ARMCPRegInfo *ri,
GICv3CPUState *cs = icc_cs_from_env(env);
int regno = ri->opc2 & 3;
- int grp = ri->crm & 1 ? GICV3_G0 : GICV3_G1;
+ int grp = (ri->crm & 1) ? GICV3_G1 : GICV3_G0;
if (icv_access(env, grp == GICV3_G0 ? HCR_FMO : HCR_IMO)) {
icv_ap_write(env, ri, value);
@@ -2292,7 +2292,7 @@ static uint64_t ich_ap_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
GICv3CPUState *cs = icc_cs_from_env(env);
int regno = ri->opc2 & 3;
- int grp = ri->crm & 1 ? GICV3_G0 : GICV3_G1NS;
+ int grp = (ri->crm & 1) ? GICV3_G1NS : GICV3_G0;
uint64_t value;
value = cs->ich_apr[grp][regno];
@@ -2305,7 +2305,7 @@ static void ich_ap_write(CPUARMState *env, const ARMCPRegInfo *ri,
{
GICv3CPUState *cs = icc_cs_from_env(env);
int regno = ri->opc2 & 3;
- int grp = ri->crm & 1 ? GICV3_G0 : GICV3_G1NS;
+ int grp = (ri->crm & 1) ? GICV3_G1NS : GICV3_G0;
trace_gicv3_ich_ap_write(ri->crm & 1, regno, gicv3_redist_affid(cs), value);
diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c
index ec371772b3..0279b86cd9 100644
--- a/hw/intc/arm_gicv3_kvm.c
+++ b/hw/intc/arm_gicv3_kvm.c
@@ -243,6 +243,7 @@ static void kvm_dist_putbmp(GICv3State *s, uint32_t offset,
if (clroffset != 0) {
reg = 0;
kvm_gicd_access(s, clroffset, &reg, true);
+ clroffset += 4;
}
reg = *gic_bmp_ptr32(bmp, irq);
kvm_gicd_access(s, offset, &reg, true);
@@ -760,7 +761,6 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
if (kvm_has_gsi_routing()) {
/* set up irq routing */
- kvm_init_irq_routing(kvm_state);
for (i = 0; i < s->num_irq - GIC_INTERNAL; ++i) {
kvm_irqchip_add_irq_route(kvm_state, i, 0, i);
}
diff --git a/hw/ipmi/isa_ipmi_kcs.c b/hw/ipmi/isa_ipmi_kcs.c
index 689587b65d..a79431554a 100644
--- a/hw/ipmi/isa_ipmi_kcs.c
+++ b/hw/ipmi/isa_ipmi_kcs.c
@@ -22,6 +22,7 @@
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
+#include "qemu/log.h"
#include "qapi/error.h"
#include "hw/hw.h"
#include "hw/ipmi/ipmi.h"
@@ -422,24 +423,69 @@ static void ipmi_isa_realize(DeviceState *dev, Error **errp)
isa_register_ioport(isadev, &iik->kcs.io, iik->kcs.io_base);
}
-const VMStateDescription vmstate_ISAIPMIKCSDevice = {
+static int ipmi_kcs_vmstate_post_load(void *opaque, int version)
+{
+ IPMIKCS *ik = opaque;
+
+ /* Make sure all the values are sane. */
+ if (ik->outpos >= MAX_IPMI_MSG_SIZE || ik->outlen >= MAX_IPMI_MSG_SIZE ||
+ ik->outpos >= ik->outlen) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ipmi:kcs: vmstate transfer received bad out values: %d %d\n",
+ ik->outpos, ik->outlen);
+ ik->outpos = 0;
+ ik->outlen = 0;
+ }
+
+ if (ik->inlen >= MAX_IPMI_MSG_SIZE) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ipmi:kcs: vmstate transfer received bad in value: %d\n",
+ ik->inlen);
+ ik->inlen = 0;
+ }
+
+ return 0;
+}
+
+static bool vmstate_kcs_before_version2(void *opaque, int version)
+{
+ return version <= 1;
+}
+
+static const VMStateDescription vmstate_IPMIKCS = {
+ .name = TYPE_IPMI_INTERFACE_PREFIX "kcs",
+ .version_id = 2,
+ .minimum_version_id = 1,
+ .post_load = ipmi_kcs_vmstate_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_BOOL(obf_irq_set, IPMIKCS),
+ VMSTATE_BOOL(atn_irq_set, IPMIKCS),
+ VMSTATE_UNUSED_TEST(vmstate_kcs_before_version2, 1), /* Was use_irq */
+ VMSTATE_BOOL(irqs_enabled, IPMIKCS),
+ VMSTATE_UINT32(outpos, IPMIKCS),
+ VMSTATE_UINT32_V(outlen, IPMIKCS, 2),
+ VMSTATE_UINT8_ARRAY(outmsg, IPMIKCS, MAX_IPMI_MSG_SIZE),
+ VMSTATE_UINT32_V(inlen, IPMIKCS, 2),
+ VMSTATE_UINT8_ARRAY(inmsg, IPMIKCS, MAX_IPMI_MSG_SIZE),
+ VMSTATE_BOOL(write_end, IPMIKCS),
+ VMSTATE_UINT8(status_reg, IPMIKCS),
+ VMSTATE_UINT8(data_out_reg, IPMIKCS),
+ VMSTATE_INT16(data_in_reg, IPMIKCS),
+ VMSTATE_INT16(cmd_reg, IPMIKCS),
+ VMSTATE_UINT8(waiting_rsp, IPMIKCS),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_ISAIPMIKCSDevice = {
.name = TYPE_IPMI_INTERFACE,
- .version_id = 1,
+ .version_id = 2,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
- VMSTATE_BOOL(kcs.obf_irq_set, ISAIPMIKCSDevice),
- VMSTATE_BOOL(kcs.atn_irq_set, ISAIPMIKCSDevice),
- VMSTATE_BOOL(kcs.use_irq, ISAIPMIKCSDevice),
- VMSTATE_BOOL(kcs.irqs_enabled, ISAIPMIKCSDevice),
- VMSTATE_UINT32(kcs.outpos, ISAIPMIKCSDevice),
- VMSTATE_UINT8_ARRAY(kcs.outmsg, ISAIPMIKCSDevice, MAX_IPMI_MSG_SIZE),
- VMSTATE_UINT8_ARRAY(kcs.inmsg, ISAIPMIKCSDevice, MAX_IPMI_MSG_SIZE),
- VMSTATE_BOOL(kcs.write_end, ISAIPMIKCSDevice),
- VMSTATE_UINT8(kcs.status_reg, ISAIPMIKCSDevice),
- VMSTATE_UINT8(kcs.data_out_reg, ISAIPMIKCSDevice),
- VMSTATE_INT16(kcs.data_in_reg, ISAIPMIKCSDevice),
- VMSTATE_INT16(kcs.cmd_reg, ISAIPMIKCSDevice),
- VMSTATE_UINT8(kcs.waiting_rsp, ISAIPMIKCSDevice),
+ VMSTATE_VSTRUCT_TEST(kcs, ISAIPMIKCSDevice, vmstate_kcs_before_version2,
+ 0, vmstate_IPMIKCS, IPMIKCS, 1),
+ VMSTATE_VSTRUCT_V(kcs, ISAIPMIKCSDevice, 2, vmstate_IPMIKCS,
+ IPMIKCS, 2),
VMSTATE_END_OF_LIST()
}
};
@@ -450,6 +496,11 @@ static void isa_ipmi_kcs_init(Object *obj)
ipmi_bmc_find_and_link(obj, (Object **) &iik->kcs.bmc);
+ /*
+ * Version 1 had an incorrect name, it clashed with the BT
+ * IPMI device, so receive it, but transmit a different
+ * version.
+ */
vmstate_register(NULL, 0, &vmstate_ISAIPMIKCSDevice, iik);
}
diff --git a/hw/isa/isa-superio.c b/hw/isa/isa-superio.c
index 76286c81a1..8bc2f69eaa 100644
--- a/hw/isa/isa-superio.c
+++ b/hw/isa/isa-superio.c
@@ -13,7 +13,6 @@
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "sysemu/sysemu.h"
-#include "sysemu/block-backend.h"
#include "sysemu/blockdev.h"
#include "chardev/char.h"
#include "hw/isa/superio.h"
@@ -43,7 +42,7 @@ static void isa_superio_realize(DeviceState *dev, Error **errp)
if (!k->parallel.is_enabled || k->parallel.is_enabled(sio, i)) {
/* FIXME use a qdev chardev prop instead of parallel_hds[] */
chr = parallel_hds[i];
- if (chr == NULL || chr->be) {
+ if (chr == NULL) {
name = g_strdup_printf("discarding-parallel%d", i);
chr = qemu_chr_new(name, "null");
} else {
@@ -83,7 +82,7 @@ static void isa_superio_realize(DeviceState *dev, Error **errp)
if (!k->serial.is_enabled || k->serial.is_enabled(sio, i)) {
/* FIXME use a qdev chardev prop instead of serial_hd() */
chr = serial_hd(i);
- if (chr == NULL || chr->be) {
+ if (chr == NULL) {
name = g_strdup_printf("discarding-serial%d", i);
chr = qemu_chr_new(name, "null");
} else {
diff --git a/hw/lm32/lm32_boards.c b/hw/lm32/lm32_boards.c
index 907e875d02..167058348e 100644
--- a/hw/lm32/lm32_boards.c
+++ b/hw/lm32/lm32_boards.c
@@ -27,7 +27,6 @@
#include "hw/devices.h"
#include "hw/boards.h"
#include "hw/loader.h"
-#include "sysemu/block-backend.h"
#include "elf.h"
#include "lm32_hwsetup.h"
#include "lm32.h"
diff --git a/hw/lm32/milkymist.c b/hw/lm32/milkymist.c
index f9688e059e..c36bbc4ae2 100644
--- a/hw/lm32/milkymist.c
+++ b/hw/lm32/milkymist.c
@@ -30,7 +30,6 @@
#include "hw/boards.h"
#include "hw/loader.h"
#include "elf.h"
-#include "sysemu/block-backend.h"
#include "milkymist-hw.h"
#include "lm32.h"
#include "exec/address-spaces.h"
diff --git a/hw/m68k/mcf5206.c b/hw/m68k/mcf5206.c
index 6ad1e4bd2d..7abd84ac47 100644
--- a/hw/m68k/mcf5206.c
+++ b/hw/m68k/mcf5206.c
@@ -14,7 +14,6 @@
#include "qemu/timer.h"
#include "hw/ptimer.h"
#include "sysemu/sysemu.h"
-#include "exec/address-spaces.h"
/* General purpose timer module. */
typedef struct {
diff --git a/hw/m68k/mcf_intc.c b/hw/m68k/mcf_intc.c
index 8198afac1e..393ce284a2 100644
--- a/hw/m68k/mcf_intc.c
+++ b/hw/m68k/mcf_intc.c
@@ -11,7 +11,6 @@
#include "hw/hw.h"
#include "hw/sysbus.h"
#include "hw/m68k/mcf.h"
-#include "exec/address-spaces.h"
#define TYPE_MCF_INTC "mcf-intc"
#define MCF_INTC(obj) OBJECT_CHECK(mcf_intc_state, (obj), TYPE_MCF_INTC)
diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c
index cf6bf3f32a..6c4a544eac 100644
--- a/hw/microblaze/petalogix_ml605_mmu.c
+++ b/hw/microblaze/petalogix_ml605_mmu.c
@@ -36,7 +36,6 @@
#include "sysemu/sysemu.h"
#include "hw/devices.h"
#include "hw/boards.h"
-#include "sysemu/block-backend.h"
#include "hw/char/serial.h"
#include "exec/address-spaces.h"
#include "hw/ssi/ssi.h"
diff --git a/hw/microblaze/petalogix_s3adsp1800_mmu.c b/hw/microblaze/petalogix_s3adsp1800_mmu.c
index 1186002a76..0da3e62102 100644
--- a/hw/microblaze/petalogix_s3adsp1800_mmu.c
+++ b/hw/microblaze/petalogix_s3adsp1800_mmu.c
@@ -34,7 +34,6 @@
#include "sysemu/sysemu.h"
#include "hw/devices.h"
#include "hw/boards.h"
-#include "sysemu/block-backend.h"
#include "exec/address-spaces.h"
#include "hw/char/xilinx_uartlite.h"
diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
index af70ecffc0..494f84e290 100644
--- a/hw/mips/mips_malta.c
+++ b/hw/mips/mips_malta.c
@@ -46,7 +46,6 @@
#include "elf.h"
#include "hw/timer/mc146818rtc.h"
#include "hw/timer/i8254.h"
-#include "sysemu/blockdev.h"
#include "exec/address-spaces.h"
#include "hw/sysbus.h" /* SysBusDevice */
#include "qemu/host-utils.h"
diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c
index e04b49d3c5..e5cf8ed1a3 100644
--- a/hw/mips/mips_r4k.c
+++ b/hw/mips/mips_r4k.c
@@ -30,7 +30,6 @@
#include "hw/timer/mc146818rtc.h"
#include "hw/input/i8042.h"
#include "hw/timer/i8254.h"
-#include "sysemu/block-backend.h"
#include "exec/address-spaces.h"
#include "sysemu/qtest.h"
#include "qemu/error-report.h"
diff --git a/hw/misc/arm_integrator_debug.c b/hw/misc/arm_integrator_debug.c
index 8a5f29559d..533e6e3208 100644
--- a/hw/misc/arm_integrator_debug.c
+++ b/hw/misc/arm_integrator_debug.c
@@ -17,7 +17,6 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/sysbus.h"
-#include "exec/address-spaces.h"
#include "hw/misc/arm_integrator_debug.h"
#include "qemu/log.h"
diff --git a/hw/misc/mips_itu.c b/hw/misc/mips_itu.c
index c84a48bbb7..ccc4c7d98a 100644
--- a/hw/misc/mips_itu.c
+++ b/hw/misc/mips_itu.c
@@ -18,13 +18,10 @@
*/
#include "qemu/osdep.h"
+#include "qemu/log.h"
#include "qapi/error.h"
#include "cpu.h"
-#include "qemu/log.h"
#include "exec/exec-all.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
#include "hw/misc/mips_itu.h"
#define ITC_TAG_ADDRSPACE_SZ (ITC_ADDRESSMAP_NUM * 8)
diff --git a/hw/misc/sga.c b/hw/misc/sga.c
index 97fd63f176..4a22a52a60 100644
--- a/hw/misc/sga.c
+++ b/hw/misc/sga.c
@@ -25,7 +25,7 @@
*
*/
#include "qemu/osdep.h"
-#include "hw/pci/pci.h"
+#include "hw/isa/isa.h"
#include "hw/loader.h"
#include "sysemu/sysemu.h"
diff --git a/hw/misc/tmp105.c b/hw/misc/tmp105.c
index 9e22d64e36..0918f3a6ea 100644
--- a/hw/misc/tmp105.c
+++ b/hw/misc/tmp105.c
@@ -229,15 +229,14 @@ static void tmp105_reset(I2CSlave *i2c)
tmp105_interrupt_update(s);
}
-static int tmp105_init(I2CSlave *i2c)
+static void tmp105_realize(DeviceState *dev, Error **errp)
{
+ I2CSlave *i2c = I2C_SLAVE(dev);
TMP105State *s = TMP105(i2c);
qdev_init_gpio_out(&i2c->qdev, &s->pin, 1);
tmp105_reset(&s->i2c);
-
- return 0;
}
static void tmp105_initfn(Object *obj)
@@ -252,7 +251,7 @@ static void tmp105_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
- k->init = tmp105_init;
+ dc->realize = tmp105_realize;
k->event = tmp105_event;
k->recv = tmp105_rx;
k->send = tmp105_tx;
diff --git a/hw/misc/tmp421.c b/hw/misc/tmp421.c
index 4a505abbce..c234044305 100644
--- a/hw/misc/tmp421.c
+++ b/hw/misc/tmp421.c
@@ -335,13 +335,11 @@ static void tmp421_reset(I2CSlave *i2c)
s->status = 0;
}
-static int tmp421_init(I2CSlave *i2c)
+static void tmp421_realize(DeviceState *dev, Error **errp)
{
- TMP421State *s = TMP421(i2c);
+ TMP421State *s = TMP421(dev);
tmp421_reset(&s->i2c);
-
- return 0;
}
static void tmp421_initfn(Object *obj)
@@ -366,7 +364,7 @@ static void tmp421_class_init(ObjectClass *klass, void *data)
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
TMP421Class *sc = TMP421_CLASS(klass);
- k->init = tmp421_init;
+ dc->realize = tmp421_realize;
k->event = tmp421_event;
k->recv = tmp421_rx;
k->send = tmp421_tx;
diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs
index ab22968641..fa461d4463 100644
--- a/hw/net/Makefile.objs
+++ b/hw/net/Makefile.objs
@@ -36,7 +36,7 @@ obj-$(CONFIG_MILKYMIST) += milkymist-minimac2.o
obj-$(CONFIG_PSERIES) += spapr_llan.o
obj-$(CONFIG_XILINX_ETHLITE) += xilinx_ethlite.o
-obj-$(CONFIG_VIRTIO) += virtio-net.o
+obj-$(CONFIG_VIRTIO_NET) += virtio-net.o
obj-y += vhost_net.o
obj-$(CONFIG_ETSEC) += fsl_etsec/etsec.o fsl_etsec/registers.o \
diff --git a/hw/net/mcf_fec.c b/hw/net/mcf_fec.c
index bfa6b4bcce..0091e4ecdd 100644
--- a/hw/net/mcf_fec.c
+++ b/hw/net/mcf_fec.c
@@ -14,7 +14,6 @@
#include "hw/sysbus.h"
/* For crc32 */
#include <zlib.h>
-#include "exec/address-spaces.h"
//#define DEBUG_FEC 1
diff --git a/hw/net/ne2000-isa.c b/hw/net/ne2000-isa.c
index 70e5c1d3d4..c7fdeb0f6c 100644
--- a/hw/net/ne2000-isa.c
+++ b/hw/net/ne2000-isa.c
@@ -27,7 +27,6 @@
#include "hw/qdev.h"
#include "ne2000.h"
#include "sysemu/sysemu.h"
-#include "exec/address-spaces.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
diff --git a/hw/net/xen_nic.c b/hw/net/xen_nic.c
index 20c43a61b3..46a8dbfc90 100644
--- a/hw/net/xen_nic.c
+++ b/hw/net/xen_nic.c
@@ -160,9 +160,8 @@ static void net_tx_packets(struct XenNetDev *netdev)
(txreq.flags & NETTXF_more_data) ? " more_data" : "",
(txreq.flags & NETTXF_extra_info) ? " extra_info" : "");
- page = xengnttab_map_grant_ref(netdev->xendev.gnttabdev,
- netdev->xendev.dom,
- txreq.gref, PROT_READ);
+ page = xen_be_map_grant_ref(&netdev->xendev, txreq.gref,
+ PROT_READ);
if (page == NULL) {
xen_pv_printf(&netdev->xendev, 0,
"error: tx gref dereference failed (%d)\n",
@@ -183,7 +182,7 @@ static void net_tx_packets(struct XenNetDev *netdev)
qemu_send_packet(qemu_get_queue(netdev->nic),
page + txreq.offset, txreq.size);
}
- xengnttab_unmap(netdev->xendev.gnttabdev, page, 1);
+ xen_be_unmap_grant_ref(&netdev->xendev, page);
net_tx_response(netdev, &txreq, NETIF_RSP_OKAY);
}
if (!netdev->tx_work) {
@@ -254,9 +253,7 @@ static ssize_t net_rx_packet(NetClientState *nc, const uint8_t *buf, size_t size
memcpy(&rxreq, RING_GET_REQUEST(&netdev->rx_ring, rc), sizeof(rxreq));
netdev->rx_ring.req_cons = ++rc;
- page = xengnttab_map_grant_ref(netdev->xendev.gnttabdev,
- netdev->xendev.dom,
- rxreq.gref, PROT_WRITE);
+ page = xen_be_map_grant_ref(&netdev->xendev, rxreq.gref, PROT_WRITE);
if (page == NULL) {
xen_pv_printf(&netdev->xendev, 0,
"error: rx gref dereference failed (%d)\n",
@@ -265,7 +262,7 @@ static ssize_t net_rx_packet(NetClientState *nc, const uint8_t *buf, size_t size
return -1;
}
memcpy(page + NET_IP_ALIGN, buf, size);
- xengnttab_unmap(netdev->xendev.gnttabdev, page, 1);
+ xen_be_unmap_grant_ref(&netdev->xendev, page);
net_rx_response(netdev, &rxreq, NETIF_RSP_OKAY, NET_IP_ALIGN, size, 0);
return size;
@@ -338,19 +335,17 @@ static int net_connect(struct XenDevice *xendev)
return -1;
}
- netdev->txs = xengnttab_map_grant_ref(netdev->xendev.gnttabdev,
- netdev->xendev.dom,
- netdev->tx_ring_ref,
- PROT_READ | PROT_WRITE);
+ netdev->txs = xen_be_map_grant_ref(&netdev->xendev,
+ netdev->tx_ring_ref,
+ PROT_READ | PROT_WRITE);
if (!netdev->txs) {
return -1;
}
- netdev->rxs = xengnttab_map_grant_ref(netdev->xendev.gnttabdev,
- netdev->xendev.dom,
- netdev->rx_ring_ref,
- PROT_READ | PROT_WRITE);
+ netdev->rxs = xen_be_map_grant_ref(&netdev->xendev,
+ netdev->rx_ring_ref,
+ PROT_READ | PROT_WRITE);
if (!netdev->rxs) {
- xengnttab_unmap(netdev->xendev.gnttabdev, netdev->txs, 1);
+ xen_be_unmap_grant_ref(&netdev->xendev, netdev->txs);
netdev->txs = NULL;
return -1;
}
@@ -375,11 +370,11 @@ static void net_disconnect(struct XenDevice *xendev)
xen_pv_unbind_evtchn(&netdev->xendev);
if (netdev->txs) {
- xengnttab_unmap(netdev->xendev.gnttabdev, netdev->txs, 1);
+ xen_be_unmap_grant_ref(&netdev->xendev, netdev->txs);
netdev->txs = NULL;
}
if (netdev->rxs) {
- xengnttab_unmap(netdev->xendev.gnttabdev, netdev->rxs, 1);
+ xen_be_unmap_grant_ref(&netdev->xendev, netdev->rxs);
netdev->rxs = NULL;
}
}
diff --git a/hw/nvram/eeprom_at24c.c b/hw/nvram/eeprom_at24c.c
index 22183f5360..27cd01e615 100644
--- a/hw/nvram/eeprom_at24c.c
+++ b/hw/nvram/eeprom_at24c.c
@@ -116,31 +116,29 @@ int at24c_eeprom_send(I2CSlave *s, uint8_t data)
return 0;
}
-static
-int at24c_eeprom_init(I2CSlave *i2c)
+static void at24c_eeprom_realize(DeviceState *dev, Error **errp)
{
- EEPROMState *ee = AT24C_EE(i2c);
-
- ee->mem = g_malloc0(ee->rsize);
+ EEPROMState *ee = AT24C_EE(dev);
if (ee->blk) {
int64_t len = blk_getlength(ee->blk);
if (len != ee->rsize) {
- ERR(TYPE_AT24C_EE " : Backing file size %lu != %u\n",
- (unsigned long)len, (unsigned)ee->rsize);
- exit(1);
+ error_setg(errp, "%s: Backing file size %" PRId64 " != %u",
+ TYPE_AT24C_EE, len, ee->rsize);
+ return;
}
if (blk_set_perm(ee->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
BLK_PERM_ALL, &error_fatal) < 0)
{
- ERR(TYPE_AT24C_EE
- " : Backing file incorrect permission\n");
- exit(1);
+ error_setg(errp, "%s: Backing file incorrect permission",
+ TYPE_AT24C_EE);
+ return;
}
}
- return 0;
+
+ ee->mem = g_malloc0(ee->rsize);
}
static
@@ -178,7 +176,7 @@ void at24c_eeprom_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
- k->init = &at24c_eeprom_init;
+ dc->realize = &at24c_eeprom_realize;
k->event = &at24c_eeprom_event;
k->recv = &at24c_eeprom_recv;
k->send = &at24c_eeprom_send;
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index 2a0739d0e9..b23e7f64a8 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -420,14 +420,16 @@ static void fw_cfg_dma_mem_write(void *opaque, hwaddr addr,
}
static bool fw_cfg_dma_mem_valid(void *opaque, hwaddr addr,
- unsigned size, bool is_write)
+ unsigned size, bool is_write,
+ MemTxAttrs attrs)
{
return !is_write || ((size == 4 && (addr == 0 || addr == 4)) ||
(size == 8 && addr == 0));
}
static bool fw_cfg_data_mem_valid(void *opaque, hwaddr addr,
- unsigned size, bool is_write)
+ unsigned size, bool is_write,
+ MemTxAttrs attrs)
{
return addr == 0;
}
@@ -439,7 +441,8 @@ static void fw_cfg_ctl_mem_write(void *opaque, hwaddr addr,
}
static bool fw_cfg_ctl_mem_valid(void *opaque, hwaddr addr,
- unsigned size, bool is_write)
+ unsigned size, bool is_write,
+ MemTxAttrs attrs)
{
return is_write && size == 2;
}
@@ -458,7 +461,8 @@ static void fw_cfg_comb_write(void *opaque, hwaddr addr,
}
static bool fw_cfg_comb_valid(void *opaque, hwaddr addr,
- unsigned size, bool is_write)
+ unsigned size, bool is_write,
+ MemTxAttrs attrs)
{
return (size == 1) || (is_write && size == 2);
}
diff --git a/hw/pci-host/versatile.c b/hw/pci-host/versatile.c
index d0b02bdc47..7b19078c80 100644
--- a/hw/pci-host/versatile.c
+++ b/hw/pci-host/versatile.c
@@ -12,7 +12,6 @@
#include "hw/pci/pci.h"
#include "hw/pci/pci_bus.h"
#include "hw/pci/pci_host.h"
-#include "exec/address-spaces.h"
#include "qemu/log.h"
/* Old and buggy versions of QEMU used the wrong mapping from
diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c
index 0b658931ee..d301067d3b 100644
--- a/hw/ppc/ppc405_boards.c
+++ b/hw/ppc/ppc405_boards.c
@@ -37,7 +37,6 @@
#include "qemu/log.h"
#include "qemu/error-report.h"
#include "hw/loader.h"
-#include "sysemu/blockdev.h"
#include "exec/address-spaces.h"
#define BIOS_FILENAME "ppc405_rom.bin"
diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c
index cb2ab1d1e4..bdc53d2603 100644
--- a/hw/ppc/sam460ex.c
+++ b/hw/ppc/sam460ex.c
@@ -17,7 +17,6 @@
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "hw/hw.h"
-#include "sysemu/blockdev.h"
#include "hw/boards.h"
#include "sysemu/kvm.h"
#include "kvm_ppc.h"
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index ebf30dd60b..2375cbee12 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -35,7 +35,6 @@
#include "elf.h"
#include "net/net.h"
#include "sysemu/device_tree.h"
-#include "sysemu/block-backend.h"
#include "sysemu/cpus.h"
#include "sysemu/hw_accel.h"
#include "kvm_ppc.h"
@@ -4071,18 +4070,18 @@ static const TypeInfo spapr_machine_info = {
type_init(spapr_machine_register_##suffix)
/*
- * pseries-2.13
+ * pseries-3.0
*/
-static void spapr_machine_2_13_instance_options(MachineState *machine)
+static void spapr_machine_3_0_instance_options(MachineState *machine)
{
}
-static void spapr_machine_2_13_class_options(MachineClass *mc)
+static void spapr_machine_3_0_class_options(MachineClass *mc)
{
/* Defaults for the latest behaviour inherited from the base class */
}
-DEFINE_SPAPR_MACHINE(2_13, "2.13", true);
+DEFINE_SPAPR_MACHINE(3_0, "3.0", true);
/*
* pseries-2.12
@@ -4091,18 +4090,18 @@ DEFINE_SPAPR_MACHINE(2_13, "2.13", true);
HW_COMPAT_2_12 \
{ \
.driver = TYPE_POWERPC_CPU, \
- .property = "pre-2.13-migration", \
+ .property = "pre-3.0-migration", \
.value = "on", \
},
static void spapr_machine_2_12_instance_options(MachineState *machine)
{
- spapr_machine_2_13_instance_options(machine);
+ spapr_machine_3_0_instance_options(machine);
}
static void spapr_machine_2_12_class_options(MachineClass *mc)
{
- spapr_machine_2_13_class_options(mc);
+ spapr_machine_3_0_class_options(mc);
SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_12);
}
diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c
index a80cbdd7ee..b4bb90d50b 100644
--- a/hw/ppc/virtex_ml507.c
+++ b/hw/ppc/virtex_ml507.c
@@ -44,8 +44,6 @@
#include "hw/ppc/ppc4xx.h"
#include "ppc405.h"
-#include "sysemu/block-backend.h"
-
#define EPAPR_MAGIC (0x45504150)
#define FLASH_SIZE (16 * 1024 * 1024)
diff --git a/hw/riscv/riscv_htif.c b/hw/riscv/riscv_htif.c
index f73512941f..4f7b11dc37 100644
--- a/hw/riscv/riscv_htif.c
+++ b/hw/riscv/riscv_htif.c
@@ -29,7 +29,6 @@
#include "chardev/char-fe.h"
#include "hw/riscv/riscv_htif.h"
#include "qemu/timer.h"
-#include "exec/address-spaces.h"
#include "qemu/error-report.h"
#define RISCV_DEBUG_HTIF 0
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
index 02a815fd31..d1a5f79678 100644
--- a/hw/s390x/s390-pci-inst.c
+++ b/hw/s390x/s390-pci-inst.c
@@ -762,7 +762,8 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
mr = s390_get_subregion(mr, offset, len);
offset -= mr->addr;
- if (!memory_region_access_valid(mr, offset, len, true)) {
+ if (!memory_region_access_valid(mr, offset, len, true,
+ MEMTXATTRS_UNSPECIFIED)) {
s390_program_interrupt(env, PGM_OPERAND, 6, ra);
return 0;
}
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index e548d341a0..7ae5fb38dd 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -812,23 +812,23 @@ bool css_migration_enabled(void)
.value = "0",\
},
-static void ccw_machine_2_13_instance_options(MachineState *machine)
+static void ccw_machine_3_0_instance_options(MachineState *machine)
{
}
-static void ccw_machine_2_13_class_options(MachineClass *mc)
+static void ccw_machine_3_0_class_options(MachineClass *mc)
{
}
-DEFINE_CCW_MACHINE(2_13, "2.13", true);
+DEFINE_CCW_MACHINE(3_0, "3.0", true);
static void ccw_machine_2_12_instance_options(MachineState *machine)
{
- ccw_machine_2_13_instance_options(machine);
+ ccw_machine_3_0_instance_options(machine);
}
static void ccw_machine_2_12_class_options(MachineClass *mc)
{
- ccw_machine_2_13_class_options(mc);
+ ccw_machine_3_0_class_options(mc);
SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_12);
}
DEFINE_CCW_MACHINE(2_12, "2.12", false);
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index 22df33b509..0a9bec484b 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -13,8 +13,6 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "hw/hw.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
#include "sysemu/sysemu.h"
#include "sysemu/kvm.h"
#include "net/net.h"
diff --git a/hw/scsi/Makefile.objs b/hw/scsi/Makefile.objs
index b188f7242b..718b4c2a68 100644
--- a/hw/scsi/Makefile.objs
+++ b/hw/scsi/Makefile.objs
@@ -8,7 +8,7 @@ common-obj-$(CONFIG_ESP) += esp.o
common-obj-$(CONFIG_ESP_PCI) += esp-pci.o
obj-$(CONFIG_PSERIES) += spapr_vscsi.o
-ifeq ($(CONFIG_VIRTIO),y)
+ifeq ($(CONFIG_VIRTIO_SCSI),y)
obj-y += virtio-scsi.o virtio-scsi-dataplane.o
obj-$(CONFIG_VHOST_SCSI) += vhost-scsi-common.o vhost-scsi.o
obj-$(CONFIG_VHOST_USER_SCSI) += vhost-scsi-common.o vhost-user-scsi.o
diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 64ec285826..9ed9727744 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -564,7 +564,8 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
}
static bool esp_mem_accepts(void *opaque, hwaddr addr,
- unsigned size, bool is_write)
+ unsigned size, bool is_write,
+ MemTxAttrs attrs)
{
return (size == 1) || (is_write && size == 4);
}
diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c
index 3f061f3f68..4176e871e1 100644
--- a/hw/scsi/mptsas.c
+++ b/hw/scsi/mptsas.c
@@ -26,7 +26,6 @@
#include "hw/hw.h"
#include "hw/pci/pci.h"
#include "sysemu/dma.h"
-#include "sysemu/block-backend.h"
#include "hw/pci/msi.h"
#include "qemu/iov.h"
#include "hw/scsi/scsi.h"
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index 381f04e339..03bce8ff39 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -17,7 +17,6 @@
#include "qemu/error-report.h"
#include "hw/scsi/scsi.h"
#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
#ifdef __linux__
diff --git a/hw/sd/pl181.c b/hw/sd/pl181.c
index 3ba1f7dd23..1cc94dbfdf 100644
--- a/hw/sd/pl181.c
+++ b/hw/sd/pl181.c
@@ -8,7 +8,6 @@
*/
#include "qemu/osdep.h"
-#include "sysemu/block-backend.h"
#include "sysemu/blockdev.h"
#include "hw/sysbus.h"
#include "hw/sd/sd.h"
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index 63c44a4ee8..3017e5a95a 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -26,8 +26,6 @@
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "hw/hw.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
#include "sysemu/dma.h"
#include "qemu/timer.h"
#include "qemu/bitops.h"
diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c
index ae04b6641b..96542ecd62 100644
--- a/hw/sd/ssi-sd.c
+++ b/hw/sd/ssi-sd.c
@@ -11,7 +11,6 @@
*/
#include "qemu/osdep.h"
-#include "sysemu/block-backend.h"
#include "sysemu/blockdev.h"
#include "hw/ssi/ssi.h"
#include "hw/sd/sd.h"
diff --git a/hw/sh4/r2d.c b/hw/sh4/r2d.c
index 6b01d6eed8..8fe8766eb9 100644
--- a/hw/sh4/r2d.c
+++ b/hw/sh4/r2d.c
@@ -40,7 +40,6 @@
#include "hw/loader.h"
#include "hw/usb.h"
#include "hw/block/flash.h"
-#include "sysemu/block-backend.h"
#include "exec/address-spaces.h"
#define FLASH_BASE 0x00000000
diff --git a/hw/sh4/sh7750.c b/hw/sh4/sh7750.c
index 5a7d47d31e..2dc07a904b 100644
--- a/hw/sh4/sh7750.c
+++ b/hw/sh4/sh7750.c
@@ -31,7 +31,6 @@
#include "hw/sh4/sh_intc.h"
#include "cpu.h"
#include "exec/exec-all.h"
-#include "exec/address-spaces.h"
#define NB_DEVICES 4
diff --git a/hw/timer/sh_timer.c b/hw/timer/sh_timer.c
index 9afb2d048c..5f8736cf10 100644
--- a/hw/timer/sh_timer.c
+++ b/hw/timer/sh_timer.c
@@ -13,7 +13,6 @@
#include "hw/sh4/sh.h"
#include "qemu/timer.h"
#include "qemu/main-loop.h"
-#include "exec/address-spaces.h"
#include "hw/ptimer.h"
//#define DEBUG_TIMER
diff --git a/hw/timer/twl92230.c b/hw/timer/twl92230.c
index ef116c636c..3b43b46199 100644
--- a/hw/timer/twl92230.c
+++ b/hw/timer/twl92230.c
@@ -853,10 +853,9 @@ static const VMStateDescription vmstate_menelaus = {
}
};
-static int twl92230_init(I2CSlave *i2c)
+static void twl92230_realize(DeviceState *dev, Error **errp)
{
- DeviceState *dev = DEVICE(i2c);
- MenelausState *s = TWL92230(i2c);
+ MenelausState *s = TWL92230(dev);
s->rtc.hz_tm = timer_new_ms(rtc_clock, menelaus_rtc_hz, s);
/* Three output pins plus one interrupt pin. */
@@ -865,9 +864,7 @@ static int twl92230_init(I2CSlave *i2c)
/* Three input pins plus one power-button pin. */
qdev_init_gpio_in(dev, menelaus_gpio_set, 4);
- menelaus_reset(i2c);
-
- return 0;
+ menelaus_reset(I2C_SLAVE(dev));
}
static void twl92230_class_init(ObjectClass *klass, void *data)
@@ -875,7 +872,7 @@ static void twl92230_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
- sc->init = twl92230_init;
+ dc->realize = twl92230_realize;
sc->event = menelaus_event;
sc->recv = menelaus_rx;
sc->send = menelaus_tx;
diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c
index 6418ef0831..10bc20dbec 100644
--- a/hw/tpm/tpm_emulator.c
+++ b/hw/tpm/tpm_emulator.c
@@ -4,7 +4,7 @@
* Copyright (c) 2017 Intel Corporation
* Author: Amarnath Valluri <amarnath.valluri@intel.com>
*
- * Copyright (c) 2010 - 2013 IBM Corporation
+ * Copyright (c) 2010 - 2013, 2018 IBM Corporation
* Authors:
* Stefan Berger <stefanb@us.ibm.com>
*
@@ -49,6 +49,19 @@
#define TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(S, cap) (((S)->caps & (cap)) == (cap))
/* data structures */
+
+/* blobs from the TPM; part of VM state when migrating */
+typedef struct TPMBlobBuffers {
+ uint32_t permanent_flags;
+ TPMSizedBuffer permanent;
+
+ uint32_t volatil_flags;
+ TPMSizedBuffer volatil;
+
+ uint32_t savestate_flags;
+ TPMSizedBuffer savestate;
+} TPMBlobBuffers;
+
typedef struct TPMEmulator {
TPMBackend parent;
@@ -64,6 +77,8 @@ typedef struct TPMEmulator {
unsigned int established_flag:1;
unsigned int established_flag_cached:1;
+
+ TPMBlobBuffers state_blobs;
} TPMEmulator;
@@ -293,7 +308,8 @@ static int tpm_emulator_set_buffer_size(TPMBackend *tb,
return 0;
}
-static int tpm_emulator_startup_tpm(TPMBackend *tb, size_t buffersize)
+static int tpm_emulator_startup_tpm_resume(TPMBackend *tb, size_t buffersize,
+ bool is_resume)
{
TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
ptm_init init = {
@@ -301,12 +317,17 @@ static int tpm_emulator_startup_tpm(TPMBackend *tb, size_t buffersize)
};
ptm_res res;
+ trace_tpm_emulator_startup_tpm_resume(is_resume, buffersize);
+
if (buffersize != 0 &&
tpm_emulator_set_buffer_size(tb, buffersize, NULL) < 0) {
goto err_exit;
}
- trace_tpm_emulator_startup_tpm();
+ if (is_resume) {
+ init.u.req.init_flags |= cpu_to_be32(PTM_INIT_FLAG_DELETE_VOLATILE);
+ }
+
if (tpm_emulator_ctrlcmd(tpm_emu, CMD_INIT, &init, sizeof(init),
sizeof(init)) < 0) {
error_report("tpm-emulator: could not send INIT: %s",
@@ -325,6 +346,11 @@ err_exit:
return -1;
}
+static int tpm_emulator_startup_tpm(TPMBackend *tb, size_t buffersize)
+{
+ return tpm_emulator_startup_tpm_resume(tb, buffersize, false);
+}
+
static bool tpm_emulator_get_tpm_established_flag(TPMBackend *tb)
{
TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
@@ -423,16 +449,21 @@ static size_t tpm_emulator_get_buffer_size(TPMBackend *tb)
static int tpm_emulator_block_migration(TPMEmulator *tpm_emu)
{
Error *err = NULL;
+ ptm_cap caps = PTM_CAP_GET_STATEBLOB | PTM_CAP_SET_STATEBLOB |
+ PTM_CAP_STOP;
- error_setg(&tpm_emu->migration_blocker,
- "Migration disabled: TPM emulator not yet migratable");
- migrate_add_blocker(tpm_emu->migration_blocker, &err);
- if (err) {
- error_report_err(err);
- error_free(tpm_emu->migration_blocker);
- tpm_emu->migration_blocker = NULL;
+ if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, caps)) {
+ error_setg(&tpm_emu->migration_blocker,
+ "Migration disabled: TPM emulator does not support "
+ "migration");
+ migrate_add_blocker(tpm_emu->migration_blocker, &err);
+ if (err) {
+ error_report_err(err);
+ error_free(tpm_emu->migration_blocker);
+ tpm_emu->migration_blocker = NULL;
- return -1;
+ return -1;
+ }
}
return 0;
@@ -570,6 +601,267 @@ static const QemuOptDesc tpm_emulator_cmdline_opts[] = {
{ /* end of list */ },
};
+/*
+ * Transfer a TPM state blob from the TPM into a provided buffer.
+ *
+ * @tpm_emu: TPMEmulator
+ * @type: the type of blob to transfer
+ * @tsb: the TPMSizeBuffer to fill with the blob
+ * @flags: the flags to return to the caller
+ */
+static int tpm_emulator_get_state_blob(TPMEmulator *tpm_emu,
+ uint8_t type,
+ TPMSizedBuffer *tsb,
+ uint32_t *flags)
+{
+ ptm_getstate pgs;
+ ptm_res res;
+ ssize_t n;
+ uint32_t totlength, length;
+
+ tpm_sized_buffer_reset(tsb);
+
+ pgs.u.req.state_flags = cpu_to_be32(PTM_STATE_FLAG_DECRYPTED);
+ pgs.u.req.type = cpu_to_be32(type);
+ pgs.u.req.offset = 0;
+
+ if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_STATEBLOB,
+ &pgs, sizeof(pgs.u.req),
+ offsetof(ptm_getstate, u.resp.data)) < 0) {
+ error_report("tpm-emulator: could not get state blob type %d : %s",
+ type, strerror(errno));
+ return -1;
+ }
+
+ res = be32_to_cpu(pgs.u.resp.tpm_result);
+ if (res != 0 && (res & 0x800) == 0) {
+ error_report("tpm-emulator: Getting the stateblob (type %d) failed "
+ "with a TPM error 0x%x", type, res);
+ return -1;
+ }
+
+ totlength = be32_to_cpu(pgs.u.resp.totlength);
+ length = be32_to_cpu(pgs.u.resp.length);
+ if (totlength != length) {
+ error_report("tpm-emulator: Expecting to read %u bytes "
+ "but would get %u", totlength, length);
+ return -1;
+ }
+
+ *flags = be32_to_cpu(pgs.u.resp.state_flags);
+
+ if (totlength > 0) {
+ tsb->buffer = g_try_malloc(totlength);
+ if (!tsb->buffer) {
+ error_report("tpm-emulator: Out of memory allocating %u bytes",
+ totlength);
+ return -1;
+ }
+
+ n = qemu_chr_fe_read_all(&tpm_emu->ctrl_chr, tsb->buffer, totlength);
+ if (n != totlength) {
+ error_report("tpm-emulator: Could not read stateblob (type %d); "
+ "expected %u bytes, got %zd",
+ type, totlength, n);
+ return -1;
+ }
+ }
+ tsb->size = totlength;
+
+ trace_tpm_emulator_get_state_blob(type, tsb->size, *flags);
+
+ return 0;
+}
+
+static int tpm_emulator_get_state_blobs(TPMEmulator *tpm_emu)
+{
+ TPMBlobBuffers *state_blobs = &tpm_emu->state_blobs;
+
+ if (tpm_emulator_get_state_blob(tpm_emu, PTM_BLOB_TYPE_PERMANENT,
+ &state_blobs->permanent,
+ &state_blobs->permanent_flags) < 0 ||
+ tpm_emulator_get_state_blob(tpm_emu, PTM_BLOB_TYPE_VOLATILE,
+ &state_blobs->volatil,
+ &state_blobs->volatil_flags) < 0 ||
+ tpm_emulator_get_state_blob(tpm_emu, PTM_BLOB_TYPE_SAVESTATE,
+ &state_blobs->savestate,
+ &state_blobs->savestate_flags) < 0) {
+ goto err_exit;
+ }
+
+ return 0;
+
+ err_exit:
+ tpm_sized_buffer_reset(&state_blobs->volatil);
+ tpm_sized_buffer_reset(&state_blobs->permanent);
+ tpm_sized_buffer_reset(&state_blobs->savestate);
+
+ return -1;
+}
+
+/*
+ * Transfer a TPM state blob to the TPM emulator.
+ *
+ * @tpm_emu: TPMEmulator
+ * @type: the type of TPM state blob to transfer
+ * @tsb: TPMSizedBuffer containing the TPM state blob
+ * @flags: Flags describing the (encryption) state of the TPM state blob
+ */
+static int tpm_emulator_set_state_blob(TPMEmulator *tpm_emu,
+ uint32_t type,
+ TPMSizedBuffer *tsb,
+ uint32_t flags)
+{
+ ssize_t n;
+ ptm_setstate pss;
+ ptm_res tpm_result;
+
+ if (tsb->size == 0) {
+ return 0;
+ }
+
+ pss = (ptm_setstate) {
+ .u.req.state_flags = cpu_to_be32(flags),
+ .u.req.type = cpu_to_be32(type),
+ .u.req.length = cpu_to_be32(tsb->size),
+ };
+
+ /* write the header only */
+ if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_STATEBLOB, &pss,
+ offsetof(ptm_setstate, u.req.data), 0) < 0) {
+ error_report("tpm-emulator: could not set state blob type %d : %s",
+ type, strerror(errno));
+ return -1;
+ }
+
+ /* now the body */
+ n = qemu_chr_fe_write_all(&tpm_emu->ctrl_chr, tsb->buffer, tsb->size);
+ if (n != tsb->size) {
+ error_report("tpm-emulator: Writing the stateblob (type %d) "
+ "failed; could not write %u bytes, but only %zd",
+ type, tsb->size, n);
+ return -1;
+ }
+
+ /* now get the result */
+ n = qemu_chr_fe_read_all(&tpm_emu->ctrl_chr,
+ (uint8_t *)&pss, sizeof(pss.u.resp));
+ if (n != sizeof(pss.u.resp)) {
+ error_report("tpm-emulator: Reading response from writing stateblob "
+ "(type %d) failed; expected %zu bytes, got %zd", type,
+ sizeof(pss.u.resp), n);
+ return -1;
+ }
+
+ tpm_result = be32_to_cpu(pss.u.resp.tpm_result);
+ if (tpm_result != 0) {
+ error_report("tpm-emulator: Setting the stateblob (type %d) failed "
+ "with a TPM error 0x%x", type, tpm_result);
+ return -1;
+ }
+
+ trace_tpm_emulator_set_state_blob(type, tsb->size, flags);
+
+ return 0;
+}
+
+/*
+ * Set all the TPM state blobs.
+ *
+ * Returns a negative errno code in case of error.
+ */
+static int tpm_emulator_set_state_blobs(TPMBackend *tb)
+{
+ TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
+ TPMBlobBuffers *state_blobs = &tpm_emu->state_blobs;
+
+ trace_tpm_emulator_set_state_blobs();
+
+ if (tpm_emulator_stop_tpm(tb) < 0) {
+ trace_tpm_emulator_set_state_blobs_error("Could not stop TPM");
+ return -EIO;
+ }
+
+ if (tpm_emulator_set_state_blob(tpm_emu, PTM_BLOB_TYPE_PERMANENT,
+ &state_blobs->permanent,
+ state_blobs->permanent_flags) < 0 ||
+ tpm_emulator_set_state_blob(tpm_emu, PTM_BLOB_TYPE_VOLATILE,
+ &state_blobs->volatil,
+ state_blobs->volatil_flags) < 0 ||
+ tpm_emulator_set_state_blob(tpm_emu, PTM_BLOB_TYPE_SAVESTATE,
+ &state_blobs->savestate,
+ state_blobs->savestate_flags) < 0) {
+ return -EIO;
+ }
+
+ trace_tpm_emulator_set_state_blobs_done();
+
+ return 0;
+}
+
+static int tpm_emulator_pre_save(void *opaque)
+{
+ TPMBackend *tb = opaque;
+ TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
+
+ trace_tpm_emulator_pre_save();
+
+ tpm_backend_finish_sync(tb);
+
+ /* get the state blobs from the TPM */
+ return tpm_emulator_get_state_blobs(tpm_emu);
+}
+
+/*
+ * Load the TPM state blobs into the TPM.
+ *
+ * Returns negative errno codes in case of error.
+ */
+static int tpm_emulator_post_load(void *opaque, int version_id)
+{
+ TPMBackend *tb = opaque;
+ int ret;
+
+ ret = tpm_emulator_set_state_blobs(tb);
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (tpm_emulator_startup_tpm_resume(tb, 0, true) < 0) {
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_tpm_emulator = {
+ .name = "tpm-emulator",
+ .version_id = 0,
+ .pre_save = tpm_emulator_pre_save,
+ .post_load = tpm_emulator_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(state_blobs.permanent_flags, TPMEmulator),
+ VMSTATE_UINT32(state_blobs.permanent.size, TPMEmulator),
+ VMSTATE_VBUFFER_ALLOC_UINT32(state_blobs.permanent.buffer,
+ TPMEmulator, 0, 0,
+ state_blobs.permanent.size),
+
+ VMSTATE_UINT32(state_blobs.volatil_flags, TPMEmulator),
+ VMSTATE_UINT32(state_blobs.volatil.size, TPMEmulator),
+ VMSTATE_VBUFFER_ALLOC_UINT32(state_blobs.volatil.buffer,
+ TPMEmulator, 0, 0,
+ state_blobs.volatil.size),
+
+ VMSTATE_UINT32(state_blobs.savestate_flags, TPMEmulator),
+ VMSTATE_UINT32(state_blobs.savestate.size, TPMEmulator),
+ VMSTATE_VBUFFER_ALLOC_UINT32(state_blobs.savestate.buffer,
+ TPMEmulator, 0, 0,
+ state_blobs.savestate.size),
+
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static void tpm_emulator_inst_init(Object *obj)
{
TPMEmulator *tpm_emu = TPM_EMULATOR(obj);
@@ -579,6 +871,8 @@ static void tpm_emulator_inst_init(Object *obj)
tpm_emu->options = g_new0(TPMEmulatorOptions, 1);
tpm_emu->cur_locty_number = ~0;
qemu_mutex_init(&tpm_emu->mutex);
+
+ vmstate_register(NULL, -1, &vmstate_tpm_emulator, obj);
}
/*
@@ -600,6 +894,7 @@ static void tpm_emulator_shutdown(TPMEmulator *tpm_emu)
static void tpm_emulator_inst_finalize(Object *obj)
{
TPMEmulator *tpm_emu = TPM_EMULATOR(obj);
+ TPMBlobBuffers *state_blobs = &tpm_emu->state_blobs;
tpm_emulator_shutdown(tpm_emu);
@@ -614,7 +909,13 @@ static void tpm_emulator_inst_finalize(Object *obj)
error_free(tpm_emu->migration_blocker);
}
+ tpm_sized_buffer_reset(&state_blobs->volatil);
+ tpm_sized_buffer_reset(&state_blobs->permanent);
+ tpm_sized_buffer_reset(&state_blobs->savestate);
+
qemu_mutex_destroy(&tpm_emu->mutex);
+
+ vmstate_unregister(NULL, &vmstate_tpm_emulator, obj);
}
static void tpm_emulator_class_init(ObjectClass *klass, void *data)
diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c
index 2ac7e74307..12f5c9a759 100644
--- a/hw/tpm/tpm_tis.c
+++ b/hw/tpm/tpm_tis.c
@@ -894,9 +894,57 @@ static void tpm_tis_reset(DeviceState *dev)
tpm_backend_startup_tpm(s->be_driver, s->be_buffer_size);
}
+/* persistent state handling */
+
+static int tpm_tis_pre_save(void *opaque)
+{
+ TPMState *s = opaque;
+ uint8_t locty = s->active_locty;
+
+ trace_tpm_tis_pre_save(locty, s->rw_offset);
+
+ if (DEBUG_TIS) {
+ tpm_tis_dump_state(opaque, 0);
+ }
+
+ /*
+ * Synchronize with backend completion.
+ */
+ tpm_backend_finish_sync(s->be_driver);
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_locty = {
+ .name = "tpm-tis/locty",
+ .version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(state, TPMLocality),
+ VMSTATE_UINT32(inte, TPMLocality),
+ VMSTATE_UINT32(ints, TPMLocality),
+ VMSTATE_UINT8(access, TPMLocality),
+ VMSTATE_UINT32(sts, TPMLocality),
+ VMSTATE_UINT32(iface_id, TPMLocality),
+ VMSTATE_END_OF_LIST(),
+ }
+};
+
static const VMStateDescription vmstate_tpm_tis = {
- .name = "tpm",
- .unmigratable = 1,
+ .name = "tpm-tis",
+ .version_id = 0,
+ .pre_save = tpm_tis_pre_save,
+ .fields = (VMStateField[]) {
+ VMSTATE_BUFFER(buffer, TPMState),
+ VMSTATE_UINT16(rw_offset, TPMState),
+ VMSTATE_UINT8(active_locty, TPMState),
+ VMSTATE_UINT8(aborting_locty, TPMState),
+ VMSTATE_UINT8(next_locty, TPMState),
+
+ VMSTATE_STRUCT_ARRAY(loc, TPMState, TPM_TIS_NUM_LOCALITIES, 0,
+ vmstate_locty, TPMLocality),
+
+ VMSTATE_END_OF_LIST()
+ }
};
static Property tpm_tis_properties[] = {
diff --git a/hw/tpm/trace-events b/hw/tpm/trace-events
index 9a65384088..25bee0cecf 100644
--- a/hw/tpm/trace-events
+++ b/hw/tpm/trace-events
@@ -20,13 +20,19 @@ tpm_emulator_set_locality(uint8_t locty) "setting locality to %d"
tpm_emulator_handle_request(void) "processing TPM command"
tpm_emulator_probe_caps(uint64_t caps) "capabilities: 0x%"PRIx64
tpm_emulator_set_buffer_size(uint32_t buffersize, uint32_t minsize, uint32_t maxsize) "buffer size: %u, min: %u, max: %u"
-tpm_emulator_startup_tpm(void) "startup"
+tpm_emulator_startup_tpm_resume(bool is_resume, size_t buffersize) "is_resume: %d, buffer size: %zu"
tpm_emulator_get_tpm_established_flag(uint8_t flag) "got established flag: %d"
tpm_emulator_cancel_cmd_not_supt(void) "Backend does not support CANCEL_TPM_CMD"
tpm_emulator_handle_device_opts_tpm12(void) "TPM Version 1.2"
tpm_emulator_handle_device_opts_tpm2(void) "TPM Version 2"
tpm_emulator_handle_device_opts_unspec(void) "TPM Version Unspecified"
tpm_emulator_handle_device_opts_startup_error(void) "Startup error"
+tpm_emulator_get_state_blob(uint8_t type, uint32_t size, uint32_t flags) "got state blob type %d, %u bytes, flags 0x%08x"
+tpm_emulator_set_state_blob(uint8_t type, uint32_t size, uint32_t flags) "set state blob type %d, %u bytes, flags 0x%08x"
+tpm_emulator_set_state_blobs(void) "setting state blobs"
+tpm_emulator_set_state_blobs_error(const char *msg) "error while setting state blobs: %s"
+tpm_emulator_set_state_blobs_done(void) "Done setting state blobs"
+tpm_emulator_pre_save(void) ""
tpm_emulator_inst_init(void) ""
# hw/tpm/tpm_tis.c
@@ -44,3 +50,4 @@ tpm_tis_mmio_write_locty_seized(uint8_t locty, uint8_t active) "Locality %d seiz
tpm_tis_mmio_write_init_abort(void) "Initiating abort"
tpm_tis_mmio_write_lowering_irq(void) "Lowering IRQ"
tpm_tis_mmio_write_data2send(uint32_t value, unsigned size) "Data to send to TPM: 0x%08x (size=%d)"
+tpm_tis_pre_save(uint8_t locty, uint32_t rw_offset) "locty: %d, rw_offset = %u"
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
index f2f632aeb0..481694a473 100644
--- a/hw/usb/dev-storage.c
+++ b/hw/usb/dev-storage.c
@@ -20,7 +20,6 @@
#include "monitor/monitor.h"
#include "sysemu/sysemu.h"
#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
#include "qapi/visitor.h"
#include "qemu/cutils.h"
diff --git a/hw/usb/xen-usb.c b/hw/usb/xen-usb.c
index b3a90c0e68..5b2e21ed18 100644
--- a/hw/usb/xen-usb.c
+++ b/hw/usb/xen-usb.c
@@ -173,8 +173,9 @@ static int usbback_gnttab_map(struct usbback_req *usbback_req)
for (i = 0; i < usbback_req->nr_buffer_segs; i++) {
ref[i] = usbback_req->req.seg[i].gref;
}
- usbback_req->buffer = xengnttab_map_domain_grant_refs(xendev->gnttabdev,
- usbback_req->nr_buffer_segs, xendev->dom, ref, prot);
+ usbback_req->buffer =
+ xen_be_map_grant_refs(xendev, ref, usbback_req->nr_buffer_segs,
+ prot);
if (!usbback_req->buffer) {
return -ENOMEM;
@@ -206,8 +207,9 @@ static int usbback_gnttab_map(struct usbback_req *usbback_req)
for (i = 0; i < usbback_req->nr_extra_segs; i++) {
ref[i] = usbback_req->req.seg[i + usbback_req->req.nr_buffer_segs].gref;
}
- usbback_req->isoc_buffer = xengnttab_map_domain_grant_refs(
- xendev->gnttabdev, usbback_req->nr_extra_segs, xendev->dom, ref, prot);
+ usbback_req->isoc_buffer =
+ xen_be_map_grant_refs(xendev, ref, usbback_req->nr_extra_segs,
+ prot);
if (!usbback_req->isoc_buffer) {
return -ENOMEM;
@@ -291,14 +293,14 @@ static void usbback_do_response(struct usbback_req *usbback_req, int32_t status,
}
if (usbback_req->buffer) {
- xengnttab_unmap(xendev->gnttabdev, usbback_req->buffer,
- usbback_req->nr_buffer_segs);
+ xen_be_unmap_grant_refs(xendev, usbback_req->buffer,
+ usbback_req->nr_buffer_segs);
usbback_req->buffer = NULL;
}
if (usbback_req->isoc_buffer) {
- xengnttab_unmap(xendev->gnttabdev, usbback_req->isoc_buffer,
- usbback_req->nr_extra_segs);
+ xen_be_unmap_grant_refs(xendev, usbback_req->isoc_buffer,
+ usbback_req->nr_extra_segs);
usbback_req->isoc_buffer = NULL;
}
@@ -834,11 +836,11 @@ static void usbback_disconnect(struct XenDevice *xendev)
xen_pv_unbind_evtchn(xendev);
if (usbif->urb_sring) {
- xengnttab_unmap(xendev->gnttabdev, usbif->urb_sring, 1);
+ xen_be_unmap_grant_ref(xendev, usbif->urb_sring);
usbif->urb_sring = NULL;
}
if (usbif->conn_sring) {
- xengnttab_unmap(xendev->gnttabdev, usbif->conn_sring, 1);
+ xen_be_unmap_grant_ref(xendev, usbif->conn_sring);
usbif->conn_sring = NULL;
}
@@ -877,12 +879,10 @@ static int usbback_connect(struct XenDevice *xendev)
return -1;
}
- usbif->urb_sring = xengnttab_map_grant_ref(xendev->gnttabdev, xendev->dom,
- urb_ring_ref,
- PROT_READ | PROT_WRITE);
- usbif->conn_sring = xengnttab_map_grant_ref(xendev->gnttabdev, xendev->dom,
- conn_ring_ref,
- PROT_READ | PROT_WRITE);
+ usbif->urb_sring = xen_be_map_grant_ref(xendev, urb_ring_ref,
+ PROT_READ | PROT_WRITE);
+ usbif->conn_sring = xen_be_map_grant_ref(xendev, conn_ring_ref,
+ PROT_READ | PROT_WRITE);
if (!usbif->urb_sring || !usbif->conn_sring) {
xen_pv_printf(xendev, 0, "error mapping rings\n");
usbback_disconnect(xendev);
@@ -1024,10 +1024,7 @@ static void usbback_alloc(struct XenDevice *xendev)
/* max_grants: for each request and for the rings (request and connect). */
max_grants = USBIF_MAX_SEGMENTS_PER_REQUEST * USB_URB_RING_SIZE + 2;
- if (xengnttab_set_max_grants(xendev->gnttabdev, max_grants) < 0) {
- xen_pv_printf(xendev, 0, "xengnttab_set_max_grants failed: %s\n",
- strerror(errno));
- }
+ xen_be_set_max_grant_refs(xendev, max_grants);
}
static int usbback_free(struct XenDevice *xendev)
diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c
index e67392c5f9..76e4e8c652 100644
--- a/hw/vfio/ccw.c
+++ b/hw/vfio/ccw.c
@@ -22,6 +22,7 @@
#include "hw/vfio/vfio-common.h"
#include "hw/s390x/s390-ccw.h"
#include "hw/s390x/ccw-device.h"
+#include "exec/address-spaces.h"
#include "qemu/error-report.h"
#define TYPE_VFIO_CCW "vfio-ccw"
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index 07ffa0ba10..8e57265edf 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -324,7 +324,8 @@ static bool vfio_get_vaddr(IOMMUTLBEntry *iotlb, void **vaddr,
*/
mr = address_space_translate(&address_space_memory,
iotlb->translated_addr,
- &xlat, &len, writable);
+ &xlat, &len, writable,
+ MEMTXATTRS_UNSPECIFIED);
if (!memory_region_is_ram(mr)) {
error_report("iommu map to non memory area %"HWADDR_PRIx"",
xlat);
diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c
index 5c921c27ba..57c4a0ee2b 100644
--- a/hw/vfio/platform.c
+++ b/hw/vfio/platform.c
@@ -24,6 +24,7 @@
#include "qemu/range.h"
#include "sysemu/sysemu.h"
#include "exec/memory.h"
+#include "exec/address-spaces.h"
#include "qemu/queue.h"
#include "hw/sysbus.h"
#include "trace.h"
diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs
index 030969e28c..1b2799cfd8 100644
--- a/hw/virtio/Makefile.objs
+++ b/hw/virtio/Makefile.objs
@@ -1,14 +1,16 @@
ifeq ($(CONFIG_VIRTIO),y)
-common-obj-y += virtio-rng.o
-common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
common-obj-y += virtio-bus.o
-common-obj-y += virtio-mmio.o
+obj-y += virtio.o
+
+common-obj-$(CONFIG_VIRTIO_RNG) += virtio-rng.o
+common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
+common-obj-$(CONFIG_VIRTIO_MMIO) += virtio-mmio.o
+obj-$(CONFIG_VIRTIO_BALLOON) += virtio-balloon.o
+obj-$(CONFIG_VIRTIO_CRYPTO) += virtio-crypto.o
+obj-$(call land,$(CONFIG_VIRTIO_CRYPTO),$(CONFIG_VIRTIO_PCI)) += virtio-crypto-pci.o
-obj-y += virtio.o virtio-balloon.o
obj-$(CONFIG_LINUX) += vhost.o vhost-backend.o vhost-user.o
obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock.o
-obj-y += virtio-crypto.o
-obj-$(CONFIG_VIRTIO_PCI) += virtio-crypto-pci.o
endif
common-obj-$(call lnot,$(call land,$(CONFIG_VIRTIO),$(CONFIG_LINUX))) += vhost-stub.o
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 624ade9682..96175b214d 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -902,7 +902,8 @@ int vhost_device_iotlb_miss(struct vhost_dev *dev, uint64_t iova, int write)
trace_vhost_iotlb_miss(dev, 1);
iotlb = address_space_get_iotlb_entry(dev->vdev->dma_as,
- iova, write);
+ iova, write,
+ MEMTXATTRS_UNSPECIFIED);
if (iotlb.target_as != NULL) {
ret = vhost_memory_region_lookup(dev, iotlb.translated_addr,
&uaddr, &len);
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 5eb0c323ca..3a01fe90f0 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -32,7 +32,6 @@
#include "hw/pci/msix.h"
#include "hw/loader.h"
#include "sysemu/kvm.h"
-#include "sysemu/block-backend.h"
#include "virtio-pci.h"
#include "qemu/range.h"
#include "hw/virtio/virtio-bus.h"
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 1debb0147b..d4e4d98b59 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -123,11 +123,22 @@ static void virtio_free_region_cache(VRingMemoryRegionCaches *caches)
g_free(caches);
}
+static void virtio_virtqueue_reset_region_cache(struct VirtQueue *vq)
+{
+ VRingMemoryRegionCaches *caches;
+
+ caches = atomic_read(&vq->vring.caches);
+ atomic_rcu_set(&vq->vring.caches, NULL);
+ if (caches) {
+ call_rcu(caches, virtio_free_region_cache, rcu);
+ }
+}
+
static void virtio_init_region_cache(VirtIODevice *vdev, int n)
{
VirtQueue *vq = &vdev->vq[n];
VRingMemoryRegionCaches *old = vq->vring.caches;
- VRingMemoryRegionCaches *new;
+ VRingMemoryRegionCaches *new = NULL;
hwaddr addr, size;
int event_size;
int64_t len;
@@ -136,7 +147,7 @@ static void virtio_init_region_cache(VirtIODevice *vdev, int n)
addr = vq->vring.desc;
if (!addr) {
- return;
+ goto out_no_cache;
}
new = g_new0(VRingMemoryRegionCaches, 1);
size = virtio_queue_get_desc_size(vdev, n);
@@ -170,11 +181,14 @@ static void virtio_init_region_cache(VirtIODevice *vdev, int n)
return;
err_avail:
- address_space_cache_destroy(&new->used);
+ address_space_cache_destroy(&new->avail);
err_used:
- address_space_cache_destroy(&new->desc);
+ address_space_cache_destroy(&new->used);
err_desc:
+ address_space_cache_destroy(&new->desc);
+out_no_cache:
g_free(new);
+ virtio_virtqueue_reset_region_cache(vq);
}
/* virt queue functions */
@@ -1168,17 +1182,6 @@ static enum virtio_device_endian virtio_current_cpu_endian(void)
}
}
-static void virtio_virtqueue_reset_region_cache(struct VirtQueue *vq)
-{
- VRingMemoryRegionCaches *caches;
-
- caches = atomic_read(&vq->vring.caches);
- atomic_rcu_set(&vq->vring.caches, NULL);
- if (caches) {
- call_rcu(caches, virtio_free_region_cache, rcu);
- }
-}
-
void virtio_reset(void *opaque)
{
VirtIODevice *vdev = opaque;
diff --git a/hw/xen/xen_backend.c b/hw/xen/xen_backend.c
index 7445b506ac..9a8e8771ec 100644
--- a/hw/xen/xen_backend.c
+++ b/hw/xen/xen_backend.c
@@ -44,9 +44,9 @@ BusState *xen_sysbus;
/* public */
struct xs_handle *xenstore = NULL;
const char *xen_protocol;
-bool xen_feature_grant_copy;
/* private */
+static bool xen_feature_grant_copy;
static int debug;
int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val)
@@ -106,6 +106,156 @@ int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state)
return 0;
}
+void xen_be_set_max_grant_refs(struct XenDevice *xendev,
+ unsigned int nr_refs)
+{
+ assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV);
+
+ if (xengnttab_set_max_grants(xendev->gnttabdev, nr_refs)) {
+ xen_pv_printf(xendev, 0, "xengnttab_set_max_grants failed: %s\n",
+ strerror(errno));
+ }
+}
+
+void *xen_be_map_grant_refs(struct XenDevice *xendev, uint32_t *refs,
+ unsigned int nr_refs, int prot)
+{
+ void *ptr;
+
+ assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV);
+
+ ptr = xengnttab_map_domain_grant_refs(xendev->gnttabdev, nr_refs,
+ xen_domid, refs, prot);
+ if (!ptr) {
+ xen_pv_printf(xendev, 0,
+ "xengnttab_map_domain_grant_refs failed: %s\n",
+ strerror(errno));
+ }
+
+ return ptr;
+}
+
+void xen_be_unmap_grant_refs(struct XenDevice *xendev, void *ptr,
+ unsigned int nr_refs)
+{
+ assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV);
+
+ if (xengnttab_unmap(xendev->gnttabdev, ptr, nr_refs)) {
+ xen_pv_printf(xendev, 0, "xengnttab_unmap failed: %s\n",
+ strerror(errno));
+ }
+}
+
+static int compat_copy_grant_refs(struct XenDevice *xendev,
+ bool to_domain,
+ XenGrantCopySegment segs[],
+ unsigned int nr_segs)
+{
+ uint32_t *refs = g_new(uint32_t, nr_segs);
+ int prot = to_domain ? PROT_WRITE : PROT_READ;
+ void *pages;
+ unsigned int i;
+
+ for (i = 0; i < nr_segs; i++) {
+ XenGrantCopySegment *seg = &segs[i];
+
+ refs[i] = to_domain ?
+ seg->dest.foreign.ref : seg->source.foreign.ref;
+ }
+
+ pages = xengnttab_map_domain_grant_refs(xendev->gnttabdev, nr_segs,
+ xen_domid, refs, prot);
+ if (!pages) {
+ xen_pv_printf(xendev, 0,
+ "xengnttab_map_domain_grant_refs failed: %s\n",
+ strerror(errno));
+ g_free(refs);
+ return -1;
+ }
+
+ for (i = 0; i < nr_segs; i++) {
+ XenGrantCopySegment *seg = &segs[i];
+ void *page = pages + (i * XC_PAGE_SIZE);
+
+ if (to_domain) {
+ memcpy(page + seg->dest.foreign.offset, seg->source.virt,
+ seg->len);
+ } else {
+ memcpy(seg->dest.virt, page + seg->source.foreign.offset,
+ seg->len);
+ }
+ }
+
+ if (xengnttab_unmap(xendev->gnttabdev, pages, nr_segs)) {
+ xen_pv_printf(xendev, 0, "xengnttab_unmap failed: %s\n",
+ strerror(errno));
+ }
+
+ g_free(refs);
+ return 0;
+}
+
+int xen_be_copy_grant_refs(struct XenDevice *xendev,
+ bool to_domain,
+ XenGrantCopySegment segs[],
+ unsigned int nr_segs)
+{
+ xengnttab_grant_copy_segment_t *xengnttab_segs;
+ unsigned int i;
+ int rc;
+
+ assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV);
+
+ if (!xen_feature_grant_copy) {
+ return compat_copy_grant_refs(xendev, to_domain, segs, nr_segs);
+ }
+
+ xengnttab_segs = g_new0(xengnttab_grant_copy_segment_t, nr_segs);
+
+ for (i = 0; i < nr_segs; i++) {
+ XenGrantCopySegment *seg = &segs[i];
+ xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i];
+
+ if (to_domain) {
+ xengnttab_seg->flags = GNTCOPY_dest_gref;
+ xengnttab_seg->dest.foreign.domid = xen_domid;
+ xengnttab_seg->dest.foreign.ref = seg->dest.foreign.ref;
+ xengnttab_seg->dest.foreign.offset = seg->dest.foreign.offset;
+ xengnttab_seg->source.virt = seg->source.virt;
+ } else {
+ xengnttab_seg->flags = GNTCOPY_source_gref;
+ xengnttab_seg->source.foreign.domid = xen_domid;
+ xengnttab_seg->source.foreign.ref = seg->source.foreign.ref;
+ xengnttab_seg->source.foreign.offset =
+ seg->source.foreign.offset;
+ xengnttab_seg->dest.virt = seg->dest.virt;
+ }
+
+ xengnttab_seg->len = seg->len;
+ }
+
+ rc = xengnttab_grant_copy(xendev->gnttabdev, nr_segs, xengnttab_segs);
+
+ if (rc) {
+ xen_pv_printf(xendev, 0, "xengnttab_copy failed: %s\n",
+ strerror(errno));
+ }
+
+ for (i = 0; i < nr_segs; i++) {
+ xengnttab_grant_copy_segment_t *xengnttab_seg =
+ &xengnttab_segs[i];
+
+ if (xengnttab_seg->status != GNTST_okay) {
+ xen_pv_printf(xendev, 0, "segment[%u] status: %d\n", i,
+ xengnttab_seg->status);
+ rc = -1;
+ }
+ }
+
+ g_free(xengnttab_segs);
+ return rc;
+}
+
/*
* get xen backend device, allocate a new one if it doesn't exist.
*/
@@ -149,18 +299,6 @@ static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
}
qemu_set_cloexec(xenevtchn_fd(xendev->evtchndev));
- if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
- xendev->gnttabdev = xengnttab_open(NULL, 0);
- if (xendev->gnttabdev == NULL) {
- xen_pv_printf(NULL, 0, "can't open gnttab device\n");
- xenevtchn_close(xendev->evtchndev);
- qdev_unplug(DEVICE(xendev), NULL);
- return NULL;
- }
- } else {
- xendev->gnttabdev = NULL;
- }
-
xen_pv_insert_xendev(xendev);
if (xendev->ops->alloc) {
@@ -322,6 +460,16 @@ static int xen_be_try_initialise(struct XenDevice *xendev)
}
}
+ if (xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
+ xendev->gnttabdev = xengnttab_open(NULL, 0);
+ if (xendev->gnttabdev == NULL) {
+ xen_pv_printf(NULL, 0, "can't open gnttab device\n");
+ return -1;
+ }
+ } else {
+ xendev->gnttabdev = NULL;
+ }
+
if (xendev->ops->initialise) {
rc = xendev->ops->initialise(xendev);
}
@@ -369,6 +517,10 @@ static void xen_be_disconnect(struct XenDevice *xendev, enum xenbus_state state)
xendev->ops->disconnect) {
xendev->ops->disconnect(xendev);
}
+ if (xendev->gnttabdev) {
+ xengnttab_close(xendev->gnttabdev);
+ xendev->gnttabdev = NULL;
+ }
if (xendev->be_state != state) {
xen_be_set_state(xendev, state);
}
diff --git a/hw/xen/xen_devconfig.c b/hw/xen/xen_devconfig.c
index fac9d3fcdc..aebc19bd71 100644
--- a/hw/xen/xen_devconfig.c
+++ b/hw/xen/xen_devconfig.c
@@ -1,7 +1,6 @@
#include "qemu/osdep.h"
#include "hw/xen/xen_backend.h"
#include "qemu/option.h"
-#include "sysemu/block-backend.h"
#include "sysemu/blockdev.h"
/* ------------------------------------------------------------- */
diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c
index 9b7a960de1..e5a6eff44f 100644
--- a/hw/xen/xen_pt.c
+++ b/hw/xen/xen_pt.c
@@ -907,7 +907,7 @@ out:
}
}
- memory_listener_register(&s->memory_listener, &s->dev.bus_master_as);
+ memory_listener_register(&s->memory_listener, &address_space_memory);
memory_listener_register(&s->io_listener, &address_space_io);
s->listener_set = true;
XEN_PT_LOG(d,
diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c
index a3ce33e78b..aee31c62bb 100644
--- a/hw/xen/xen_pt_config_init.c
+++ b/hw/xen/xen_pt_config_init.c
@@ -504,6 +504,8 @@ static int xen_pt_bar_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
bar_ro_mask = XEN_PT_BAR_IO_RO_MASK | (r_size - 1);
break;
case XEN_PT_BAR_FLAG_UPPER:
+ assert(index > 0);
+ r_size = d->io_regions[index - 1].size >> 32;
bar_emu_mask = XEN_PT_BAR_ALLF;
bar_ro_mask = r_size ? r_size - 1 : 0;
break;
diff --git a/hw/xen/xen_pt_msi.c b/hw/xen/xen_pt_msi.c
index 6d1e3bdeb4..cc514f9157 100644
--- a/hw/xen/xen_pt_msi.c
+++ b/hw/xen/xen_pt_msi.c
@@ -498,7 +498,8 @@ static uint64_t pci_msix_read(void *opaque, hwaddr addr,
}
static bool pci_msix_accepts(void *opaque, hwaddr addr,
- unsigned size, bool is_write)
+ unsigned size, bool is_write,
+ MemTxAttrs attrs)
{
return !(addr & (size - 1));
}
diff --git a/hw/xtensa/xtfpga.c b/hw/xtensa/xtfpga.c
index 63734c70ec..5dc13034f9 100644
--- a/hw/xtensa/xtfpga.c
+++ b/hw/xtensa/xtfpga.c
@@ -38,7 +38,6 @@
#include "net/net.h"
#include "hw/sysbus.h"
#include "hw/block/flash.h"
-#include "sysemu/block-backend.h"
#include "chardev/char.h"
#include "sysemu/device_tree.h"
#include "qemu/error-report.h"
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 76b589da57..6c0927bce3 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -1029,7 +1029,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
BlockdevOnError on_target_error,
int creation_flags,
BlockCompletionFunc *cb, void *opaque,
- BlockJobTxn *txn, Error **errp);
+ JobTxn *txn, Error **errp);
void hmp_drive_add_node(Monitor *mon, const char *optstr);
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
index 0f56f723de..32c00b7dc0 100644
--- a/include/block/blockjob.h
+++ b/include/block/blockjob.h
@@ -26,13 +26,13 @@
#ifndef BLOCKJOB_H
#define BLOCKJOB_H
+#include "qemu/job.h"
#include "block/block.h"
#include "qemu/ratelimit.h"
#define BLOCK_JOB_SLICE_TIME 100000000ULL /* ns */
typedef struct BlockJobDriver BlockJobDriver;
-typedef struct BlockJobTxn BlockJobTxn;
/**
* BlockJob:
@@ -40,141 +40,40 @@ typedef struct BlockJobTxn BlockJobTxn;
* Long-running operation on a BlockDriverState.
*/
typedef struct BlockJob {
- /** The job type, including the job vtable. */
- const BlockJobDriver *driver;
+ /** Data belonging to the generic Job infrastructure */
+ Job job;
/** The block device on which the job is operating. */
BlockBackend *blk;
- /**
- * The ID of the block job. May be NULL for internal jobs.
- */
- char *id;
-
- /**
- * The coroutine that executes the job. If not NULL, it is
- * reentered when busy is false and the job is cancelled.
- */
- Coroutine *co;
-
- /**
- * Set to true if the job should cancel itself. The flag must
- * always be tested just before toggling the busy flag from false
- * to true. After a job has been cancelled, it should only yield
- * if #aio_poll will ("sooner or later") reenter the coroutine.
- */
- bool cancelled;
-
- /**
- * Set to true if the job should abort immediately without waiting
- * for data to be in sync.
- */
- bool force;
-
- /**
- * Counter for pause request. If non-zero, the block job is either paused,
- * or if busy == true will pause itself as soon as possible.
- */
- int pause_count;
-
- /**
- * Set to true if the job is paused by user. Can be unpaused with the
- * block-job-resume QMP command.
- */
- bool user_paused;
-
- /**
- * Set to false by the job while the coroutine has yielded and may be
- * re-entered by block_job_enter(). There may still be I/O or event loop
- * activity pending. Accessed under block_job_mutex (in blockjob.c).
- */
- bool busy;
-
- /**
- * Set to true by the job while it is in a quiescent state, where
- * no I/O or event loop activity is pending.
- */
- bool paused;
-
- /**
- * Set to true when the job is ready to be completed.
- */
- bool ready;
-
- /**
- * Set to true when the job has deferred work to the main loop.
- */
- bool deferred_to_main_loop;
-
- /** Element of the list of block jobs */
- QLIST_ENTRY(BlockJob) job_list;
-
/** Status that is published by the query-block-jobs QMP API */
BlockDeviceIoStatus iostatus;
- /** Offset that is published by the query-block-jobs QMP API */
- int64_t offset;
-
- /** Length that is published by the query-block-jobs QMP API */
- int64_t len;
-
/** Speed that was set with @block_job_set_speed. */
int64_t speed;
/** Rate limiting data structure for implementing @speed. */
RateLimit limit;
- /** The completion function that will be called when the job completes. */
- BlockCompletionFunc *cb;
-
/** Block other operations when block job is running */
Error *blocker;
- /** BlockDriverStates that are involved in this block job */
- GSList *nodes;
-
- /** The opaque value that is passed to the completion function. */
- void *opaque;
-
- /** Reference count of the block job */
- int refcnt;
-
- /** True when job has reported completion by calling block_job_completed. */
- bool completed;
-
- /** ret code passed to block_job_completed. */
- int ret;
-
- /**
- * Timer that is used by @block_job_sleep_ns. Accessed under
- * block_job_mutex (in blockjob.c).
- */
- QEMUTimer sleep_timer;
+ /** Called when a cancelled job is finalised. */
+ Notifier finalize_cancelled_notifier;
- /** Current state; See @BlockJobStatus for details. */
- BlockJobStatus status;
+ /** Called when a successfully completed job is finalised. */
+ Notifier finalize_completed_notifier;
- /** True if this job should automatically finalize itself */
- bool auto_finalize;
+ /** Called when the job transitions to PENDING */
+ Notifier pending_notifier;
- /** True if this job should automatically dismiss itself */
- bool auto_dismiss;
+ /** Called when the job transitions to READY */
+ Notifier ready_notifier;
- BlockJobTxn *txn;
- QLIST_ENTRY(BlockJob) txn_list;
+ /** BlockDriverStates that are involved in this block job */
+ GSList *nodes;
} BlockJob;
-typedef enum BlockJobCreateFlags {
- /* Default behavior */
- BLOCK_JOB_DEFAULT = 0x00,
- /* BlockJob is not QMP-created and should not send QMP events */
- BLOCK_JOB_INTERNAL = 0x01,
- /* BlockJob requires manual finalize step */
- BLOCK_JOB_MANUAL_FINALIZE = 0x02,
- /* BlockJob requires manual dismiss step */
- BLOCK_JOB_MANUAL_DISMISS = 0x04,
-} BlockJobCreateFlags;
-
/**
* block_job_next:
* @job: A block job, or %NULL.
@@ -231,78 +130,6 @@ void block_job_remove_all_bdrv(BlockJob *job);
void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp);
/**
- * block_job_start:
- * @job: A job that has not yet been started.
- *
- * Begins execution of a block job.
- * Takes ownership of one reference to the job object.
- */
-void block_job_start(BlockJob *job);
-
-/**
- * block_job_cancel:
- * @job: The job to be canceled.
- * @force: Quit a job without waiting for data to be in sync.
- *
- * Asynchronously cancel the specified job.
- */
-void block_job_cancel(BlockJob *job, bool force);
-
-/**
- * block_job_complete:
- * @job: The job to be completed.
- * @errp: Error object.
- *
- * Asynchronously complete the specified job.
- */
-void block_job_complete(BlockJob *job, Error **errp);
-
-
-/**
- * block_job_finalize:
- * @job: The job to fully commit and finish.
- * @errp: Error object.
- *
- * For jobs that have finished their work and are pending
- * awaiting explicit acknowledgement to commit their work,
- * This will commit that work.
- *
- * FIXME: Make the below statement universally true:
- * For jobs that support the manual workflow mode, all graph
- * changes that occur as a result will occur after this command
- * and before a successful reply.
- */
-void block_job_finalize(BlockJob *job, Error **errp);
-
-/**
- * block_job_dismiss:
- * @job: The job to be dismissed.
- * @errp: Error object.
- *
- * Remove a concluded job from the query list.
- */
-void block_job_dismiss(BlockJob **job, Error **errp);
-
-/**
- * block_job_progress_update:
- * @job: The job that has made progress
- * @done: How much progress the job made
- *
- * Updates the progress counter of the job.
- */
-void block_job_progress_update(BlockJob *job, uint64_t done);
-
-/**
- * block_job_progress_set_remaining:
- * @job: The job whose expected progress end value is set
- * @remaining: Expected end value of the progress counter of the job
- *
- * Sets the expected end value of the progress counter of a job so that a
- * completion percentage can be calculated when the progress is updated.
- */
-void block_job_progress_set_remaining(BlockJob *job, uint64_t remaining);
-
-/**
* block_job_query:
* @job: The job to get information about.
*
@@ -311,78 +138,6 @@ void block_job_progress_set_remaining(BlockJob *job, uint64_t remaining);
BlockJobInfo *block_job_query(BlockJob *job, Error **errp);
/**
- * block_job_user_pause:
- * @job: The job to be paused.
- *
- * Asynchronously pause the specified job.
- * Do not allow a resume until a matching call to block_job_user_resume.
- */
-void block_job_user_pause(BlockJob *job, Error **errp);
-
-/**
- * block_job_paused:
- * @job: The job to query.
- *
- * Returns true if the job is user-paused.
- */
-bool block_job_user_paused(BlockJob *job);
-
-/**
- * block_job_user_resume:
- * @job: The job to be resumed.
- *
- * Resume the specified job.
- * Must be paired with a preceding block_job_user_pause.
- */
-void block_job_user_resume(BlockJob *job, Error **errp);
-
-/**
- * block_job_user_cancel:
- * @job: The job to be cancelled.
- * @force: Quit a job without waiting for data to be in sync.
- *
- * Cancels the specified job, but may refuse to do so if the
- * operation isn't currently meaningful.
- */
-void block_job_user_cancel(BlockJob *job, bool force, Error **errp);
-
-/**
- * block_job_cancel_sync:
- * @job: The job to be canceled.
- *
- * Synchronously cancel the job. The completion callback is called
- * before the function returns. The job may actually complete
- * instead of canceling itself; the circumstances under which this
- * happens depend on the kind of job that is active.
- *
- * Returns the return value from the job if the job actually completed
- * during the call, or -ECANCELED if it was canceled.
- */
-int block_job_cancel_sync(BlockJob *job);
-
-/**
- * block_job_cancel_sync_all:
- *
- * Synchronously cancels all jobs using block_job_cancel_sync().
- */
-void block_job_cancel_sync_all(void);
-
-/**
- * block_job_complete_sync:
- * @job: The job to be completed.
- * @errp: Error object which may be set by block_job_complete(); this is not
- * necessarily set on every error, the job return value has to be
- * checked as well.
- *
- * Synchronously complete the job. The completion callback is called before the
- * function returns, unless it is NULL (which is permissible when using this
- * function).
- *
- * Returns the return value from the job.
- */
-int block_job_complete_sync(BlockJob *job, Error **errp);
-
-/**
* block_job_iostatus_reset:
* @job: The job whose I/O status should be reset.
*
@@ -392,59 +147,6 @@ int block_job_complete_sync(BlockJob *job, Error **errp);
void block_job_iostatus_reset(BlockJob *job);
/**
- * block_job_txn_new:
- *
- * Allocate and return a new block job transaction. Jobs can be added to the
- * transaction using block_job_txn_add_job().
- *
- * The transaction is automatically freed when the last job completes or is
- * cancelled.
- *
- * All jobs in the transaction either complete successfully or fail/cancel as a
- * group. Jobs wait for each other before completing. Cancelling one job
- * cancels all jobs in the transaction.
- */
-BlockJobTxn *block_job_txn_new(void);
-
-/**
- * block_job_ref:
- *
- * Add a reference to BlockJob refcnt, it will be decreased with
- * block_job_unref, and then be freed if it comes to be the last
- * reference.
- */
-void block_job_ref(BlockJob *job);
-
-/**
- * block_job_unref:
- *
- * Release a reference that was previously acquired with block_job_ref
- * or block_job_create. If it's the last reference to the object, it will be
- * freed.
- */
-void block_job_unref(BlockJob *job);
-
-/**
- * block_job_txn_unref:
- *
- * Release a reference that was previously acquired with block_job_txn_add_job
- * or block_job_txn_new. If it's the last reference to the object, it will be
- * freed.
- */
-void block_job_txn_unref(BlockJobTxn *txn);
-
-/**
- * block_job_txn_add_job:
- * @txn: The transaction (may be NULL)
- * @job: Job to add to the transaction
- *
- * Add @job to the transaction. The @job must not already be in a transaction.
- * The caller must call either block_job_txn_unref() or block_job_completed()
- * to release the reference that is automatically grabbed here.
- */
-void block_job_txn_add_job(BlockJobTxn *txn, BlockJob *job);
-
-/**
* block_job_is_internal:
* @job: The job to determine if it is user-visible or not.
*
diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h
index 62ec964d09..5cd50c6639 100644
--- a/include/block/blockjob_int.h
+++ b/include/block/blockjob_int.h
@@ -35,72 +35,8 @@
* A class type for block job driver.
*/
struct BlockJobDriver {
- /** Derived BlockJob struct size */
- size_t instance_size;
-
- /** String describing the operation, part of query-block-jobs QMP API */
- BlockJobType job_type;
-
- /** Mandatory: Entrypoint for the Coroutine. */
- CoroutineEntry *start;
-
- /**
- * Optional callback for job types whose completion must be triggered
- * manually.
- */
- void (*complete)(BlockJob *job, Error **errp);
-
- /**
- * If the callback is not NULL, prepare will be invoked when all the jobs
- * belonging to the same transaction complete; or upon this job's completion
- * if it is not in a transaction.
- *
- * This callback will not be invoked if the job has already failed.
- * If it fails, abort and then clean will be called.
- */
- int (*prepare)(BlockJob *job);
-
- /**
- * If the callback is not NULL, it will be invoked when all the jobs
- * belonging to the same transaction complete; or upon this job's
- * completion if it is not in a transaction. Skipped if NULL.
- *
- * All jobs will complete with a call to either .commit() or .abort() but
- * never both.
- */
- void (*commit)(BlockJob *job);
-
- /**
- * If the callback is not NULL, it will be invoked when any job in the
- * same transaction fails; or upon this job's failure (due to error or
- * cancellation) if it is not in a transaction. Skipped if NULL.
- *
- * All jobs will complete with a call to either .commit() or .abort() but
- * never both.
- */
- void (*abort)(BlockJob *job);
-
- /**
- * If the callback is not NULL, it will be invoked after a call to either
- * .commit() or .abort(). Regardless of which callback is invoked after
- * completion, .clean() will always be called, even if the job does not
- * belong to a transaction group.
- */
- void (*clean)(BlockJob *job);
-
- /**
- * If the callback is not NULL, it will be invoked when the job transitions
- * into the paused state. Paused jobs must not perform any asynchronous
- * I/O or event loop activity. This callback is used to quiesce jobs.
- */
- void coroutine_fn (*pause)(BlockJob *job);
-
- /**
- * If the callback is not NULL, it will be invoked when the job transitions
- * out of the paused state. Any asynchronous I/O or event loop activity
- * should be restarted from this callback.
- */
- void coroutine_fn (*resume)(BlockJob *job);
+ /** Generic JobDriver callbacks and settings */
+ JobDriver job_driver;
/*
* If the callback is not NULL, it will be invoked before the job is
@@ -113,6 +49,10 @@ struct BlockJobDriver {
* If the callback is not NULL, it will be invoked when the job has to be
* synchronously cancelled or completed; it should drain BlockDriverStates
* as required to ensure progress.
+ *
+ * Block jobs must use the default implementation for job_driver.drain,
+ * which will in turn call this callback after doing generic block job
+ * stuff.
*/
void (*drain)(BlockJob *job);
};
@@ -126,8 +66,7 @@ struct BlockJobDriver {
* @bs: The block
* @perm, @shared_perm: Permissions to request for @bs
* @speed: The maximum speed, in bytes per second, or 0 for unlimited.
- * @flags: Creation flags for the Block Job.
- * See @BlockJobCreateFlags
+ * @flags: Creation flags for the Block Job. See @JobCreateFlags.
* @cb: Completion function for the job.
* @opaque: Opaque pointer value passed to @cb.
* @errp: Error object.
@@ -142,28 +81,31 @@ struct BlockJobDriver {
* called from a wrapper that is specific to the job type.
*/
void *block_job_create(const char *job_id, const BlockJobDriver *driver,
- BlockJobTxn *txn, BlockDriverState *bs, uint64_t perm,
+ JobTxn *txn, BlockDriverState *bs, uint64_t perm,
uint64_t shared_perm, int64_t speed, int flags,
BlockCompletionFunc *cb, void *opaque, Error **errp);
/**
- * block_job_sleep_ns:
- * @job: The job that calls the function.
- * @ns: How many nanoseconds to stop for.
- *
- * Put the job to sleep (assuming that it wasn't canceled) for @ns
- * %QEMU_CLOCK_REALTIME nanoseconds. Canceling the job will immediately
- * interrupt the wait.
+ * block_job_free:
+ * Callback to be used for JobDriver.free in all block jobs. Frees block job
+ * specific resources in @job.
*/
-void block_job_sleep_ns(BlockJob *job, int64_t ns);
+void block_job_free(Job *job);
/**
- * block_job_yield:
- * @job: The job that calls the function.
- *
- * Yield the block job coroutine.
+ * block_job_user_resume:
+ * Callback to be used for JobDriver.user_resume in all block jobs. Resets the
+ * iostatus when the user resumes @job.
+ */
+void block_job_user_resume(Job *job);
+
+/**
+ * block_job_drain:
+ * Callback to be used for JobDriver.drain in all block jobs. Drains the main
+ * block node associated with the block jobs and calls BlockJobDriver.drain for
+ * job-specific actions.
*/
-void block_job_yield(BlockJob *job);
+void block_job_drain(Job *job);
/**
* block_job_ratelimit_get_delay:
@@ -174,57 +116,6 @@ void block_job_yield(BlockJob *job);
int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n);
/**
- * block_job_early_fail:
- * @bs: The block device.
- *
- * The block job could not be started, free it.
- */
-void block_job_early_fail(BlockJob *job);
-
-/**
- * block_job_completed:
- * @job: The job being completed.
- * @ret: The status code.
- *
- * Call the completion function that was registered at creation time, and
- * free @job.
- */
-void block_job_completed(BlockJob *job, int ret);
-
-/**
- * block_job_is_cancelled:
- * @job: The job being queried.
- *
- * Returns whether the job is scheduled for cancellation.
- */
-bool block_job_is_cancelled(BlockJob *job);
-
-/**
- * block_job_pause_point:
- * @job: The job that is ready to pause.
- *
- * Pause now if block_job_pause() has been called. Block jobs that perform
- * lots of I/O must call this between requests so that the job can be paused.
- */
-void coroutine_fn block_job_pause_point(BlockJob *job);
-
-/**
- * block_job_enter:
- * @job: The job to enter.
- *
- * Continue the specified job by entering the coroutine.
- */
-void block_job_enter(BlockJob *job);
-
-/**
- * block_job_event_ready:
- * @job: The job which is now ready to be completed.
- *
- * Send a BLOCK_JOB_READY event for the specified job.
- */
-void block_job_event_ready(BlockJob *job);
-
-/**
* block_job_error_action:
* @job: The job to signal an error for.
* @on_err: The error action setting.
@@ -237,23 +128,4 @@ void block_job_event_ready(BlockJob *job);
BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err,
int is_read, int error);
-typedef void BlockJobDeferToMainLoopFn(BlockJob *job, void *opaque);
-
-/**
- * block_job_defer_to_main_loop:
- * @job: The job
- * @fn: The function to run in the main loop
- * @opaque: The opaque value that is passed to @fn
- *
- * This function must be called by the main job coroutine just before it
- * returns. @fn is executed in the main loop with the BlockDriverState
- * AioContext acquired. Block jobs must call bdrv_unref(), bdrv_close(), and
- * anything that uses bdrv_drain_all() in the main loop.
- *
- * The @job AioContext is held while @fn executes.
- */
-void block_job_defer_to_main_loop(BlockJob *job,
- BlockJobDeferToMainLoopFn *fn,
- void *opaque);
-
#endif
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index bd68328ed9..4d09eaba72 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -255,7 +255,7 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr,
void tlb_set_page(CPUState *cpu, target_ulong vaddr,
hwaddr paddr, int prot,
int mmu_idx, target_ulong size);
-void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr);
+void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr, MemTxAttrs attrs);
void probe_write(CPUArchState *env, target_ulong addr, int size, int mmu_idx,
uintptr_t retaddr);
#else
@@ -303,7 +303,8 @@ static inline void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *cpu,
uint16_t idxmap)
{
}
-static inline void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr)
+static inline void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr,
+ MemTxAttrs attrs)
{
}
#endif
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index 2e8a4b83b9..08363969c1 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -48,6 +48,21 @@ int use_gdb_syscalls(void);
void gdb_set_stop_cpu(CPUState *cpu);
void gdb_exit(CPUArchState *, int);
#ifdef CONFIG_USER_ONLY
+/**
+ * gdb_handlesig: yield control to gdb
+ * @cpu: CPU
+ * @sig: if non-zero, the signal number which caused us to stop
+ *
+ * This function yields control to gdb, when a user-mode-only target
+ * needs to stop execution. If @sig is non-zero, then we will send a
+ * stop packet to tell gdb that we have stopped because of this signal.
+ *
+ * This function will block (handling protocol requests from gdb)
+ * until gdb tells us to continue target execution. When it does
+ * return, the return value is a signal to deliver to the target,
+ * or 0 if no signal should be delivered, ie the signal that caused
+ * us to stop should be ignored.
+ */
int gdb_handlesig(CPUState *, int);
void gdb_signalled(CPUArchState *, int);
void gdbserver_fork(CPUState *);
diff --git a/include/exec/helper-head.h b/include/exec/helper-head.h
index 15b6a68de3..276dd5afce 100644
--- a/include/exec/helper-head.h
+++ b/include/exec/helper-head.h
@@ -39,7 +39,7 @@
#define dh_ctype_int int
#define dh_ctype_i64 uint64_t
#define dh_ctype_s64 int64_t
-#define dh_ctype_f16 float16
+#define dh_ctype_f16 uint32_t
#define dh_ctype_f32 float32
#define dh_ctype_f64 float64
#define dh_ctype_ptr void *
diff --git a/include/exec/memory-internal.h b/include/exec/memory-internal.h
index 58399b9318..56c25c0ef7 100644
--- a/include/exec/memory-internal.h
+++ b/include/exec/memory-internal.h
@@ -37,7 +37,8 @@ void flatview_unref(FlatView *view);
extern const MemoryRegionOps unassigned_mem_ops;
bool memory_region_access_valid(MemoryRegion *mr, hwaddr addr,
- unsigned size, bool is_write);
+ unsigned size, bool is_write,
+ MemTxAttrs attrs);
void flatview_add_to_dispatch(FlatView *fv, MemoryRegionSection *section);
AddressSpaceDispatch *address_space_dispatch_new(FlatView *fv);
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 525619a5f4..eb2ba06519 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -166,7 +166,8 @@ struct MemoryRegionOps {
* as a machine check exception).
*/
bool (*accepts)(void *opaque, hwaddr addr,
- unsigned size, bool is_write);
+ unsigned size, bool is_write,
+ MemTxAttrs attrs);
} valid;
/* Internal implementation constraints: */
struct {
@@ -194,29 +195,100 @@ enum IOMMUMemoryRegionAttr {
IOMMU_ATTR_SPAPR_TCE_FD
};
+/**
+ * IOMMUMemoryRegionClass:
+ *
+ * All IOMMU implementations need to subclass TYPE_IOMMU_MEMORY_REGION
+ * and provide an implementation of at least the @translate method here
+ * to handle requests to the memory region. Other methods are optional.
+ *
+ * The IOMMU implementation must use the IOMMU notifier infrastructure
+ * to report whenever mappings are changed, by calling
+ * memory_region_notify_iommu() (or, if necessary, by calling
+ * memory_region_notify_one() for each registered notifier).
+ */
typedef struct IOMMUMemoryRegionClass {
/* private */
struct DeviceClass parent_class;
/*
- * Return a TLB entry that contains a given address. Flag should
- * be the access permission of this translation operation. We can
- * set flag to IOMMU_NONE to mean that we don't need any
- * read/write permission checks, like, when for region replay.
+ * Return a TLB entry that contains a given address.
+ *
+ * The IOMMUAccessFlags indicated via @flag are optional and may
+ * be specified as IOMMU_NONE to indicate that the caller needs
+ * the full translation information for both reads and writes. If
+ * the access flags are specified then the IOMMU implementation
+ * may use this as an optimization, to stop doing a page table
+ * walk as soon as it knows that the requested permissions are not
+ * allowed. If IOMMU_NONE is passed then the IOMMU must do the
+ * full page table walk and report the permissions in the returned
+ * IOMMUTLBEntry. (Note that this implies that an IOMMU may not
+ * return different mappings for reads and writes.)
+ *
+ * The returned information remains valid while the caller is
+ * holding the big QEMU lock or is inside an RCU critical section;
+ * if the caller wishes to cache the mapping beyond that it must
+ * register an IOMMU notifier so it can invalidate its cached
+ * information when the IOMMU mapping changes.
+ *
+ * @iommu: the IOMMUMemoryRegion
+ * @hwaddr: address to be translated within the memory region
+ * @flag: requested access permissions
*/
IOMMUTLBEntry (*translate)(IOMMUMemoryRegion *iommu, hwaddr addr,
IOMMUAccessFlags flag);
- /* Returns minimum supported page size */
+ /* Returns minimum supported page size in bytes.
+ * If this method is not provided then the minimum is assumed to
+ * be TARGET_PAGE_SIZE.
+ *
+ * @iommu: the IOMMUMemoryRegion
+ */
uint64_t (*get_min_page_size)(IOMMUMemoryRegion *iommu);
- /* Called when IOMMU Notifier flag changed */
+ /* Called when IOMMU Notifier flag changes (ie when the set of
+ * events which IOMMU users are requesting notification for changes).
+ * Optional method -- need not be provided if the IOMMU does not
+ * need to know exactly which events must be notified.
+ *
+ * @iommu: the IOMMUMemoryRegion
+ * @old_flags: events which previously needed to be notified
+ * @new_flags: events which now need to be notified
+ */
void (*notify_flag_changed)(IOMMUMemoryRegion *iommu,
IOMMUNotifierFlag old_flags,
IOMMUNotifierFlag new_flags);
- /* Set this up to provide customized IOMMU replay function */
+ /* Called to handle memory_region_iommu_replay().
+ *
+ * The default implementation of memory_region_iommu_replay() is to
+ * call the IOMMU translate method for every page in the address space
+ * with flag == IOMMU_NONE and then call the notifier if translate
+ * returns a valid mapping. If this method is implemented then it
+ * overrides the default behaviour, and must provide the full semantics
+ * of memory_region_iommu_replay(), by calling @notifier for every
+ * translation present in the IOMMU.
+ *
+ * Optional method -- an IOMMU only needs to provide this method
+ * if the default is inefficient or produces undesirable side effects.
+ *
+ * Note: this is not related to record-and-replay functionality.
+ */
void (*replay)(IOMMUMemoryRegion *iommu, IOMMUNotifier *notifier);
- /* Get IOMMU misc attributes */
- int (*get_attr)(IOMMUMemoryRegion *iommu, enum IOMMUMemoryRegionAttr,
+ /* Get IOMMU misc attributes. This is an optional method that
+ * can be used to allow users of the IOMMU to get implementation-specific
+ * information. The IOMMU implements this method to handle calls
+ * by IOMMU users to memory_region_iommu_get_attr() by filling in
+ * the arbitrary data pointer for any IOMMUMemoryRegionAttr values that
+ * the IOMMU supports. If the method is unimplemented then
+ * memory_region_iommu_get_attr() will always return -EINVAL.
+ *
+ * @iommu: the IOMMUMemoryRegion
+ * @attr: attribute being queried
+ * @data: memory to fill in with the attribute data
+ *
+ * Returns 0 on success, or a negative errno; in particular
+ * returns -EINVAL for unrecognized or unimplemented attribute types.
+ */
+ int (*get_attr)(IOMMUMemoryRegion *iommu, enum IOMMUMemoryRegionAttr attr,
void *data);
} IOMMUMemoryRegionClass;
@@ -676,35 +748,20 @@ void memory_region_init_rom_device_nomigrate(MemoryRegion *mr,
Error **errp);
/**
- * memory_region_init_reservation: Initialize a memory region that reserves
- * I/O space.
- *
- * A reservation region primariy serves debugging purposes. It claims I/O
- * space that is not supposed to be handled by QEMU itself. Any access via
- * the memory API will cause an abort().
- * This function is deprecated. Use memory_region_init_io() with NULL
- * callbacks instead.
- *
- * @mr: the #MemoryRegion to be initialized
- * @owner: the object that tracks the region's reference count
- * @name: used for debugging; not visible to the user or ABI
- * @size: size of the region.
- */
-static inline void memory_region_init_reservation(MemoryRegion *mr,
- Object *owner,
- const char *name,
- uint64_t size)
-{
- memory_region_init_io(mr, owner, NULL, mr, name, size);
-}
-
-/**
* memory_region_init_iommu: Initialize a memory region of a custom type
* that translates addresses
*
* An IOMMU region translates addresses and forwards accesses to a target
* memory region.
*
+ * The IOMMU implementation must define a subclass of TYPE_IOMMU_MEMORY_REGION.
+ * @_iommu_mr should be a pointer to enough memory for an instance of
+ * that subclass, @instance_size is the size of that subclass, and
+ * @mrtypename is its name. This function will initialize @_iommu_mr as an
+ * instance of the subclass, and its methods will then be called to handle
+ * accesses to the memory region. See the documentation of
+ * #IOMMUMemoryRegionClass for further details.
+ *
* @_iommu_mr: the #IOMMUMemoryRegion to be initialized
* @instance_size: the IOMMUMemoryRegion subclass instance size
* @mrtypename: the type name of the #IOMMUMemoryRegion
@@ -953,6 +1010,8 @@ void memory_region_register_iommu_notifier(MemoryRegion *mr,
* a notifier with the minimum page granularity returned by
* mr->iommu_ops->get_page_size().
*
+ * Note: this is not related to record-and-replay functionality.
+ *
* @iommu_mr: the memory region to observe
* @n: the notifier to which to replay iommu mappings
*/
@@ -962,6 +1021,8 @@ void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n);
* memory_region_iommu_replay_all: replay existing IOMMU translations
* to all the notifiers registered.
*
+ * Note: this is not related to record-and-replay functionality.
+ *
* @iommu_mr: the memory region to observe
*/
void memory_region_iommu_replay_all(IOMMUMemoryRegion *iommu_mr);
@@ -981,7 +1042,9 @@ void memory_region_unregister_iommu_notifier(MemoryRegion *mr,
* memory_region_iommu_get_attr: return an IOMMU attr if get_attr() is
* defined on the IOMMU.
*
- * Returns 0 if succeded, error code otherwise.
+ * Returns 0 on success, or a negative errno otherwise. In particular,
+ * -EINVAL indicates that the IOMMU does not support the requested
+ * attribute.
*
* @iommu_mr: the memory region
* @attr: the requested attribute
@@ -1810,7 +1873,7 @@ void address_space_cache_destroy(MemoryRegionCache *cache);
* entry. Should be called from an RCU critical section.
*/
IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr,
- bool is_write);
+ bool is_write, MemTxAttrs attrs);
/* address_space_translate: translate an address range into an address space
* into a MemoryRegion and an address range into that section. Should be
@@ -1823,17 +1886,20 @@ IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr,
* #MemoryRegion.
* @len: pointer to length
* @is_write: indicates the transfer direction
+ * @attrs: memory attributes
*/
MemoryRegion *flatview_translate(FlatView *fv,
hwaddr addr, hwaddr *xlat,
- hwaddr *len, bool is_write);
+ hwaddr *len, bool is_write,
+ MemTxAttrs attrs);
static inline MemoryRegion *address_space_translate(AddressSpace *as,
hwaddr addr, hwaddr *xlat,
- hwaddr *len, bool is_write)
+ hwaddr *len, bool is_write,
+ MemTxAttrs attrs)
{
return flatview_translate(address_space_to_flatview(as),
- addr, xlat, len, is_write);
+ addr, xlat, len, is_write, attrs);
}
/* address_space_access_valid: check for validity of accessing an address
@@ -1850,8 +1916,10 @@ static inline MemoryRegion *address_space_translate(AddressSpace *as,
* @addr: address within that address space
* @len: length of the area to be checked
* @is_write: indicates the transfer direction
+ * @attrs: memory attributes
*/
-bool address_space_access_valid(AddressSpace *as, hwaddr addr, int len, bool is_write);
+bool address_space_access_valid(AddressSpace *as, hwaddr addr, int len,
+ bool is_write, MemTxAttrs attrs);
/* address_space_map: map a physical memory region into a host virtual address
*
@@ -1865,9 +1933,10 @@ bool address_space_access_valid(AddressSpace *as, hwaddr addr, int len, bool is_
* @addr: address within that address space
* @plen: pointer to length of buffer; updated on return
* @is_write: indicates the transfer direction
+ * @attrs: memory attributes
*/
void *address_space_map(AddressSpace *as, hwaddr addr,
- hwaddr *plen, bool is_write);
+ hwaddr *plen, bool is_write, MemTxAttrs attrs);
/* address_space_unmap: Unmaps a memory region previously mapped by address_space_map()
*
@@ -1939,7 +2008,7 @@ MemTxResult address_space_read(AddressSpace *as, hwaddr addr,
rcu_read_lock();
fv = address_space_to_flatview(as);
l = len;
- mr = flatview_translate(fv, addr, &addr1, &l, false);
+ mr = flatview_translate(fv, addr, &addr1, &l, false, attrs);
if (len == l && memory_access_is_direct(mr, false)) {
ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
memcpy(buf, ptr, len);
diff --git a/include/exec/user/thunk.h b/include/exec/user/thunk.h
index 8f55b233b3..8d3af5a3be 100644
--- a/include/exec/user/thunk.h
+++ b/include/exec/user/thunk.h
@@ -135,7 +135,7 @@ static inline int thunk_type_size(const argtype *type_ptr, int is_host)
se = struct_entries + type_ptr[1];
return se->size[is_host];
default:
- return -1;
+ g_assert_not_reached();
}
}
@@ -185,7 +185,7 @@ static inline int thunk_type_align(const argtype *type_ptr, int is_host)
se = struct_entries + type_ptr[1];
return se->align[is_host];
default:
- return -1;
+ g_assert_not_reached();
}
}
diff --git a/include/hw/arm/allwinner-a10.h b/include/hw/arm/allwinner-a10.h
index 6b32a99e21..efb8fc8123 100644
--- a/include/hw/arm/allwinner-a10.h
+++ b/include/hw/arm/allwinner-a10.h
@@ -11,7 +11,6 @@
#include "hw/ide/ahci.h"
#include "sysemu/sysemu.h"
-#include "exec/address-spaces.h"
#define AW_A10_PIC_REG_BASE 0x01c20400
diff --git a/include/hw/arm/bcm2835_peripherals.h b/include/hw/arm/bcm2835_peripherals.h
index 122b286de7..f5b193f670 100644
--- a/include/hw/arm/bcm2835_peripherals.h
+++ b/include/hw/arm/bcm2835_peripherals.h
@@ -12,7 +12,6 @@
#define BCM2835_PERIPHERALS_H
#include "qemu-common.h"
-#include "exec/address-spaces.h"
#include "hw/sysbus.h"
#include "hw/char/bcm2835_aux.h"
#include "hw/display/bcm2835_fb.h"
diff --git a/include/hw/devices.h b/include/hw/devices.h
index 861ddea8af..0e27feb0c2 100644
--- a/include/hw/devices.h
+++ b/include/hw/devices.h
@@ -1,13 +1,10 @@
#ifndef QEMU_DEVICES_H
#define QEMU_DEVICES_H
-#include "hw/irq.h"
-
-/* ??? Not all users of this file can include cpu-common.h. */
-struct MemoryRegion;
-
/* Devices that have nowhere better to go. */
+#include "hw/hw.h"
+
/* smc91c111.c */
void smc91c111_init(NICInfo *, uint32_t, qemu_irq);
diff --git a/include/hw/display/bcm2835_fb.h b/include/hw/display/bcm2835_fb.h
index 9a12d7afa2..ae0a3807f2 100644
--- a/include/hw/display/bcm2835_fb.h
+++ b/include/hw/display/bcm2835_fb.h
@@ -12,7 +12,6 @@
#define BCM2835_FB_H
#include "hw/sysbus.h"
-#include "exec/address-spaces.h"
#include "ui/console.h"
#define TYPE_BCM2835_FB "bcm2835-fb"
diff --git a/include/hw/display/bochs-vbe.h b/include/hw/display/bochs-vbe.h
new file mode 100644
index 0000000000..bc2f046eee
--- /dev/null
+++ b/include/hw/display/bochs-vbe.h
@@ -0,0 +1,69 @@
+#ifndef HW_DISPLAY_BOCHS_VBE_H
+#define HW_DISPLAY_BOCHS_VBE_H
+
+/*
+ * bochs vesa bios extension interface
+ */
+
+#define VBE_DISPI_MAX_XRES 16000
+#define VBE_DISPI_MAX_YRES 12000
+#define VBE_DISPI_MAX_BPP 32
+
+#define VBE_DISPI_INDEX_ID 0x0
+#define VBE_DISPI_INDEX_XRES 0x1
+#define VBE_DISPI_INDEX_YRES 0x2
+#define VBE_DISPI_INDEX_BPP 0x3
+#define VBE_DISPI_INDEX_ENABLE 0x4
+#define VBE_DISPI_INDEX_BANK 0x5
+#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
+#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
+#define VBE_DISPI_INDEX_X_OFFSET 0x8
+#define VBE_DISPI_INDEX_Y_OFFSET 0x9
+#define VBE_DISPI_INDEX_NB 0xa /* size of vbe_regs[] */
+#define VBE_DISPI_INDEX_VIDEO_MEMORY_64K 0xa /* read-only, not in vbe_regs */
+
+/* VBE_DISPI_INDEX_ID */
+#define VBE_DISPI_ID0 0xB0C0
+#define VBE_DISPI_ID1 0xB0C1
+#define VBE_DISPI_ID2 0xB0C2
+#define VBE_DISPI_ID3 0xB0C3
+#define VBE_DISPI_ID4 0xB0C4
+#define VBE_DISPI_ID5 0xB0C5
+
+/* VBE_DISPI_INDEX_ENABLE */
+#define VBE_DISPI_DISABLED 0x00
+#define VBE_DISPI_ENABLED 0x01
+#define VBE_DISPI_GETCAPS 0x02
+#define VBE_DISPI_8BIT_DAC 0x20
+#define VBE_DISPI_LFB_ENABLED 0x40
+#define VBE_DISPI_NOCLEARMEM 0x80
+
+/* only used by isa-vga, pci vga devices use a memory bar */
+#define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000
+
+
+/*
+ * qemu extension: mmio bar (region 2)
+ */
+
+#define PCI_VGA_MMIO_SIZE 0x1000
+
+/* vga register region */
+#define PCI_VGA_IOPORT_OFFSET 0x400
+#define PCI_VGA_IOPORT_SIZE (0x3e0 - 0x3c0)
+
+/* bochs vbe register region */
+#define PCI_VGA_BOCHS_OFFSET 0x500
+#define PCI_VGA_BOCHS_SIZE (0x0b * 2)
+
+/* qemu extension register region */
+#define PCI_VGA_QEXT_OFFSET 0x600
+#define PCI_VGA_QEXT_SIZE (2 * 4)
+
+/* qemu extension registers */
+#define PCI_VGA_QEXT_REG_SIZE (0 * 4)
+#define PCI_VGA_QEXT_REG_BYTEORDER (1 * 4)
+#define PCI_VGA_QEXT_LITTLE_ENDIAN 0x1e1e1e1e
+#define PCI_VGA_QEXT_BIG_ENDIAN 0xbebebebe
+
+#endif /* HW_DISPLAY_BOCHS_VBE_H */
diff --git a/include/hw/dma/bcm2835_dma.h b/include/hw/dma/bcm2835_dma.h
index 75312e2e17..60138f4d31 100644
--- a/include/hw/dma/bcm2835_dma.h
+++ b/include/hw/dma/bcm2835_dma.h
@@ -7,7 +7,6 @@
#define BCM2835_DMA_H
#include "qemu-common.h"
-#include "exec/address-spaces.h"
#include "hw/sysbus.h"
typedef struct {
diff --git a/include/hw/i2c/i2c.h b/include/hw/i2c/i2c.h
index d727379b48..5dc166158b 100644
--- a/include/hw/i2c/i2c.h
+++ b/include/hw/i2c/i2c.h
@@ -28,9 +28,6 @@ typedef struct I2CSlave I2CSlave;
typedef struct I2CSlaveClass {
DeviceClass parent_class;
- /* Callbacks provided by the device. */
- int (*init)(I2CSlave *dev);
-
/* Master to slave. Returns non-zero for a NAK, 0 for success. */
int (*send)(I2CSlave *s, uint8_t data);
diff --git a/include/hw/i2c/smbus.h b/include/hw/i2c/smbus.h
index 544bbc1957..cfe3fa69f3 100644
--- a/include/hw/i2c/smbus.h
+++ b/include/hw/i2c/smbus.h
@@ -38,7 +38,6 @@
typedef struct SMBusDeviceClass
{
I2CSlaveClass parent_class;
- int (*init)(SMBusDevice *dev);
void (*quick_cmd)(SMBusDevice *dev, uint8_t read);
void (*send_byte)(SMBusDevice *dev, uint8_t val);
uint8_t (*receive_byte)(SMBusDevice *dev);
diff --git a/include/hw/misc/bcm2835_mbox.h b/include/hw/misc/bcm2835_mbox.h
index f4e9ff9ef6..7e8f3ce86d 100644
--- a/include/hw/misc/bcm2835_mbox.h
+++ b/include/hw/misc/bcm2835_mbox.h
@@ -8,7 +8,6 @@
#include "bcm2835_mbox_defs.h"
#include "hw/sysbus.h"
-#include "exec/address-spaces.h"
#define TYPE_BCM2835_MBOX "bcm2835-mbox"
#define BCM2835_MBOX(obj) \
diff --git a/include/hw/misc/bcm2835_property.h b/include/hw/misc/bcm2835_property.h
index edcab603ce..11be0dbeac 100644
--- a/include/hw/misc/bcm2835_property.h
+++ b/include/hw/misc/bcm2835_property.h
@@ -7,7 +7,6 @@
#define BCM2835_PROPERTY_H
#include "hw/sysbus.h"
-#include "exec/address-spaces.h"
#include "net/net.h"
#include "hw/display/bcm2835_fb.h"
diff --git a/include/hw/misc/mips_itu.h b/include/hw/misc/mips_itu.h
index b3a4532036..030eb4ac62 100644
--- a/include/hw/misc/mips_itu.h
+++ b/include/hw/misc/mips_itu.h
@@ -20,6 +20,8 @@
#ifndef MIPS_ITU_H
#define MIPS_ITU_H
+#include "hw/sysbus.h"
+
#define TYPE_MIPS_ITU "mips-itu"
#define MIPS_ITU(obj) OBJECT_CHECK(MIPSITUState, (obj), TYPE_MIPS_ITU)
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index 9453588160..f1fd0f8736 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -29,8 +29,6 @@ typedef enum DeviceCategory {
DEVICE_CATEGORY_MAX
} DeviceCategory;
-typedef int (*qdev_initfn)(DeviceState *dev);
-typedef int (*qdev_event)(DeviceState *dev);
typedef void (*DeviceRealize)(DeviceState *dev, Error **errp);
typedef void (*DeviceUnrealize)(DeviceState *dev, Error **errp);
typedef void (*DeviceReset)(DeviceState *dev);
@@ -43,13 +41,9 @@ struct VMStateDescription;
* DeviceClass:
* @props: Properties accessing state fields.
* @realize: Callback function invoked when the #DeviceState:realized
- * property is changed to %true. The default invokes @init if not %NULL.
+ * property is changed to %true.
* @unrealize: Callback function invoked when the #DeviceState:realized
* property is changed to %false.
- * @init: Callback function invoked when the #DeviceState::realized property
- * is changed to %true. Deprecated, new types inheriting directly from
- * TYPE_DEVICE should use @realize instead, new leaf types should consult
- * their respective parent type.
* @hotpluggable: indicates if #DeviceClass is hotpluggable, available
* as readonly "hotpluggable" property of #DeviceState instance
*
@@ -73,19 +67,15 @@ struct VMStateDescription;
* object_initialize() in their own #TypeInfo.instance_init and forward the
* realization events appropriately.
*
- * The @init callback is considered private to a particular bus implementation
- * (immediate abstract child types of TYPE_DEVICE). Derived leaf types set an
- * "init" callback on their parent class instead.
- *
* Any type may override the @realize and/or @unrealize callbacks but needs
* to call the parent type's implementation if keeping their functionality
* is desired. Refer to QOM documentation for further discussion and examples.
*
* <note>
* <para>
- * If a type derived directly from TYPE_DEVICE implements @realize, it does
- * not need to implement @init and therefore does not need to store and call
- * #DeviceClass' default @realize callback.
+ * Since TYPE_DEVICE doesn't implement @realize and @unrealize, types
+ * derived directly from it need not call their parent's @realize and
+ * @unrealize.
* For other types consult the documentation and implementation of the
* respective parent types.
* </para>
@@ -124,8 +114,6 @@ typedef struct DeviceClass {
const struct VMStateDescription *vmsd;
/* Private to qdev / bus. */
- qdev_initfn init; /* TODO remove, once users are converted to realize */
- qdev_event exit; /* TODO remove, once users are converted to unrealize */
const char *bus_type;
} DeviceClass;
diff --git a/include/hw/sh4/sh_intc.h b/include/hw/sh4/sh_intc.h
index 7913bc48a2..fbcee94ed7 100644
--- a/include/hw/sh4/sh_intc.h
+++ b/include/hw/sh4/sh_intc.h
@@ -3,7 +3,6 @@
#include "qemu-common.h"
#include "hw/irq.h"
-#include "exec/address-spaces.h"
typedef unsigned char intc_enum;
diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h
index d9360148e6..8264a65fa5 100644
--- a/include/hw/vfio/vfio-common.h
+++ b/include/hw/vfio/vfio-common.h
@@ -22,7 +22,6 @@
#define HW_VFIO_VFIO_COMMON_H
#include "qemu-common.h"
-#include "exec/address-spaces.h"
#include "exec/memory.h"
#include "qemu/queue.h"
#include "qemu/notify.h"
diff --git a/include/hw/virtio/virtio-access.h b/include/hw/virtio/virtio-access.h
index 2e92074bd1..bdf58f3119 100644
--- a/include/hw/virtio/virtio-access.h
+++ b/include/hw/virtio/virtio-access.h
@@ -18,7 +18,6 @@
#include "hw/virtio/virtio.h"
#include "hw/virtio/virtio-bus.h"
-#include "exec/address-spaces.h"
#if defined(TARGET_PPC64) || defined(TARGET_ARM)
#define LEGACY_VIRTIO_IS_BIENDIAN 1
diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h
index 79bb3fb3dd..d6ba61f2f1 100644
--- a/include/hw/virtio/virtio-gpu.h
+++ b/include/hw/virtio/virtio-gpu.h
@@ -21,6 +21,12 @@
#include "qemu/log.h"
#include "standard-headers/linux/virtio_gpu.h"
+
+/* Not yet(?) defined in standard-headers, remove when possible */
+#ifndef VIRTIO_GPU_CAPSET_VIRGL2
+#define VIRTIO_GPU_CAPSET_VIRGL2 2
+#endif
+
#define TYPE_VIRTIO_GPU "virtio-gpu-device"
#define VIRTIO_GPU(obj) \
OBJECT_CHECK(VirtIOGPU, (obj), TYPE_VIRTIO_GPU)
diff --git a/include/hw/xen/xen_backend.h b/include/hw/xen/xen_backend.h
index 3a27692407..9c17fdd85d 100644
--- a/include/hw/xen/xen_backend.h
+++ b/include/hw/xen/xen_backend.h
@@ -16,7 +16,6 @@
/* variables */
extern struct xs_handle *xenstore;
extern const char *xen_protocol;
-extern bool xen_feature_grant_copy;
extern DeviceState *xen_sysdev;
extern BusState *xen_sysbus;
@@ -42,6 +41,39 @@ void xen_be_register_common(void);
int xen_be_register(const char *type, struct XenDevOps *ops);
int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state);
int xen_be_bind_evtchn(struct XenDevice *xendev);
+void xen_be_set_max_grant_refs(struct XenDevice *xendev,
+ unsigned int nr_refs);
+void *xen_be_map_grant_refs(struct XenDevice *xendev, uint32_t *refs,
+ unsigned int nr_refs, int prot);
+void xen_be_unmap_grant_refs(struct XenDevice *xendev, void *ptr,
+ unsigned int nr_refs);
+
+typedef struct XenGrantCopySegment {
+ union {
+ void *virt;
+ struct {
+ uint32_t ref;
+ off_t offset;
+ } foreign;
+ } source, dest;
+ size_t len;
+} XenGrantCopySegment;
+
+int xen_be_copy_grant_refs(struct XenDevice *xendev,
+ bool to_domain, XenGrantCopySegment segs[],
+ unsigned int nr_segs);
+
+static inline void *xen_be_map_grant_ref(struct XenDevice *xendev,
+ uint32_t ref, int prot)
+{
+ return xen_be_map_grant_refs(xendev, &ref, 1, prot);
+}
+
+static inline void xen_be_unmap_grant_ref(struct XenDevice *xendev,
+ void *ptr)
+{
+ return xen_be_unmap_grant_refs(xendev, ptr, 1);
+}
/* actual backend drivers */
extern struct XenDevOps xen_console_ops; /* xen_console.c */
diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_common.h
index 5f1402b494..93f631e5bf 100644
--- a/include/hw/xen/xen_common.h
+++ b/include/hw/xen/xen_common.h
@@ -119,6 +119,22 @@ static inline int xendevicemodel_pin_memory_cacheattr(
return xc_domain_pin_memory_cacheattr(xen_xc, domid, start, end, type);
}
+typedef void xenforeignmemory_resource_handle;
+
+#define XENMEM_resource_ioreq_server 0
+
+#define XENMEM_resource_ioreq_server_frame_bufioreq 0
+#define XENMEM_resource_ioreq_server_frame_ioreq(n) (1 + (n))
+
+static inline xenforeignmemory_resource_handle *xenforeignmemory_map_resource(
+ xenforeignmemory_handle *fmem, domid_t domid, unsigned int type,
+ unsigned int id, unsigned long frame, unsigned long nr_frames,
+ void **paddr, int prot, int flags)
+{
+ errno = EOPNOTSUPP;
+ return NULL;
+}
+
#endif /* CONFIG_XEN_CTRL_INTERFACE_VERSION < 41100 */
#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 41000
@@ -667,8 +683,21 @@ static inline int xen_domain_create(xc_interface *xc, uint32_t ssidref,
#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 40800
-
-typedef void *xengnttab_grant_copy_segment_t;
+struct xengnttab_grant_copy_segment {
+ union xengnttab_copy_ptr {
+ void *virt;
+ struct {
+ uint32_t ref;
+ uint16_t offset;
+ uint16_t domid;
+ } foreign;
+ } source, dest;
+ uint16_t len;
+ uint16_t flags;
+ int16_t status;
+};
+
+typedef struct xengnttab_grant_copy_segment xengnttab_grant_copy_segment_t;
static inline int xengnttab_grant_copy(xengnttab_handle *xgt, uint32_t count,
xengnttab_grant_copy_segment_t *segs)
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 5877caed90..3747110f95 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -143,6 +143,11 @@ enum VMStateFlags {
* to determine the number of entries in the array. Only valid in
* combination with one of VMS_VARRAY*. */
VMS_MULTIPLY_ELEMENTS = 0x4000,
+
+ /* A structure field that is like VMS_STRUCT, but uses
+ * VMStateField.struct_version_id to tell which version of the
+ * structure we are referencing to use. */
+ VMS_VSTRUCT = 0x8000,
};
typedef enum {
@@ -167,6 +172,7 @@ struct VMStateField {
enum VMStateFlags flags;
const VMStateDescription *vmsd;
int version_id;
+ int struct_version_id;
bool (*field_exists)(void *opaque, int version_id);
};
@@ -248,6 +254,25 @@ extern const VMStateInfo vmstate_info_qtailq;
vmstate_offset_array(_state, _field, uint8_t, \
sizeof(typeof_field(_state, _field)))
+/* In the macros below, if there is a _version, that means the macro's
+ * field will be processed only if the version being received is >=
+ * the _version specified. In general, if you add a new field, you
+ * would increment the structure's version and put that version
+ * number into the new field so it would only be processed with the
+ * new version.
+ *
+ * In particular, for VMSTATE_STRUCT() and friends the _version does
+ * *NOT* pick the version of the sub-structure. It works just as
+ * specified above. The version of the top-level structure received
+ * is passed down to all sub-structures. This means that the
+ * sub-structures must have version that are compatible with all the
+ * structures that use them.
+ *
+ * If you want to specify the version of the sub-structure, use
+ * VMSTATE_VSTRUCT(), which allows the specific sub-structure version
+ * to be directly specified.
+ */
+
#define VMSTATE_SINGLE_TEST(_field, _state, _test, _version, _info, _type) { \
.name = (stringify(_field)), \
.version_id = (_version), \
@@ -395,6 +420,17 @@ extern const VMStateInfo vmstate_info_qtailq;
.offset = offsetof(_state, _field), \
}
+#define VMSTATE_VSTRUCT_TEST(_field, _state, _test, _version, _vmsd, _type, _struct_version) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .struct_version_id = (_struct_version), \
+ .field_exists = (_test), \
+ .vmsd = &(_vmsd), \
+ .size = sizeof(_type), \
+ .flags = VMS_VSTRUCT, \
+ .offset = vmstate_offset_value(_state, _field, _type), \
+}
+
#define VMSTATE_STRUCT_TEST(_field, _state, _test, _version, _vmsd, _type) { \
.name = (stringify(_field)), \
.version_id = (_version), \
@@ -712,6 +748,13 @@ extern const VMStateInfo vmstate_info_qtailq;
#define VMSTATE_SINGLE(_field, _state, _version, _info, _type) \
VMSTATE_SINGLE_TEST(_field, _state, NULL, _version, _info, _type)
+#define VMSTATE_VSTRUCT(_field, _state, _vmsd, _type, _struct_version)\
+ VMSTATE_VSTRUCT_TEST(_field, _state, NULL, 0, _vmsd, _type, _struct_version)
+
+#define VMSTATE_VSTRUCT_V(_field, _state, _version, _vmsd, _type, _struct_version) \
+ VMSTATE_VSTRUCT_TEST(_field, _state, NULL, _version, _vmsd, _type, \
+ _struct_version)
+
#define VMSTATE_STRUCT(_field, _state, _version, _vmsd, _type) \
VMSTATE_STRUCT_TEST(_field, _state, NULL, _version, _vmsd, _type)
@@ -870,6 +913,9 @@ extern const VMStateInfo vmstate_info_qtailq;
#define VMSTATE_BOOL_ARRAY(_f, _s, _n) \
VMSTATE_BOOL_ARRAY_V(_f, _s, _n, 0)
+#define VMSTATE_BOOL_SUB_ARRAY(_f, _s, _start, _num) \
+ VMSTATE_SUB_ARRAY(_f, _s, _start, _num, 0, vmstate_info_bool, bool)
+
#define VMSTATE_UINT16_ARRAY_V(_f, _s, _n, _v) \
VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint16, uint16_t)
@@ -1000,6 +1046,8 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
void *opaque, int version_id);
int vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
void *opaque, QJSON *vmdesc);
+int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
+ void *opaque, QJSON *vmdesc, int version_id);
bool vmstate_save_needed(const VMStateDescription *vmsd, void *opaque);
diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index ffb4652f71..b366bb48bd 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -23,6 +23,7 @@ typedef enum QmpCommandOptions
QCO_NO_OPTIONS = 0x0,
QCO_NO_SUCCESS_RESP = (1U << 0),
QCO_ALLOW_OOB = (1U << 1),
+ QCO_ALLOW_PRECONFIG = (1U << 2),
} QmpCommandOptions;
typedef struct QmpCommand
diff --git a/include/qemu/job.h b/include/qemu/job.h
new file mode 100644
index 0000000000..1d820530fa
--- /dev/null
+++ b/include/qemu/job.h
@@ -0,0 +1,567 @@
+/*
+ * Declarations for background jobs
+ *
+ * Copyright (c) 2011 IBM Corp.
+ * Copyright (c) 2012, 2018 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef JOB_H
+#define JOB_H
+
+#include "qapi/qapi-types-block-core.h"
+#include "qemu/queue.h"
+#include "qemu/coroutine.h"
+#include "block/aio.h"
+
+typedef struct JobDriver JobDriver;
+typedef struct JobTxn JobTxn;
+
+
+/**
+ * Long-running operation.
+ */
+typedef struct Job {
+ /** The ID of the job. May be NULL for internal jobs. */
+ char *id;
+
+ /** The type of this job. */
+ const JobDriver *driver;
+
+ /** Reference count of the block job */
+ int refcnt;
+
+ /** Current state; See @JobStatus for details. */
+ JobStatus status;
+
+ /** AioContext to run the job coroutine in */
+ AioContext *aio_context;
+
+ /**
+ * The coroutine that executes the job. If not NULL, it is reentered when
+ * busy is false and the job is cancelled.
+ */
+ Coroutine *co;
+
+ /**
+ * Timer that is used by @job_sleep_ns. Accessed under job_mutex (in
+ * job.c).
+ */
+ QEMUTimer sleep_timer;
+
+ /**
+ * Counter for pause request. If non-zero, the block job is either paused,
+ * or if busy == true will pause itself as soon as possible.
+ */
+ int pause_count;
+
+ /**
+ * Set to false by the job while the coroutine has yielded and may be
+ * re-entered by job_enter(). There may still be I/O or event loop activity
+ * pending. Accessed under block_job_mutex (in blockjob.c).
+ */
+ bool busy;
+
+ /**
+ * Set to true by the job while it is in a quiescent state, where
+ * no I/O or event loop activity is pending.
+ */
+ bool paused;
+
+ /**
+ * Set to true if the job is paused by user. Can be unpaused with the
+ * block-job-resume QMP command.
+ */
+ bool user_paused;
+
+ /**
+ * Set to true if the job should cancel itself. The flag must
+ * always be tested just before toggling the busy flag from false
+ * to true. After a job has been cancelled, it should only yield
+ * if #aio_poll will ("sooner or later") reenter the coroutine.
+ */
+ bool cancelled;
+
+ /**
+ * Set to true if the job should abort immediately without waiting
+ * for data to be in sync.
+ */
+ bool force_cancel;
+
+ /** Set to true when the job has deferred work to the main loop. */
+ bool deferred_to_main_loop;
+
+ /** True if this job should automatically finalize itself */
+ bool auto_finalize;
+
+ /** True if this job should automatically dismiss itself */
+ bool auto_dismiss;
+
+ /**
+ * Current progress. The unit is arbitrary as long as the ratio between
+ * progress_current and progress_total represents the estimated percentage
+ * of work already done.
+ */
+ int64_t progress_current;
+
+ /** Estimated progress_current value at the completion of the job */
+ int64_t progress_total;
+
+ /** Error string for a failed job (NULL if, and only if, job->ret == 0) */
+ char *error;
+
+ /** ret code passed to job_completed. */
+ int ret;
+
+ /** The completion function that will be called when the job completes. */
+ BlockCompletionFunc *cb;
+
+ /** The opaque value that is passed to the completion function. */
+ void *opaque;
+
+ /** Notifiers called when a cancelled job is finalised */
+ NotifierList on_finalize_cancelled;
+
+ /** Notifiers called when a successfully completed job is finalised */
+ NotifierList on_finalize_completed;
+
+ /** Notifiers called when the job transitions to PENDING */
+ NotifierList on_pending;
+
+ /** Notifiers called when the job transitions to READY */
+ NotifierList on_ready;
+
+ /** Element of the list of jobs */
+ QLIST_ENTRY(Job) job_list;
+
+ /** Transaction this job is part of */
+ JobTxn *txn;
+
+ /** Element of the list of jobs in a job transaction */
+ QLIST_ENTRY(Job) txn_list;
+} Job;
+
+/**
+ * Callbacks and other information about a Job driver.
+ */
+struct JobDriver {
+ /** Derived Job struct size */
+ size_t instance_size;
+
+ /** Enum describing the operation */
+ JobType job_type;
+
+ /** Mandatory: Entrypoint for the Coroutine. */
+ CoroutineEntry *start;
+
+ /**
+ * If the callback is not NULL, it will be invoked when the job transitions
+ * into the paused state. Paused jobs must not perform any asynchronous
+ * I/O or event loop activity. This callback is used to quiesce jobs.
+ */
+ void coroutine_fn (*pause)(Job *job);
+
+ /**
+ * If the callback is not NULL, it will be invoked when the job transitions
+ * out of the paused state. Any asynchronous I/O or event loop activity
+ * should be restarted from this callback.
+ */
+ void coroutine_fn (*resume)(Job *job);
+
+ /**
+ * Called when the job is resumed by the user (i.e. user_paused becomes
+ * false). .user_resume is called before .resume.
+ */
+ void (*user_resume)(Job *job);
+
+ /**
+ * Optional callback for job types whose completion must be triggered
+ * manually.
+ */
+ void (*complete)(Job *job, Error **errp);
+
+ /*
+ * If the callback is not NULL, it will be invoked when the job has to be
+ * synchronously cancelled or completed; it should drain any activities
+ * as required to ensure progress.
+ */
+ void (*drain)(Job *job);
+
+ /**
+ * If the callback is not NULL, prepare will be invoked when all the jobs
+ * belonging to the same transaction complete; or upon this job's completion
+ * if it is not in a transaction.
+ *
+ * This callback will not be invoked if the job has already failed.
+ * If it fails, abort and then clean will be called.
+ */
+ int (*prepare)(Job *job);
+
+ /**
+ * If the callback is not NULL, it will be invoked when all the jobs
+ * belonging to the same transaction complete; or upon this job's
+ * completion if it is not in a transaction. Skipped if NULL.
+ *
+ * All jobs will complete with a call to either .commit() or .abort() but
+ * never both.
+ */
+ void (*commit)(Job *job);
+
+ /**
+ * If the callback is not NULL, it will be invoked when any job in the
+ * same transaction fails; or upon this job's failure (due to error or
+ * cancellation) if it is not in a transaction. Skipped if NULL.
+ *
+ * All jobs will complete with a call to either .commit() or .abort() but
+ * never both.
+ */
+ void (*abort)(Job *job);
+
+ /**
+ * If the callback is not NULL, it will be invoked after a call to either
+ * .commit() or .abort(). Regardless of which callback is invoked after
+ * completion, .clean() will always be called, even if the job does not
+ * belong to a transaction group.
+ */
+ void (*clean)(Job *job);
+
+
+ /** Called when the job is freed */
+ void (*free)(Job *job);
+};
+
+typedef enum JobCreateFlags {
+ /* Default behavior */
+ JOB_DEFAULT = 0x00,
+ /* Job is not QMP-created and should not send QMP events */
+ JOB_INTERNAL = 0x01,
+ /* Job requires manual finalize step */
+ JOB_MANUAL_FINALIZE = 0x02,
+ /* Job requires manual dismiss step */
+ JOB_MANUAL_DISMISS = 0x04,
+} JobCreateFlags;
+
+/**
+ * Allocate and return a new job transaction. Jobs can be added to the
+ * transaction using job_txn_add_job().
+ *
+ * The transaction is automatically freed when the last job completes or is
+ * cancelled.
+ *
+ * All jobs in the transaction either complete successfully or fail/cancel as a
+ * group. Jobs wait for each other before completing. Cancelling one job
+ * cancels all jobs in the transaction.
+ */
+JobTxn *job_txn_new(void);
+
+/**
+ * Release a reference that was previously acquired with job_txn_add_job or
+ * job_txn_new. If it's the last reference to the object, it will be freed.
+ */
+void job_txn_unref(JobTxn *txn);
+
+/**
+ * @txn: The transaction (may be NULL)
+ * @job: Job to add to the transaction
+ *
+ * Add @job to the transaction. The @job must not already be in a transaction.
+ * The caller must call either job_txn_unref() or job_completed() to release
+ * the reference that is automatically grabbed here.
+ *
+ * If @txn is NULL, the function does nothing.
+ */
+void job_txn_add_job(JobTxn *txn, Job *job);
+
+/**
+ * Create a new long-running job and return it.
+ *
+ * @job_id: The id of the newly-created job, or %NULL for internal jobs
+ * @driver: The class object for the newly-created job.
+ * @txn: The transaction this job belongs to, if any. %NULL otherwise.
+ * @ctx: The AioContext to run the job coroutine in.
+ * @flags: Creation flags for the job. See @JobCreateFlags.
+ * @cb: Completion function for the job.
+ * @opaque: Opaque pointer value passed to @cb.
+ * @errp: Error object.
+ */
+void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn,
+ AioContext *ctx, int flags, BlockCompletionFunc *cb,
+ void *opaque, Error **errp);
+
+/**
+ * Add a reference to Job refcnt, it will be decreased with job_unref, and then
+ * be freed if it comes to be the last reference.
+ */
+void job_ref(Job *job);
+
+/**
+ * Release a reference that was previously acquired with job_ref() or
+ * job_create(). If it's the last reference to the object, it will be freed.
+ */
+void job_unref(Job *job);
+
+/**
+ * @job: The job that has made progress
+ * @done: How much progress the job made since the last call
+ *
+ * Updates the progress counter of the job.
+ */
+void job_progress_update(Job *job, uint64_t done);
+
+/**
+ * @job: The job whose expected progress end value is set
+ * @remaining: Missing progress (on top of the current progress counter value)
+ * until the new expected end value is reached
+ *
+ * Sets the expected end value of the progress counter of a job so that a
+ * completion percentage can be calculated when the progress is updated.
+ */
+void job_progress_set_remaining(Job *job, uint64_t remaining);
+
+/** To be called when a cancelled job is finalised. */
+void job_event_cancelled(Job *job);
+
+/** To be called when a successfully completed job is finalised. */
+void job_event_completed(Job *job);
+
+/**
+ * Conditionally enter the job coroutine if the job is ready to run, not
+ * already busy and fn() returns true. fn() is called while under the job_lock
+ * critical section.
+ */
+void job_enter_cond(Job *job, bool(*fn)(Job *job));
+
+/**
+ * @job: A job that has not yet been started.
+ *
+ * Begins execution of a job.
+ * Takes ownership of one reference to the job object.
+ */
+void job_start(Job *job);
+
+/**
+ * @job: The job to enter.
+ *
+ * Continue the specified job by entering the coroutine.
+ */
+void job_enter(Job *job);
+
+/**
+ * @job: The job that is ready to pause.
+ *
+ * Pause now if job_pause() has been called. Jobs that perform lots of I/O
+ * must call this between requests so that the job can be paused.
+ */
+void coroutine_fn job_pause_point(Job *job);
+
+/**
+ * @job: The job that calls the function.
+ *
+ * Yield the job coroutine.
+ */
+void job_yield(Job *job);
+
+/**
+ * @job: The job that calls the function.
+ * @ns: How many nanoseconds to stop for.
+ *
+ * Put the job to sleep (assuming that it wasn't canceled) for @ns
+ * %QEMU_CLOCK_REALTIME nanoseconds. Canceling the job will immediately
+ * interrupt the wait.
+ */
+void coroutine_fn job_sleep_ns(Job *job, int64_t ns);
+
+
+/** Returns the JobType of a given Job. */
+JobType job_type(const Job *job);
+
+/** Returns the enum string for the JobType of a given Job. */
+const char *job_type_str(const Job *job);
+
+/** Returns true if the job should not be visible to the management layer. */
+bool job_is_internal(Job *job);
+
+/** Returns whether the job is scheduled for cancellation. */
+bool job_is_cancelled(Job *job);
+
+/** Returns whether the job is in a completed state. */
+bool job_is_completed(Job *job);
+
+/** Returns whether the job is ready to be completed. */
+bool job_is_ready(Job *job);
+
+/**
+ * Request @job to pause at the next pause point. Must be paired with
+ * job_resume(). If the job is supposed to be resumed by user action, call
+ * job_user_pause() instead.
+ */
+void job_pause(Job *job);
+
+/** Resumes a @job paused with job_pause. */
+void job_resume(Job *job);
+
+/**
+ * Asynchronously pause the specified @job.
+ * Do not allow a resume until a matching call to job_user_resume.
+ */
+void job_user_pause(Job *job, Error **errp);
+
+/** Returns true if the job is user-paused. */
+bool job_user_paused(Job *job);
+
+/**
+ * Resume the specified @job.
+ * Must be paired with a preceding job_user_pause.
+ */
+void job_user_resume(Job *job, Error **errp);
+
+/*
+ * Drain any activities as required to ensure progress. This can be called in a
+ * loop to synchronously complete a job.
+ */
+void job_drain(Job *job);
+
+/**
+ * Get the next element from the list of block jobs after @job, or the
+ * first one if @job is %NULL.
+ *
+ * Returns the requested job, or %NULL if there are no more jobs left.
+ */
+Job *job_next(Job *job);
+
+/**
+ * Get the job identified by @id (which must not be %NULL).
+ *
+ * Returns the requested job, or %NULL if it doesn't exist.
+ */
+Job *job_get(const char *id);
+
+/**
+ * Check whether the verb @verb can be applied to @job in its current state.
+ * Returns 0 if the verb can be applied; otherwise errp is set and -EPERM
+ * returned.
+ */
+int job_apply_verb(Job *job, JobVerb verb, Error **errp);
+
+/** The @job could not be started, free it. */
+void job_early_fail(Job *job);
+
+/** Moves the @job from RUNNING to READY */
+void job_transition_to_ready(Job *job);
+
+/**
+ * @job: The job being completed.
+ * @ret: The status code.
+ * @error: The error message for a failing job (only with @ret < 0). If @ret is
+ * negative, but NULL is given for @error, strerror() is used.
+ *
+ * Marks @job as completed. If @ret is non-zero, the job transaction it is part
+ * of is aborted. If @ret is zero, the job moves into the WAITING state. If it
+ * is the last job to complete in its transaction, all jobs in the transaction
+ * move from WAITING to PENDING.
+ */
+void job_completed(Job *job, int ret, Error *error);
+
+/** Asynchronously complete the specified @job. */
+void job_complete(Job *job, Error **errp);
+
+/**
+ * Asynchronously cancel the specified @job. If @force is true, the job should
+ * be cancelled immediately without waiting for a consistent state.
+ */
+void job_cancel(Job *job, bool force);
+
+/**
+ * Cancels the specified job like job_cancel(), but may refuse to do so if the
+ * operation isn't meaningful in the current state of the job.
+ */
+void job_user_cancel(Job *job, bool force, Error **errp);
+
+/**
+ * Synchronously cancel the @job. The completion callback is called
+ * before the function returns. The job may actually complete
+ * instead of canceling itself; the circumstances under which this
+ * happens depend on the kind of job that is active.
+ *
+ * Returns the return value from the job if the job actually completed
+ * during the call, or -ECANCELED if it was canceled.
+ */
+int job_cancel_sync(Job *job);
+
+/** Synchronously cancels all jobs using job_cancel_sync(). */
+void job_cancel_sync_all(void);
+
+/**
+ * @job: The job to be completed.
+ * @errp: Error object which may be set by job_complete(); this is not
+ * necessarily set on every error, the job return value has to be
+ * checked as well.
+ *
+ * Synchronously complete the job. The completion callback is called before the
+ * function returns, unless it is NULL (which is permissible when using this
+ * function).
+ *
+ * Returns the return value from the job.
+ */
+int job_complete_sync(Job *job, Error **errp);
+
+/**
+ * For a @job that has finished its work and is pending awaiting explicit
+ * acknowledgement to commit its work, this will commit that work.
+ *
+ * FIXME: Make the below statement universally true:
+ * For jobs that support the manual workflow mode, all graph changes that occur
+ * as a result will occur after this command and before a successful reply.
+ */
+void job_finalize(Job *job, Error **errp);
+
+/**
+ * Remove the concluded @job from the query list and resets the passed pointer
+ * to %NULL. Returns an error if the job is not actually concluded.
+ */
+void job_dismiss(Job **job, Error **errp);
+
+typedef void JobDeferToMainLoopFn(Job *job, void *opaque);
+
+/**
+ * @job: The job
+ * @fn: The function to run in the main loop
+ * @opaque: The opaque value that is passed to @fn
+ *
+ * This function must be called by the main job coroutine just before it
+ * returns. @fn is executed in the main loop with the job AioContext acquired.
+ *
+ * Block jobs must call bdrv_unref(), bdrv_close(), and anything that uses
+ * bdrv_drain_all() in the main loop.
+ *
+ * The @job AioContext is held while @fn executes.
+ */
+void job_defer_to_main_loop(Job *job, JobDeferToMainLoopFn *fn, void *opaque);
+
+/**
+ * Synchronously finishes the given @job. If @finish is given, it is called to
+ * trigger completion or cancellation of the job.
+ *
+ * Returns 0 if the job is successfully completed, -ECANCELED if the job was
+ * cancelled before completing, and -errno in other error cases.
+ */
+int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp);
+
+#endif
diff --git a/include/standard-headers/asm-x86/hyperv.h b/include/standard-headers/asm-x86/hyperv.h
deleted file mode 100644
index ce87d0c344..0000000000
--- a/include/standard-headers/asm-x86/hyperv.h
+++ /dev/null
@@ -1 +0,0 @@
- /* this is a temporary placeholder until kvm_para.h stops including it */
diff --git a/include/standard-headers/asm-x86/kvm_para.h b/include/standard-headers/asm-x86/kvm_para.h
index 53a85ae3ed..1617c84b0d 100644
--- a/include/standard-headers/asm-x86/kvm_para.h
+++ b/include/standard-headers/asm-x86/kvm_para.h
@@ -29,7 +29,7 @@
#define KVM_FEATURE_PV_TLB_FLUSH 9
#define KVM_FEATURE_ASYNC_PF_VMEXIT 10
-#define KVM_HINTS_DEDICATED 0
+#define KVM_HINTS_REALTIME 0
/* The last 8 bits are used to indicate how to interpret the flags field
* in pvclock structure. If no bits are set, all flags are ignored.
diff --git a/include/standard-headers/linux/ethtool.h b/include/standard-headers/linux/ethtool.h
index 94aacb7adf..eb10c075e4 100644
--- a/include/standard-headers/linux/ethtool.h
+++ b/include/standard-headers/linux/ethtool.h
@@ -217,10 +217,14 @@ struct ethtool_value {
uint32_t data;
};
+#define PFC_STORM_PREVENTION_AUTO 0xffff
+#define PFC_STORM_PREVENTION_DISABLE 0
+
enum tunable_id {
ETHTOOL_ID_UNSPEC,
ETHTOOL_RX_COPYBREAK,
ETHTOOL_TX_COPYBREAK,
+ ETHTOOL_PFC_PREVENTION_TOUT, /* timeout in msecs */
/*
* Add your fresh new tubale attribute above and remember to update
* tunable_strings[] in net/core/ethtool.c
@@ -914,12 +918,15 @@ static inline uint64_t ethtool_get_flow_spec_ring_vf(uint64_t ring_cookie)
* @flow_type: Type of flow to be affected, e.g. %TCP_V4_FLOW
* @data: Command-dependent value
* @fs: Flow classification rule
+ * @rss_context: RSS context to be affected
* @rule_cnt: Number of rules to be affected
* @rule_locs: Array of used rule locations
*
* For %ETHTOOL_GRXFH and %ETHTOOL_SRXFH, @data is a bitmask indicating
* the fields included in the flow hash, e.g. %RXH_IP_SRC. The following
- * structure fields must not be used.
+ * structure fields must not be used, except that if @flow_type includes
+ * the %FLOW_RSS flag, then @rss_context determines which RSS context to
+ * act on.
*
* For %ETHTOOL_GRXRINGS, @data is set to the number of RX rings/queues
* on return.
@@ -931,7 +938,9 @@ static inline uint64_t ethtool_get_flow_spec_ring_vf(uint64_t ring_cookie)
* set in @data then special location values should not be used.
*
* For %ETHTOOL_GRXCLSRULE, @fs.@location specifies the location of an
- * existing rule on entry and @fs contains the rule on return.
+ * existing rule on entry and @fs contains the rule on return; if
+ * @fs.@flow_type includes the %FLOW_RSS flag, then @rss_context is
+ * filled with the RSS context ID associated with the rule.
*
* For %ETHTOOL_GRXCLSRLALL, @rule_cnt specifies the array size of the
* user buffer for @rule_locs on entry. On return, @data is the size
@@ -942,7 +951,11 @@ static inline uint64_t ethtool_get_flow_spec_ring_vf(uint64_t ring_cookie)
* For %ETHTOOL_SRXCLSRLINS, @fs specifies the rule to add or update.
* @fs.@location either specifies the location to use or is a special
* location value with %RX_CLS_LOC_SPECIAL flag set. On return,
- * @fs.@location is the actual rule location.
+ * @fs.@location is the actual rule location. If @fs.@flow_type
+ * includes the %FLOW_RSS flag, @rss_context is the RSS context ID to
+ * use for flow spreading traffic which matches this rule. The value
+ * from the rxfh indirection table will be added to @fs.@ring_cookie
+ * to choose which ring to deliver to.
*
* For %ETHTOOL_SRXCLSRLDEL, @fs.@location specifies the location of an
* existing rule on entry.
@@ -963,7 +976,10 @@ struct ethtool_rxnfc {
uint32_t flow_type;
uint64_t data;
struct ethtool_rx_flow_spec fs;
- uint32_t rule_cnt;
+ union {
+ uint32_t rule_cnt;
+ uint32_t rss_context;
+ };
uint32_t rule_locs[0];
};
@@ -990,7 +1006,11 @@ struct ethtool_rxfh_indir {
/**
* struct ethtool_rxfh - command to get/set RX flow hash indir or/and hash key.
* @cmd: Specific command number - %ETHTOOL_GRSSH or %ETHTOOL_SRSSH
- * @rss_context: RSS context identifier.
+ * @rss_context: RSS context identifier. Context 0 is the default for normal
+ * traffic; other contexts can be referenced as the destination for RX flow
+ * classification rules. %ETH_RXFH_CONTEXT_ALLOC is used with command
+ * %ETHTOOL_SRSSH to allocate a new RSS context; on return this field will
+ * contain the ID of the newly allocated context.
* @indir_size: On entry, the array size of the user buffer for the
* indirection table, which may be zero, or (for %ETHTOOL_SRSSH),
* %ETH_RXFH_INDIR_NO_CHANGE. On return from %ETHTOOL_GRSSH,
@@ -1009,7 +1029,8 @@ struct ethtool_rxfh_indir {
* size should be returned. For %ETHTOOL_SRSSH, an @indir_size of
* %ETH_RXFH_INDIR_NO_CHANGE means that indir table setting is not requested
* and a @indir_size of zero means the indir table should be reset to default
- * values. An hfunc of zero means that hash function setting is not requested.
+ * values (if @rss_context == 0) or that the RSS context should be deleted.
+ * An hfunc of zero means that hash function setting is not requested.
*/
struct ethtool_rxfh {
uint32_t cmd;
@@ -1021,6 +1042,7 @@ struct ethtool_rxfh {
uint32_t rsvd32;
uint32_t rss_config[0];
};
+#define ETH_RXFH_CONTEXT_ALLOC 0xffffffff
#define ETH_RXFH_INDIR_NO_CHANGE 0xffffffff
/**
@@ -1635,6 +1657,8 @@ static inline int ethtool_validate_duplex(uint8_t duplex)
/* Flag to enable additional fields in struct ethtool_rx_flow_spec */
#define FLOW_EXT 0x80000000
#define FLOW_MAC_EXT 0x40000000
+/* Flag to enable RSS spreading of traffic matching rule (nfc only) */
+#define FLOW_RSS 0x20000000
/* L3-L4 network traffic flow hash options */
#define RXH_L2DA (1 << 1)
diff --git a/include/standard-headers/linux/input.h b/include/standard-headers/linux/input.h
index 939b62775c..6d6128c081 100644
--- a/include/standard-headers/linux/input.h
+++ b/include/standard-headers/linux/input.h
@@ -28,8 +28,8 @@ struct input_event {
#define input_event_sec time.tv_sec
#define input_event_usec time.tv_usec
#else
- __kernel_ulong_t __sec;
- __kernel_ulong_t __usec;
+ unsigned long __sec;
+ unsigned long __usec;
#define input_event_sec __sec
#define input_event_usec __usec
#endif
diff --git a/include/standard-headers/linux/pci_regs.h b/include/standard-headers/linux/pci_regs.h
index 0c79eac5e9..103ba797a8 100644
--- a/include/standard-headers/linux/pci_regs.h
+++ b/include/standard-headers/linux/pci_regs.h
@@ -520,6 +520,7 @@
#define PCI_EXP_LNKCAP_SLS_2_5GB 0x00000001 /* LNKCAP2 SLS Vector bit 0 */
#define PCI_EXP_LNKCAP_SLS_5_0GB 0x00000002 /* LNKCAP2 SLS Vector bit 1 */
#define PCI_EXP_LNKCAP_SLS_8_0GB 0x00000003 /* LNKCAP2 SLS Vector bit 2 */
+#define PCI_EXP_LNKCAP_SLS_16_0GB 0x00000004 /* LNKCAP2 SLS Vector bit 3 */
#define PCI_EXP_LNKCAP_MLW 0x000003f0 /* Maximum Link Width */
#define PCI_EXP_LNKCAP_ASPMS 0x00000c00 /* ASPM Support */
#define PCI_EXP_LNKCAP_L0SEL 0x00007000 /* L0s Exit Latency */
@@ -547,6 +548,7 @@
#define PCI_EXP_LNKSTA_CLS_2_5GB 0x0001 /* Current Link Speed 2.5GT/s */
#define PCI_EXP_LNKSTA_CLS_5_0GB 0x0002 /* Current Link Speed 5.0GT/s */
#define PCI_EXP_LNKSTA_CLS_8_0GB 0x0003 /* Current Link Speed 8.0GT/s */
+#define PCI_EXP_LNKSTA_CLS_16_0GB 0x0004 /* Current Link Speed 16.0GT/s */
#define PCI_EXP_LNKSTA_NLW 0x03f0 /* Negotiated Link Width */
#define PCI_EXP_LNKSTA_NLW_X1 0x0010 /* Current Link Width x1 */
#define PCI_EXP_LNKSTA_NLW_X2 0x0020 /* Current Link Width x2 */
@@ -648,8 +650,9 @@
#define PCI_CAP_EXP_RC_ENDPOINT_SIZEOF_V2 44 /* v2 endpoints without link end here */
#define PCI_EXP_LNKCAP2 44 /* Link Capabilities 2 */
#define PCI_EXP_LNKCAP2_SLS_2_5GB 0x00000002 /* Supported Speed 2.5GT/s */
-#define PCI_EXP_LNKCAP2_SLS_5_0GB 0x00000004 /* Supported Speed 5.0GT/s */
-#define PCI_EXP_LNKCAP2_SLS_8_0GB 0x00000008 /* Supported Speed 8.0GT/s */
+#define PCI_EXP_LNKCAP2_SLS_5_0GB 0x00000004 /* Supported Speed 5GT/s */
+#define PCI_EXP_LNKCAP2_SLS_8_0GB 0x00000008 /* Supported Speed 8GT/s */
+#define PCI_EXP_LNKCAP2_SLS_16_0GB 0x00000010 /* Supported Speed 16GT/s */
#define PCI_EXP_LNKCAP2_CROSSLINK 0x00000100 /* Crosslink supported */
#define PCI_EXP_LNKCTL2 48 /* Link Control 2 */
#define PCI_EXP_LNKSTA2 50 /* Link Status 2 */
diff --git a/include/standard-headers/linux/virtio_balloon.h b/include/standard-headers/linux/virtio_balloon.h
index e446805ae9..4dbb7dc6c0 100644
--- a/include/standard-headers/linux/virtio_balloon.h
+++ b/include/standard-headers/linux/virtio_balloon.h
@@ -57,6 +57,21 @@ struct virtio_balloon_config {
#define VIRTIO_BALLOON_S_HTLB_PGFAIL 9 /* Hugetlb page allocation failures */
#define VIRTIO_BALLOON_S_NR 10
+#define VIRTIO_BALLOON_S_NAMES_WITH_PREFIX(VIRTIO_BALLOON_S_NAMES_prefix) { \
+ VIRTIO_BALLOON_S_NAMES_prefix "swap-in", \
+ VIRTIO_BALLOON_S_NAMES_prefix "swap-out", \
+ VIRTIO_BALLOON_S_NAMES_prefix "major-faults", \
+ VIRTIO_BALLOON_S_NAMES_prefix "minor-faults", \
+ VIRTIO_BALLOON_S_NAMES_prefix "free-memory", \
+ VIRTIO_BALLOON_S_NAMES_prefix "total-memory", \
+ VIRTIO_BALLOON_S_NAMES_prefix "available-memory", \
+ VIRTIO_BALLOON_S_NAMES_prefix "disk-caches", \
+ VIRTIO_BALLOON_S_NAMES_prefix "hugetlb-allocations", \
+ VIRTIO_BALLOON_S_NAMES_prefix "hugetlb-failures" \
+}
+
+#define VIRTIO_BALLOON_S_NAMES VIRTIO_BALLOON_S_NAMES_WITH_PREFIX("")
+
/*
* Memory statistics structure.
* Driver fills an array of these structures and passes to device.
diff --git a/include/standard-headers/linux/virtio_gpu.h b/include/standard-headers/linux/virtio_gpu.h
index 52a830dcf8..c1c8f0751d 100644
--- a/include/standard-headers/linux/virtio_gpu.h
+++ b/include/standard-headers/linux/virtio_gpu.h
@@ -260,7 +260,6 @@ struct virtio_gpu_cmd_submit {
};
#define VIRTIO_GPU_CAPSET_VIRGL 1
-#define VIRTIO_GPU_CAPSET_VIRGL2 2
/* VIRTIO_GPU_CMD_GET_CAPSET_INFO */
struct virtio_gpu_get_capset_info {
diff --git a/include/standard-headers/rdma/vmw_pvrdma-abi.h b/include/standard-headers/rdma/vmw_pvrdma-abi.h
index 07a820d337..6c2bc46116 100644
--- a/include/standard-headers/rdma/vmw_pvrdma-abi.h
+++ b/include/standard-headers/rdma/vmw_pvrdma-abi.h
@@ -143,7 +143,7 @@ struct pvrdma_alloc_pd_resp {
};
struct pvrdma_create_cq {
- uint64_t buf_addr;
+ uint64_t __attribute__((aligned(8))) buf_addr;
uint32_t buf_size;
uint32_t reserved;
};
@@ -154,13 +154,13 @@ struct pvrdma_create_cq_resp {
};
struct pvrdma_resize_cq {
- uint64_t buf_addr;
+ uint64_t __attribute__((aligned(8))) buf_addr;
uint32_t buf_size;
uint32_t reserved;
};
struct pvrdma_create_srq {
- uint64_t buf_addr;
+ uint64_t __attribute__((aligned(8))) buf_addr;
uint32_t buf_size;
uint32_t reserved;
};
@@ -171,25 +171,25 @@ struct pvrdma_create_srq_resp {
};
struct pvrdma_create_qp {
- uint64_t rbuf_addr;
- uint64_t sbuf_addr;
+ uint64_t __attribute__((aligned(8))) rbuf_addr;
+ uint64_t __attribute__((aligned(8))) sbuf_addr;
uint32_t rbuf_size;
uint32_t sbuf_size;
- uint64_t qp_addr;
+ uint64_t __attribute__((aligned(8))) qp_addr;
};
/* PVRDMA masked atomic compare and swap */
struct pvrdma_ex_cmp_swap {
- uint64_t swap_val;
- uint64_t compare_val;
- uint64_t swap_mask;
- uint64_t compare_mask;
+ uint64_t __attribute__((aligned(8))) swap_val;
+ uint64_t __attribute__((aligned(8))) compare_val;
+ uint64_t __attribute__((aligned(8))) swap_mask;
+ uint64_t __attribute__((aligned(8))) compare_mask;
};
/* PVRDMA masked atomic fetch and add */
struct pvrdma_ex_fetch_add {
- uint64_t add_val;
- uint64_t field_boundary;
+ uint64_t __attribute__((aligned(8))) add_val;
+ uint64_t __attribute__((aligned(8))) field_boundary;
};
/* PVRDMA address vector. */
@@ -207,14 +207,14 @@ struct pvrdma_av {
/* PVRDMA scatter/gather entry */
struct pvrdma_sge {
- uint64_t addr;
+ uint64_t __attribute__((aligned(8))) addr;
uint32_t length;
uint32_t lkey;
};
/* PVRDMA receive queue work request */
struct pvrdma_rq_wqe_hdr {
- uint64_t wr_id; /* wr id */
+ uint64_t __attribute__((aligned(8))) wr_id; /* wr id */
uint32_t num_sge; /* size of s/g array */
uint32_t total_len; /* reserved */
};
@@ -222,7 +222,7 @@ struct pvrdma_rq_wqe_hdr {
/* PVRDMA send queue work request */
struct pvrdma_sq_wqe_hdr {
- uint64_t wr_id; /* wr id */
+ uint64_t __attribute__((aligned(8))) wr_id; /* wr id */
uint32_t num_sge; /* size of s/g array */
uint32_t total_len; /* reserved */
uint32_t opcode; /* operation type */
@@ -234,19 +234,19 @@ struct pvrdma_sq_wqe_hdr {
uint32_t reserved;
union {
struct {
- uint64_t remote_addr;
+ uint64_t __attribute__((aligned(8))) remote_addr;
uint32_t rkey;
uint8_t reserved[4];
} rdma;
struct {
- uint64_t remote_addr;
- uint64_t compare_add;
- uint64_t swap;
+ uint64_t __attribute__((aligned(8))) remote_addr;
+ uint64_t __attribute__((aligned(8))) compare_add;
+ uint64_t __attribute__((aligned(8))) swap;
uint32_t rkey;
uint32_t reserved;
} atomic;
struct {
- uint64_t remote_addr;
+ uint64_t __attribute__((aligned(8))) remote_addr;
uint32_t log_arg_sz;
uint32_t rkey;
union {
@@ -255,13 +255,14 @@ struct pvrdma_sq_wqe_hdr {
} wr_data;
} masked_atomics;
struct {
- uint64_t iova_start;
- uint64_t pl_pdir_dma;
+ uint64_t __attribute__((aligned(8))) iova_start;
+ uint64_t __attribute__((aligned(8))) pl_pdir_dma;
uint32_t page_shift;
uint32_t page_list_len;
uint32_t length;
uint32_t access_flags;
uint32_t rkey;
+ uint32_t reserved;
} fast_reg;
struct {
uint32_t remote_qpn;
@@ -274,8 +275,8 @@ struct pvrdma_sq_wqe_hdr {
/* Completion queue element. */
struct pvrdma_cqe {
- uint64_t wr_id;
- uint64_t qp;
+ uint64_t __attribute__((aligned(8))) wr_id;
+ uint64_t __attribute__((aligned(8))) qp;
uint32_t opcode;
uint32_t status;
uint32_t byte_len;
diff --git a/include/sysemu/dma.h b/include/sysemu/dma.h
index c228c66513..5da3c4e3c5 100644
--- a/include/sysemu/dma.h
+++ b/include/sysemu/dma.h
@@ -77,7 +77,8 @@ static inline bool dma_memory_valid(AddressSpace *as,
DMADirection dir)
{
return address_space_access_valid(as, addr, len,
- dir == DMA_DIRECTION_FROM_DEVICE);
+ dir == DMA_DIRECTION_FROM_DEVICE,
+ MEMTXATTRS_UNSPECIFIED);
}
static inline int dma_memory_rw_relaxed(AddressSpace *as, dma_addr_t addr,
@@ -132,7 +133,8 @@ static inline void *dma_memory_map(AddressSpace *as,
hwaddr xlen = *len;
void *p;
- p = address_space_map(as, addr, &xlen, dir == DMA_DIRECTION_FROM_DEVICE);
+ p = address_space_map(as, addr, &xlen, dir == DMA_DIRECTION_FROM_DEVICE,
+ MEMTXATTRS_UNSPECIFIED);
*len = xlen;
return p;
}
diff --git a/include/sysemu/numa.h b/include/sysemu/numa.h
index d99e5474b4..7a0ae751aa 100644
--- a/include/sysemu/numa.h
+++ b/include/sysemu/numa.h
@@ -22,7 +22,9 @@ struct NumaNodeMem {
};
extern NodeInfo numa_info[MAX_NODES];
+int parse_numa(void *opaque, QemuOpts *opts, Error **errp);
void parse_numa_opts(MachineState *ms);
+void numa_complete_configuration(MachineState *ms);
void query_numa_node_mem(NumaNodeMem node_mem[]);
extern QemuOptsList qemu_numa_opts;
void numa_legacy_auto_assign_ram(MachineClass *mc, NodeInfo *nodes,
diff --git a/include/sysemu/seccomp.h b/include/sysemu/seccomp.h
index 9b092aa23f..fe859894f6 100644
--- a/include/sysemu/seccomp.h
+++ b/include/sysemu/seccomp.h
@@ -21,5 +21,6 @@
#define QEMU_SECCOMP_SET_SPAWN (1 << 3)
#define QEMU_SECCOMP_SET_RESOURCECTL (1 << 4)
-int seccomp_start(uint32_t seccomp_opts);
+int parse_sandbox(void *opaque, QemuOpts *opts, Error **errp);
+
#endif
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 544ab77a2b..e893f72f3b 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -66,6 +66,7 @@ typedef enum WakeupReason {
QEMU_WAKEUP_REASON_OTHER,
} WakeupReason;
+void qemu_exit_preconfig_request(void);
void qemu_system_reset_request(ShutdownCause reason);
void qemu_system_suspend_request(void);
void qemu_register_suspend_notifier(Notifier *notifier);
diff --git a/include/sysemu/xen-mapcache.h b/include/sysemu/xen-mapcache.h
index bd4d49e0a4..a03e2f1878 100644
--- a/include/sysemu/xen-mapcache.h
+++ b/include/sysemu/xen-mapcache.h
@@ -9,9 +9,8 @@
#ifndef XEN_MAPCACHE_H
#define XEN_MAPCACHE_H
-typedef hwaddr (*phys_offset_to_gaddr_t)(hwaddr start_addr,
- ram_addr_t size,
- void *opaque);
+typedef hwaddr (*phys_offset_to_gaddr_t)(hwaddr phys_offset,
+ ram_addr_t size);
#ifdef CONFIG_XEN
void xen_map_cache_init(phys_offset_to_gaddr_t f,
diff --git a/job-qmp.c b/job-qmp.c
new file mode 100644
index 0000000000..410775df61
--- /dev/null
+++ b/job-qmp.c
@@ -0,0 +1,183 @@
+/*
+ * QMP interface for background jobs
+ *
+ * Copyright (c) 2011 IBM Corp.
+ * Copyright (c) 2012, 2018 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qemu/job.h"
+#include "qapi/qapi-commands-job.h"
+#include "qapi/error.h"
+#include "trace-root.h"
+
+/* Get a job using its ID and acquire its AioContext */
+static Job *find_job(const char *id, AioContext **aio_context, Error **errp)
+{
+ Job *job;
+
+ *aio_context = NULL;
+
+ job = job_get(id);
+ if (!job) {
+ error_setg(errp, "Job not found");
+ return NULL;
+ }
+
+ *aio_context = job->aio_context;
+ aio_context_acquire(*aio_context);
+
+ return job;
+}
+
+void qmp_job_cancel(const char *id, Error **errp)
+{
+ AioContext *aio_context;
+ Job *job = find_job(id, &aio_context, errp);
+
+ if (!job) {
+ return;
+ }
+
+ trace_qmp_job_cancel(job);
+ job_user_cancel(job, true, errp);
+ aio_context_release(aio_context);
+}
+
+void qmp_job_pause(const char *id, Error **errp)
+{
+ AioContext *aio_context;
+ Job *job = find_job(id, &aio_context, errp);
+
+ if (!job) {
+ return;
+ }
+
+ trace_qmp_job_pause(job);
+ job_user_pause(job, errp);
+ aio_context_release(aio_context);
+}
+
+void qmp_job_resume(const char *id, Error **errp)
+{
+ AioContext *aio_context;
+ Job *job = find_job(id, &aio_context, errp);
+
+ if (!job) {
+ return;
+ }
+
+ trace_qmp_job_resume(job);
+ job_user_resume(job, errp);
+ aio_context_release(aio_context);
+}
+
+void qmp_job_complete(const char *id, Error **errp)
+{
+ AioContext *aio_context;
+ Job *job = find_job(id, &aio_context, errp);
+
+ if (!job) {
+ return;
+ }
+
+ trace_qmp_job_complete(job);
+ job_complete(job, errp);
+ aio_context_release(aio_context);
+}
+
+void qmp_job_finalize(const char *id, Error **errp)
+{
+ AioContext *aio_context;
+ Job *job = find_job(id, &aio_context, errp);
+
+ if (!job) {
+ return;
+ }
+
+ trace_qmp_job_finalize(job);
+ job_finalize(job, errp);
+ aio_context_release(aio_context);
+}
+
+void qmp_job_dismiss(const char *id, Error **errp)
+{
+ AioContext *aio_context;
+ Job *job = find_job(id, &aio_context, errp);
+
+ if (!job) {
+ return;
+ }
+
+ trace_qmp_job_dismiss(job);
+ job_dismiss(&job, errp);
+ aio_context_release(aio_context);
+}
+
+static JobInfo *job_query_single(Job *job, Error **errp)
+{
+ JobInfo *info;
+
+ assert(!job_is_internal(job));
+
+ info = g_new(JobInfo, 1);
+ *info = (JobInfo) {
+ .id = g_strdup(job->id),
+ .type = job_type(job),
+ .status = job->status,
+ .current_progress = job->progress_current,
+ .total_progress = job->progress_total,
+ .has_error = !!job->error,
+ .error = g_strdup(job->error),
+ };
+
+ return info;
+}
+
+JobInfoList *qmp_query_jobs(Error **errp)
+{
+ JobInfoList *head = NULL, **p_next = &head;
+ Job *job;
+
+ for (job = job_next(NULL); job; job = job_next(job)) {
+ JobInfoList *elem;
+ AioContext *aio_context;
+
+ if (job_is_internal(job)) {
+ continue;
+ }
+ elem = g_new0(JobInfoList, 1);
+ aio_context = job->aio_context;
+ aio_context_acquire(aio_context);
+ elem->value = job_query_single(job, errp);
+ aio_context_release(aio_context);
+ if (!elem->value) {
+ g_free(elem);
+ qapi_free_JobInfoList(head);
+ return NULL;
+ }
+ *p_next = elem;
+ p_next = &elem->next;
+ }
+
+ return head;
+}
diff --git a/job.c b/job.c
new file mode 100644
index 0000000000..84e140238b
--- /dev/null
+++ b/job.c
@@ -0,0 +1,1012 @@
+/*
+ * Background jobs (long-running operations)
+ *
+ * Copyright (c) 2011 IBM Corp.
+ * Copyright (c) 2012, 2018 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qapi/error.h"
+#include "qemu/job.h"
+#include "qemu/id.h"
+#include "qemu/main-loop.h"
+#include "trace-root.h"
+#include "qapi/qapi-events-job.h"
+
+static QLIST_HEAD(, Job) jobs = QLIST_HEAD_INITIALIZER(jobs);
+
+/* Job State Transition Table */
+bool JobSTT[JOB_STATUS__MAX][JOB_STATUS__MAX] = {
+ /* U, C, R, P, Y, S, W, D, X, E, N */
+ /* U: */ [JOB_STATUS_UNDEFINED] = {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* C: */ [JOB_STATUS_CREATED] = {0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1},
+ /* R: */ [JOB_STATUS_RUNNING] = {0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0},
+ /* P: */ [JOB_STATUS_PAUSED] = {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* Y: */ [JOB_STATUS_READY] = {0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0},
+ /* S: */ [JOB_STATUS_STANDBY] = {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
+ /* W: */ [JOB_STATUS_WAITING] = {0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0},
+ /* D: */ [JOB_STATUS_PENDING] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0},
+ /* X: */ [JOB_STATUS_ABORTING] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0},
+ /* E: */ [JOB_STATUS_CONCLUDED] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
+ /* N: */ [JOB_STATUS_NULL] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+};
+
+bool JobVerbTable[JOB_VERB__MAX][JOB_STATUS__MAX] = {
+ /* U, C, R, P, Y, S, W, D, X, E, N */
+ [JOB_VERB_CANCEL] = {0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0},
+ [JOB_VERB_PAUSE] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
+ [JOB_VERB_RESUME] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
+ [JOB_VERB_SET_SPEED] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
+ [JOB_VERB_COMPLETE] = {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
+ [JOB_VERB_FINALIZE] = {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0},
+ [JOB_VERB_DISMISS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
+};
+
+/* Transactional group of jobs */
+struct JobTxn {
+
+ /* Is this txn being cancelled? */
+ bool aborting;
+
+ /* List of jobs */
+ QLIST_HEAD(, Job) jobs;
+
+ /* Reference count */
+ int refcnt;
+};
+
+/* Right now, this mutex is only needed to synchronize accesses to job->busy
+ * and job->sleep_timer, such as concurrent calls to job_do_yield and
+ * job_enter. */
+static QemuMutex job_mutex;
+
+static void job_lock(void)
+{
+ qemu_mutex_lock(&job_mutex);
+}
+
+static void job_unlock(void)
+{
+ qemu_mutex_unlock(&job_mutex);
+}
+
+static void __attribute__((__constructor__)) job_init(void)
+{
+ qemu_mutex_init(&job_mutex);
+}
+
+JobTxn *job_txn_new(void)
+{
+ JobTxn *txn = g_new0(JobTxn, 1);
+ QLIST_INIT(&txn->jobs);
+ txn->refcnt = 1;
+ return txn;
+}
+
+static void job_txn_ref(JobTxn *txn)
+{
+ txn->refcnt++;
+}
+
+void job_txn_unref(JobTxn *txn)
+{
+ if (txn && --txn->refcnt == 0) {
+ g_free(txn);
+ }
+}
+
+void job_txn_add_job(JobTxn *txn, Job *job)
+{
+ if (!txn) {
+ return;
+ }
+
+ assert(!job->txn);
+ job->txn = txn;
+
+ QLIST_INSERT_HEAD(&txn->jobs, job, txn_list);
+ job_txn_ref(txn);
+}
+
+static void job_txn_del_job(Job *job)
+{
+ if (job->txn) {
+ QLIST_REMOVE(job, txn_list);
+ job_txn_unref(job->txn);
+ job->txn = NULL;
+ }
+}
+
+static int job_txn_apply(JobTxn *txn, int fn(Job *), bool lock)
+{
+ AioContext *ctx;
+ Job *job, *next;
+ int rc = 0;
+
+ QLIST_FOREACH_SAFE(job, &txn->jobs, txn_list, next) {
+ if (lock) {
+ ctx = job->aio_context;
+ aio_context_acquire(ctx);
+ }
+ rc = fn(job);
+ if (lock) {
+ aio_context_release(ctx);
+ }
+ if (rc) {
+ break;
+ }
+ }
+ return rc;
+}
+
+bool job_is_internal(Job *job)
+{
+ return (job->id == NULL);
+}
+
+static void job_state_transition(Job *job, JobStatus s1)
+{
+ JobStatus s0 = job->status;
+ assert(s1 >= 0 && s1 <= JOB_STATUS__MAX);
+ trace_job_state_transition(job, job->ret,
+ JobSTT[s0][s1] ? "allowed" : "disallowed",
+ JobStatus_str(s0), JobStatus_str(s1));
+ assert(JobSTT[s0][s1]);
+ job->status = s1;
+
+ if (!job_is_internal(job) && s1 != s0) {
+ qapi_event_send_job_status_change(job->id, job->status, &error_abort);
+ }
+}
+
+int job_apply_verb(Job *job, JobVerb verb, Error **errp)
+{
+ JobStatus s0 = job->status;
+ assert(verb >= 0 && verb <= JOB_VERB__MAX);
+ trace_job_apply_verb(job, JobStatus_str(s0), JobVerb_str(verb),
+ JobVerbTable[verb][s0] ? "allowed" : "prohibited");
+ if (JobVerbTable[verb][s0]) {
+ return 0;
+ }
+ error_setg(errp, "Job '%s' in state '%s' cannot accept command verb '%s'",
+ job->id, JobStatus_str(s0), JobVerb_str(verb));
+ return -EPERM;
+}
+
+JobType job_type(const Job *job)
+{
+ return job->driver->job_type;
+}
+
+const char *job_type_str(const Job *job)
+{
+ return JobType_str(job_type(job));
+}
+
+bool job_is_cancelled(Job *job)
+{
+ return job->cancelled;
+}
+
+bool job_is_ready(Job *job)
+{
+ switch (job->status) {
+ case JOB_STATUS_UNDEFINED:
+ case JOB_STATUS_CREATED:
+ case JOB_STATUS_RUNNING:
+ case JOB_STATUS_PAUSED:
+ case JOB_STATUS_WAITING:
+ case JOB_STATUS_PENDING:
+ case JOB_STATUS_ABORTING:
+ case JOB_STATUS_CONCLUDED:
+ case JOB_STATUS_NULL:
+ return false;
+ case JOB_STATUS_READY:
+ case JOB_STATUS_STANDBY:
+ return true;
+ default:
+ g_assert_not_reached();
+ }
+ return false;
+}
+
+bool job_is_completed(Job *job)
+{
+ switch (job->status) {
+ case JOB_STATUS_UNDEFINED:
+ case JOB_STATUS_CREATED:
+ case JOB_STATUS_RUNNING:
+ case JOB_STATUS_PAUSED:
+ case JOB_STATUS_READY:
+ case JOB_STATUS_STANDBY:
+ return false;
+ case JOB_STATUS_WAITING:
+ case JOB_STATUS_PENDING:
+ case JOB_STATUS_ABORTING:
+ case JOB_STATUS_CONCLUDED:
+ case JOB_STATUS_NULL:
+ return true;
+ default:
+ g_assert_not_reached();
+ }
+ return false;
+}
+
+static bool job_started(Job *job)
+{
+ return job->co;
+}
+
+static bool job_should_pause(Job *job)
+{
+ return job->pause_count > 0;
+}
+
+Job *job_next(Job *job)
+{
+ if (!job) {
+ return QLIST_FIRST(&jobs);
+ }
+ return QLIST_NEXT(job, job_list);
+}
+
+Job *job_get(const char *id)
+{
+ Job *job;
+
+ QLIST_FOREACH(job, &jobs, job_list) {
+ if (job->id && !strcmp(id, job->id)) {
+ return job;
+ }
+ }
+
+ return NULL;
+}
+
+static void job_sleep_timer_cb(void *opaque)
+{
+ Job *job = opaque;
+
+ job_enter(job);
+}
+
+void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn,
+ AioContext *ctx, int flags, BlockCompletionFunc *cb,
+ void *opaque, Error **errp)
+{
+ Job *job;
+
+ if (job_id) {
+ if (flags & JOB_INTERNAL) {
+ error_setg(errp, "Cannot specify job ID for internal job");
+ return NULL;
+ }
+ if (!id_wellformed(job_id)) {
+ error_setg(errp, "Invalid job ID '%s'", job_id);
+ return NULL;
+ }
+ if (job_get(job_id)) {
+ error_setg(errp, "Job ID '%s' already in use", job_id);
+ return NULL;
+ }
+ } else if (!(flags & JOB_INTERNAL)) {
+ error_setg(errp, "An explicit job ID is required");
+ return NULL;
+ }
+
+ job = g_malloc0(driver->instance_size);
+ job->driver = driver;
+ job->id = g_strdup(job_id);
+ job->refcnt = 1;
+ job->aio_context = ctx;
+ job->busy = false;
+ job->paused = true;
+ job->pause_count = 1;
+ job->auto_finalize = !(flags & JOB_MANUAL_FINALIZE);
+ job->auto_dismiss = !(flags & JOB_MANUAL_DISMISS);
+ job->cb = cb;
+ job->opaque = opaque;
+
+ notifier_list_init(&job->on_finalize_cancelled);
+ notifier_list_init(&job->on_finalize_completed);
+ notifier_list_init(&job->on_pending);
+ notifier_list_init(&job->on_ready);
+
+ job_state_transition(job, JOB_STATUS_CREATED);
+ aio_timer_init(qemu_get_aio_context(), &job->sleep_timer,
+ QEMU_CLOCK_REALTIME, SCALE_NS,
+ job_sleep_timer_cb, job);
+
+ QLIST_INSERT_HEAD(&jobs, job, job_list);
+
+ /* Single jobs are modeled as single-job transactions for sake of
+ * consolidating the job management logic */
+ if (!txn) {
+ txn = job_txn_new();
+ job_txn_add_job(txn, job);
+ job_txn_unref(txn);
+ } else {
+ job_txn_add_job(txn, job);
+ }
+
+ return job;
+}
+
+void job_ref(Job *job)
+{
+ ++job->refcnt;
+}
+
+void job_unref(Job *job)
+{
+ if (--job->refcnt == 0) {
+ assert(job->status == JOB_STATUS_NULL);
+ assert(!timer_pending(&job->sleep_timer));
+ assert(!job->txn);
+
+ if (job->driver->free) {
+ job->driver->free(job);
+ }
+
+ QLIST_REMOVE(job, job_list);
+
+ g_free(job->error);
+ g_free(job->id);
+ g_free(job);
+ }
+}
+
+void job_progress_update(Job *job, uint64_t done)
+{
+ job->progress_current += done;
+}
+
+void job_progress_set_remaining(Job *job, uint64_t remaining)
+{
+ job->progress_total = job->progress_current + remaining;
+}
+
+void job_event_cancelled(Job *job)
+{
+ notifier_list_notify(&job->on_finalize_cancelled, job);
+}
+
+void job_event_completed(Job *job)
+{
+ notifier_list_notify(&job->on_finalize_completed, job);
+}
+
+static void job_event_pending(Job *job)
+{
+ notifier_list_notify(&job->on_pending, job);
+}
+
+static void job_event_ready(Job *job)
+{
+ notifier_list_notify(&job->on_ready, job);
+}
+
+void job_enter_cond(Job *job, bool(*fn)(Job *job))
+{
+ if (!job_started(job)) {
+ return;
+ }
+ if (job->deferred_to_main_loop) {
+ return;
+ }
+
+ job_lock();
+ if (job->busy) {
+ job_unlock();
+ return;
+ }
+
+ if (fn && !fn(job)) {
+ job_unlock();
+ return;
+ }
+
+ assert(!job->deferred_to_main_loop);
+ timer_del(&job->sleep_timer);
+ job->busy = true;
+ job_unlock();
+ aio_co_wake(job->co);
+}
+
+void job_enter(Job *job)
+{
+ job_enter_cond(job, NULL);
+}
+
+/* Yield, and schedule a timer to reenter the coroutine after @ns nanoseconds.
+ * Reentering the job coroutine with job_enter() before the timer has expired
+ * is allowed and cancels the timer.
+ *
+ * If @ns is (uint64_t) -1, no timer is scheduled and job_enter() must be
+ * called explicitly. */
+static void coroutine_fn job_do_yield(Job *job, uint64_t ns)
+{
+ job_lock();
+ if (ns != -1) {
+ timer_mod(&job->sleep_timer, ns);
+ }
+ job->busy = false;
+ job_unlock();
+ qemu_coroutine_yield();
+
+ /* Set by job_enter_cond() before re-entering the coroutine. */
+ assert(job->busy);
+}
+
+void coroutine_fn job_pause_point(Job *job)
+{
+ assert(job && job_started(job));
+
+ if (!job_should_pause(job)) {
+ return;
+ }
+ if (job_is_cancelled(job)) {
+ return;
+ }
+
+ if (job->driver->pause) {
+ job->driver->pause(job);
+ }
+
+ if (job_should_pause(job) && !job_is_cancelled(job)) {
+ JobStatus status = job->status;
+ job_state_transition(job, status == JOB_STATUS_READY
+ ? JOB_STATUS_STANDBY
+ : JOB_STATUS_PAUSED);
+ job->paused = true;
+ job_do_yield(job, -1);
+ job->paused = false;
+ job_state_transition(job, status);
+ }
+
+ if (job->driver->resume) {
+ job->driver->resume(job);
+ }
+}
+
+void job_yield(Job *job)
+{
+ assert(job->busy);
+
+ /* Check cancellation *before* setting busy = false, too! */
+ if (job_is_cancelled(job)) {
+ return;
+ }
+
+ if (!job_should_pause(job)) {
+ job_do_yield(job, -1);
+ }
+
+ job_pause_point(job);
+}
+
+void coroutine_fn job_sleep_ns(Job *job, int64_t ns)
+{
+ assert(job->busy);
+
+ /* Check cancellation *before* setting busy = false, too! */
+ if (job_is_cancelled(job)) {
+ return;
+ }
+
+ if (!job_should_pause(job)) {
+ job_do_yield(job, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + ns);
+ }
+
+ job_pause_point(job);
+}
+
+void job_drain(Job *job)
+{
+ /* If job is !busy this kicks it into the next pause point. */
+ job_enter(job);
+
+ if (job->driver->drain) {
+ job->driver->drain(job);
+ }
+}
+
+
+/**
+ * All jobs must allow a pause point before entering their job proper. This
+ * ensures that jobs can be paused prior to being started, then resumed later.
+ */
+static void coroutine_fn job_co_entry(void *opaque)
+{
+ Job *job = opaque;
+
+ assert(job && job->driver && job->driver->start);
+ job_pause_point(job);
+ job->driver->start(job);
+}
+
+
+void job_start(Job *job)
+{
+ assert(job && !job_started(job) && job->paused &&
+ job->driver && job->driver->start);
+ job->co = qemu_coroutine_create(job_co_entry, job);
+ job->pause_count--;
+ job->busy = true;
+ job->paused = false;
+ job_state_transition(job, JOB_STATUS_RUNNING);
+ aio_co_enter(job->aio_context, job->co);
+}
+
+/* Assumes the block_job_mutex is held */
+static bool job_timer_not_pending(Job *job)
+{
+ return !timer_pending(&job->sleep_timer);
+}
+
+void job_pause(Job *job)
+{
+ job->pause_count++;
+}
+
+void job_resume(Job *job)
+{
+ assert(job->pause_count > 0);
+ job->pause_count--;
+ if (job->pause_count) {
+ return;
+ }
+
+ /* kick only if no timer is pending */
+ job_enter_cond(job, job_timer_not_pending);
+}
+
+void job_user_pause(Job *job, Error **errp)
+{
+ if (job_apply_verb(job, JOB_VERB_PAUSE, errp)) {
+ return;
+ }
+ if (job->user_paused) {
+ error_setg(errp, "Job is already paused");
+ return;
+ }
+ job->user_paused = true;
+ job_pause(job);
+}
+
+bool job_user_paused(Job *job)
+{
+ return job->user_paused;
+}
+
+void job_user_resume(Job *job, Error **errp)
+{
+ assert(job);
+ if (!job->user_paused || job->pause_count <= 0) {
+ error_setg(errp, "Can't resume a job that was not paused");
+ return;
+ }
+ if (job_apply_verb(job, JOB_VERB_RESUME, errp)) {
+ return;
+ }
+ if (job->driver->user_resume) {
+ job->driver->user_resume(job);
+ }
+ job->user_paused = false;
+ job_resume(job);
+}
+
+static void job_do_dismiss(Job *job)
+{
+ assert(job);
+ job->busy = false;
+ job->paused = false;
+ job->deferred_to_main_loop = true;
+
+ job_txn_del_job(job);
+
+ job_state_transition(job, JOB_STATUS_NULL);
+ job_unref(job);
+}
+
+void job_dismiss(Job **jobptr, Error **errp)
+{
+ Job *job = *jobptr;
+ /* similarly to _complete, this is QMP-interface only. */
+ assert(job->id);
+ if (job_apply_verb(job, JOB_VERB_DISMISS, errp)) {
+ return;
+ }
+
+ job_do_dismiss(job);
+ *jobptr = NULL;
+}
+
+void job_early_fail(Job *job)
+{
+ assert(job->status == JOB_STATUS_CREATED);
+ job_do_dismiss(job);
+}
+
+static void job_conclude(Job *job)
+{
+ job_state_transition(job, JOB_STATUS_CONCLUDED);
+ if (job->auto_dismiss || !job_started(job)) {
+ job_do_dismiss(job);
+ }
+}
+
+static void job_update_rc(Job *job)
+{
+ if (!job->ret && job_is_cancelled(job)) {
+ job->ret = -ECANCELED;
+ }
+ if (job->ret) {
+ if (!job->error) {
+ job->error = g_strdup(strerror(-job->ret));
+ }
+ job_state_transition(job, JOB_STATUS_ABORTING);
+ }
+}
+
+static void job_commit(Job *job)
+{
+ assert(!job->ret);
+ if (job->driver->commit) {
+ job->driver->commit(job);
+ }
+}
+
+static void job_abort(Job *job)
+{
+ assert(job->ret);
+ if (job->driver->abort) {
+ job->driver->abort(job);
+ }
+}
+
+static void job_clean(Job *job)
+{
+ if (job->driver->clean) {
+ job->driver->clean(job);
+ }
+}
+
+static int job_finalize_single(Job *job)
+{
+ assert(job_is_completed(job));
+
+ /* Ensure abort is called for late-transactional failures */
+ job_update_rc(job);
+
+ if (!job->ret) {
+ job_commit(job);
+ } else {
+ job_abort(job);
+ }
+ job_clean(job);
+
+ if (job->cb) {
+ job->cb(job->opaque, job->ret);
+ }
+
+ /* Emit events only if we actually started */
+ if (job_started(job)) {
+ if (job_is_cancelled(job)) {
+ job_event_cancelled(job);
+ } else {
+ job_event_completed(job);
+ }
+ }
+
+ job_txn_del_job(job);
+ job_conclude(job);
+ return 0;
+}
+
+static void job_cancel_async(Job *job, bool force)
+{
+ if (job->user_paused) {
+ /* Do not call job_enter here, the caller will handle it. */
+ job->user_paused = false;
+ if (job->driver->user_resume) {
+ job->driver->user_resume(job);
+ }
+ assert(job->pause_count > 0);
+ job->pause_count--;
+ }
+ job->cancelled = true;
+ /* To prevent 'force == false' overriding a previous 'force == true' */
+ job->force_cancel |= force;
+}
+
+static void job_completed_txn_abort(Job *job)
+{
+ AioContext *ctx;
+ JobTxn *txn = job->txn;
+ Job *other_job;
+
+ if (txn->aborting) {
+ /*
+ * We are cancelled by another job, which will handle everything.
+ */
+ return;
+ }
+ txn->aborting = true;
+ job_txn_ref(txn);
+
+ /* We are the first failed job. Cancel other jobs. */
+ QLIST_FOREACH(other_job, &txn->jobs, txn_list) {
+ ctx = other_job->aio_context;
+ aio_context_acquire(ctx);
+ }
+
+ /* Other jobs are effectively cancelled by us, set the status for
+ * them; this job, however, may or may not be cancelled, depending
+ * on the caller, so leave it. */
+ QLIST_FOREACH(other_job, &txn->jobs, txn_list) {
+ if (other_job != job) {
+ job_cancel_async(other_job, false);
+ }
+ }
+ while (!QLIST_EMPTY(&txn->jobs)) {
+ other_job = QLIST_FIRST(&txn->jobs);
+ ctx = other_job->aio_context;
+ if (!job_is_completed(other_job)) {
+ assert(job_is_cancelled(other_job));
+ job_finish_sync(other_job, NULL, NULL);
+ }
+ job_finalize_single(other_job);
+ aio_context_release(ctx);
+ }
+
+ job_txn_unref(txn);
+}
+
+static int job_prepare(Job *job)
+{
+ if (job->ret == 0 && job->driver->prepare) {
+ job->ret = job->driver->prepare(job);
+ job_update_rc(job);
+ }
+ return job->ret;
+}
+
+static int job_needs_finalize(Job *job)
+{
+ return !job->auto_finalize;
+}
+
+static void job_do_finalize(Job *job)
+{
+ int rc;
+ assert(job && job->txn);
+
+ /* prepare the transaction to complete */
+ rc = job_txn_apply(job->txn, job_prepare, true);
+ if (rc) {
+ job_completed_txn_abort(job);
+ } else {
+ job_txn_apply(job->txn, job_finalize_single, true);
+ }
+}
+
+void job_finalize(Job *job, Error **errp)
+{
+ assert(job && job->id);
+ if (job_apply_verb(job, JOB_VERB_FINALIZE, errp)) {
+ return;
+ }
+ job_do_finalize(job);
+}
+
+static int job_transition_to_pending(Job *job)
+{
+ job_state_transition(job, JOB_STATUS_PENDING);
+ if (!job->auto_finalize) {
+ job_event_pending(job);
+ }
+ return 0;
+}
+
+void job_transition_to_ready(Job *job)
+{
+ job_state_transition(job, JOB_STATUS_READY);
+ job_event_ready(job);
+}
+
+static void job_completed_txn_success(Job *job)
+{
+ JobTxn *txn = job->txn;
+ Job *other_job;
+
+ job_state_transition(job, JOB_STATUS_WAITING);
+
+ /*
+ * Successful completion, see if there are other running jobs in this
+ * txn.
+ */
+ QLIST_FOREACH(other_job, &txn->jobs, txn_list) {
+ if (!job_is_completed(other_job)) {
+ return;
+ }
+ assert(other_job->ret == 0);
+ }
+
+ job_txn_apply(txn, job_transition_to_pending, false);
+
+ /* If no jobs need manual finalization, automatically do so */
+ if (job_txn_apply(txn, job_needs_finalize, false) == 0) {
+ job_do_finalize(job);
+ }
+}
+
+void job_completed(Job *job, int ret, Error *error)
+{
+ assert(job && job->txn && !job_is_completed(job));
+
+ job->ret = ret;
+ if (error) {
+ assert(job->ret < 0);
+ job->error = g_strdup(error_get_pretty(error));
+ error_free(error);
+ }
+
+ job_update_rc(job);
+ trace_job_completed(job, ret, job->ret);
+ if (job->ret) {
+ job_completed_txn_abort(job);
+ } else {
+ job_completed_txn_success(job);
+ }
+}
+
+void job_cancel(Job *job, bool force)
+{
+ if (job->status == JOB_STATUS_CONCLUDED) {
+ job_do_dismiss(job);
+ return;
+ }
+ job_cancel_async(job, force);
+ if (!job_started(job)) {
+ job_completed(job, -ECANCELED, NULL);
+ } else if (job->deferred_to_main_loop) {
+ job_completed_txn_abort(job);
+ } else {
+ job_enter(job);
+ }
+}
+
+void job_user_cancel(Job *job, bool force, Error **errp)
+{
+ if (job_apply_verb(job, JOB_VERB_CANCEL, errp)) {
+ return;
+ }
+ job_cancel(job, force);
+}
+
+/* A wrapper around job_cancel() taking an Error ** parameter so it may be
+ * used with job_finish_sync() without the need for (rather nasty) function
+ * pointer casts there. */
+static void job_cancel_err(Job *job, Error **errp)
+{
+ job_cancel(job, false);
+}
+
+int job_cancel_sync(Job *job)
+{
+ return job_finish_sync(job, &job_cancel_err, NULL);
+}
+
+void job_cancel_sync_all(void)
+{
+ Job *job;
+ AioContext *aio_context;
+
+ while ((job = job_next(NULL))) {
+ aio_context = job->aio_context;
+ aio_context_acquire(aio_context);
+ job_cancel_sync(job);
+ aio_context_release(aio_context);
+ }
+}
+
+int job_complete_sync(Job *job, Error **errp)
+{
+ return job_finish_sync(job, job_complete, errp);
+}
+
+void job_complete(Job *job, Error **errp)
+{
+ /* Should not be reachable via external interface for internal jobs */
+ assert(job->id);
+ if (job_apply_verb(job, JOB_VERB_COMPLETE, errp)) {
+ return;
+ }
+ if (job->pause_count || job_is_cancelled(job) || !job->driver->complete) {
+ error_setg(errp, "The active block job '%s' cannot be completed",
+ job->id);
+ return;
+ }
+
+ job->driver->complete(job, errp);
+}
+
+
+typedef struct {
+ Job *job;
+ JobDeferToMainLoopFn *fn;
+ void *opaque;
+} JobDeferToMainLoopData;
+
+static void job_defer_to_main_loop_bh(void *opaque)
+{
+ JobDeferToMainLoopData *data = opaque;
+ Job *job = data->job;
+ AioContext *aio_context = job->aio_context;
+
+ aio_context_acquire(aio_context);
+ data->fn(data->job, data->opaque);
+ aio_context_release(aio_context);
+
+ g_free(data);
+}
+
+void job_defer_to_main_loop(Job *job, JobDeferToMainLoopFn *fn, void *opaque)
+{
+ JobDeferToMainLoopData *data = g_malloc(sizeof(*data));
+ data->job = job;
+ data->fn = fn;
+ data->opaque = opaque;
+ job->deferred_to_main_loop = true;
+
+ aio_bh_schedule_oneshot(qemu_get_aio_context(),
+ job_defer_to_main_loop_bh, data);
+}
+
+int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp)
+{
+ Error *local_err = NULL;
+ int ret;
+
+ job_ref(job);
+
+ if (finish) {
+ finish(job, &local_err);
+ }
+ if (local_err) {
+ error_propagate(errp, local_err);
+ job_unref(job);
+ return -EBUSY;
+ }
+ /* job_drain calls job_enter, and it should be enough to induce progress
+ * until the job completes or moves to the main thread. */
+ while (!job->deferred_to_main_loop && !job_is_completed(job)) {
+ job_drain(job);
+ }
+ while (!job_is_completed(job)) {
+ aio_poll(qemu_get_aio_context(), true);
+ }
+ ret = (job_is_cancelled(job) && job->ret == 0) ? -ECANCELED : job->ret;
+ job_unref(job);
+ return ret;
+}
diff --git a/linux-headers/COPYING b/linux-headers/COPYING
index ca442d313d..da4cb28feb 100644
--- a/linux-headers/COPYING
+++ b/linux-headers/COPYING
@@ -1,356 +1,18 @@
+The Linux Kernel is provided under:
- NOTE! This copyright does *not* cover user programs that use kernel
- services by normal system calls - this is merely considered normal use
- of the kernel, and does *not* fall under the heading of "derived work".
- Also note that the GPL below is copyrighted by the Free Software
- Foundation, but the instance of code that it refers to (the Linux
- kernel) is copyrighted by me and others who actually wrote it.
+ SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
- Also note that the only valid version of the GPL as far as the kernel
- is concerned is _this_ particular version of the license (ie v2, not
- v2.2 or v3.x or whatever), unless explicitly otherwise stated.
+Being under the terms of the GNU General Public License version 2 only,
+according with:
- Linus Torvalds
+ LICENSES/preferred/GPL-2.0
-----------------------------------------
+With an explicit syscall exception, as stated at:
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
+ LICENSES/exceptions/Linux-syscall-note
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
+In addition, other licenses may also apply. Please see:
- Preamble
+ Documentation/process/license-rules.rst
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program 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 General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Library General
-Public License instead of this License.
+for more details.
diff --git a/linux-headers/LICENSES/exceptions/Linux-syscall-note b/linux-headers/LICENSES/exceptions/Linux-syscall-note
new file mode 100644
index 0000000000..6b60b61be4
--- /dev/null
+++ b/linux-headers/LICENSES/exceptions/Linux-syscall-note
@@ -0,0 +1,25 @@
+SPDX-Exception-Identifier: Linux-syscall-note
+SPDX-URL: https://spdx.org/licenses/Linux-syscall-note.html
+SPDX-Licenses: GPL-2.0, GPL-2.0+, GPL-1.0+, LGPL-2.0, LGPL-2.0+, LGPL-2.1, LGPL-2.1+
+Usage-Guide:
+ This exception is used together with one of the above SPDX-Licenses
+ to mark user space API (uapi) header files so they can be included
+ into non GPL compliant user space application code.
+ To use this exception add it with the keyword WITH to one of the
+ identifiers in the SPDX-Licenses tag:
+ SPDX-License-Identifier: <SPDX-License> WITH Linux-syscall-note
+License-Text:
+
+ NOTE! This copyright does *not* cover user programs that use kernel
+ services by normal system calls - this is merely considered normal use
+ of the kernel, and does *not* fall under the heading of "derived work".
+ Also note that the GPL below is copyrighted by the Free Software
+ Foundation, but the instance of code that it refers to (the Linux
+ kernel) is copyrighted by me and others who actually wrote it.
+
+ Also note that the only valid version of the GPL as far as the kernel
+ is concerned is _this_ particular version of the license (ie v2, not
+ v2.2 or v3.x or whatever), unless explicitly otherwise stated.
+
+ Linus Torvalds
+
diff --git a/linux-headers/LICENSES/preferred/BSD-2-Clause b/linux-headers/LICENSES/preferred/BSD-2-Clause
new file mode 100644
index 0000000000..da366e2ce5
--- /dev/null
+++ b/linux-headers/LICENSES/preferred/BSD-2-Clause
@@ -0,0 +1,32 @@
+Valid-License-Identifier: BSD-2-Clause
+SPDX-URL: https://spdx.org/licenses/BSD-2-Clause.html
+Usage-Guide:
+ To use the BSD 2-clause "Simplified" License put the following SPDX
+ tag/value pair into a comment according to the placement guidelines in
+ the licensing rules documentation:
+ SPDX-License-Identifier: BSD-2-Clause
+License-Text:
+
+Copyright (c) <year> <owner> . All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/linux-headers/LICENSES/preferred/BSD-3-Clause b/linux-headers/LICENSES/preferred/BSD-3-Clause
new file mode 100644
index 0000000000..34c7f057c8
--- /dev/null
+++ b/linux-headers/LICENSES/preferred/BSD-3-Clause
@@ -0,0 +1,36 @@
+Valid-License-Identifier: BSD-3-Clause
+SPDX-URL: https://spdx.org/licenses/BSD-3-Clause.html
+Usage-Guide:
+ To use the BSD 3-clause "New" or "Revised" License put the following SPDX
+ tag/value pair into a comment according to the placement guidelines in
+ the licensing rules documentation:
+ SPDX-License-Identifier: BSD-3-Clause
+License-Text:
+
+Copyright (c) <year> <owner> . All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/linux-headers/LICENSES/preferred/GPL-2.0 b/linux-headers/LICENSES/preferred/GPL-2.0
new file mode 100644
index 0000000000..b8db91d3a1
--- /dev/null
+++ b/linux-headers/LICENSES/preferred/GPL-2.0
@@ -0,0 +1,353 @@
+Valid-License-Identifier: GPL-2.0
+Valid-License-Identifier: GPL-2.0+
+SPDX-URL: https://spdx.org/licenses/GPL-2.0.html
+Usage-Guide:
+ To use this license in source code, put one of the following SPDX
+ tag/value pairs into a comment according to the placement
+ guidelines in the licensing rules documentation.
+ For 'GNU General Public License (GPL) version 2 only' use:
+ SPDX-License-Identifier: GPL-2.0
+ For 'GNU General Public License (GPL) version 2 or any later version' use:
+ SPDX-License-Identifier: GPL-2.0+
+License-Text:
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/linux-headers/asm-arm/kvm.h b/linux-headers/asm-arm/kvm.h
index 4392955081..670b43c9e9 100644
--- a/linux-headers/asm-arm/kvm.h
+++ b/linux-headers/asm-arm/kvm.h
@@ -135,6 +135,15 @@ struct kvm_arch_memory_slot {
#define KVM_REG_ARM_CRM_SHIFT 7
#define KVM_REG_ARM_32_CRN_MASK 0x0000000000007800
#define KVM_REG_ARM_32_CRN_SHIFT 11
+/*
+ * For KVM currently all guest registers are nonsecure, but we reserve a bit
+ * in the encoding to distinguish secure from nonsecure for AArch32 system
+ * registers that are banked by security. This is 1 for the secure banked
+ * register, and 0 for the nonsecure banked register or if the register is
+ * not banked by security.
+ */
+#define KVM_REG_ARM_SECURE_MASK 0x0000000010000000
+#define KVM_REG_ARM_SECURE_SHIFT 28
#define ARM_CP15_REG_SHIFT_MASK(x,n) \
(((x) << KVM_REG_ARM_ ## n ## _SHIFT) & KVM_REG_ARM_ ## n ## _MASK)
@@ -186,6 +195,12 @@ struct kvm_arch_memory_slot {
#define KVM_REG_ARM_VFP_FPINST 0x1009
#define KVM_REG_ARM_VFP_FPINST2 0x100A
+/* KVM-as-firmware specific pseudo-registers */
+#define KVM_REG_ARM_FW (0x0014 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM_FW_REG(r) (KVM_REG_ARM | KVM_REG_SIZE_U64 | \
+ KVM_REG_ARM_FW | ((r) & 0xffff))
+#define KVM_REG_ARM_PSCI_VERSION KVM_REG_ARM_FW_REG(0)
+
/* Device Control API: ARM VGIC */
#define KVM_DEV_ARM_VGIC_GRP_ADDR 0
#define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1
diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h
index 4e80651efe..17315aba6a 100644
--- a/linux-headers/asm-arm64/kvm.h
+++ b/linux-headers/asm-arm64/kvm.h
@@ -206,6 +206,12 @@ struct kvm_arch_memory_slot {
#define KVM_REG_ARM_TIMER_CNT ARM64_SYS_REG(3, 3, 14, 3, 2)
#define KVM_REG_ARM_TIMER_CVAL ARM64_SYS_REG(3, 3, 14, 0, 2)
+/* KVM-as-firmware specific pseudo-registers */
+#define KVM_REG_ARM_FW (0x0014 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM_FW_REG(r) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
+ KVM_REG_ARM_FW | ((r) & 0xffff))
+#define KVM_REG_ARM_PSCI_VERSION KVM_REG_ARM_FW_REG(0)
+
/* Device Control API: ARM VGIC */
#define KVM_DEV_ARM_VGIC_GRP_ADDR 0
#define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1
diff --git a/linux-headers/asm-x86/hyperv.h b/linux-headers/asm-x86/hyperv.h
deleted file mode 100644
index 01af4d8593..0000000000
--- a/linux-headers/asm-x86/hyperv.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "standard-headers/asm-x86/hyperv.h"
diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h
index f3a960488e..c535c2fdea 100644
--- a/linux-headers/asm-x86/kvm.h
+++ b/linux-headers/asm-x86/kvm.h
@@ -354,8 +354,25 @@ struct kvm_xcrs {
__u64 padding[16];
};
-/* definition of registers in kvm_run */
+#define KVM_SYNC_X86_REGS (1UL << 0)
+#define KVM_SYNC_X86_SREGS (1UL << 1)
+#define KVM_SYNC_X86_EVENTS (1UL << 2)
+
+#define KVM_SYNC_X86_VALID_FIELDS \
+ (KVM_SYNC_X86_REGS| \
+ KVM_SYNC_X86_SREGS| \
+ KVM_SYNC_X86_EVENTS)
+
+/* kvm_sync_regs struct included by kvm_run struct */
struct kvm_sync_regs {
+ /* Members of this structure are potentially malicious.
+ * Care must be taken by code reading, esp. interpreting,
+ * data fields from them inside KVM to prevent TOCTOU and
+ * double-fetch types of vulnerabilities.
+ */
+ struct kvm_regs regs;
+ struct kvm_sregs sregs;
+ struct kvm_vcpu_events events;
};
#define KVM_X86_QUIRK_LINT0_REENABLED (1 << 0)
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index a167be89d1..cdb148e959 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -396,6 +396,10 @@ struct kvm_run {
char padding[256];
};
+ /* 2048 is the size of the char array used to bound/pad the size
+ * of the union that holds sync regs.
+ */
+ #define SYNC_REGS_SIZE_BYTES 2048
/*
* shared registers between kvm and userspace.
* kvm_valid_regs specifies the register classes set by the host
@@ -407,7 +411,7 @@ struct kvm_run {
__u64 kvm_dirty_regs;
union {
struct kvm_sync_regs regs;
- char padding[2048];
+ char padding[SYNC_REGS_SIZE_BYTES];
} s;
};
@@ -672,6 +676,13 @@ struct kvm_ioeventfd {
__u8 pad[36];
};
+#define KVM_X86_DISABLE_EXITS_MWAIT (1 << 0)
+#define KVM_X86_DISABLE_EXITS_HTL (1 << 1)
+#define KVM_X86_DISABLE_EXITS_PAUSE (1 << 2)
+#define KVM_X86_DISABLE_VALID_EXITS (KVM_X86_DISABLE_EXITS_MWAIT | \
+ KVM_X86_DISABLE_EXITS_HTL | \
+ KVM_X86_DISABLE_EXITS_PAUSE)
+
/* for KVM_ENABLE_CAP */
struct kvm_enable_cap {
/* in */
@@ -925,7 +936,7 @@ struct kvm_ppc_resize_hpt {
#define KVM_CAP_S390_GS 140
#define KVM_CAP_S390_AIS 141
#define KVM_CAP_SPAPR_TCE_VFIO 142
-#define KVM_CAP_X86_GUEST_MWAIT 143
+#define KVM_CAP_X86_DISABLE_EXITS 143
#define KVM_CAP_ARM_USER_IRQ 144
#define KVM_CAP_S390_CMMA_MIGRATION 145
#define KVM_CAP_PPC_FWNMI 146
@@ -936,6 +947,7 @@ struct kvm_ppc_resize_hpt {
#define KVM_CAP_PPC_GET_CPU_CHAR 151
#define KVM_CAP_S390_BPB 152
#define KVM_CAP_GET_MSR_FEATURES 153
+#define KVM_CAP_HYPERV_EVENTFD 154
#ifdef KVM_CAP_IRQ_ROUTING
@@ -1375,6 +1387,10 @@ struct kvm_enc_region {
#define KVM_MEMORY_ENCRYPT_REG_REGION _IOR(KVMIO, 0xbb, struct kvm_enc_region)
#define KVM_MEMORY_ENCRYPT_UNREG_REGION _IOR(KVMIO, 0xbc, struct kvm_enc_region)
+/* Available with KVM_CAP_HYPERV_EVENTFD */
+#define KVM_HYPERV_EVENTFD _IOW(KVMIO, 0xbd, struct kvm_hyperv_eventfd)
+
+
/* Secure Encrypted Virtualization command */
enum sev_cmd_id {
/* Guest initialization commands */
@@ -1515,4 +1531,14 @@ struct kvm_assigned_msix_entry {
#define KVM_ARM_DEV_EL1_PTIMER (1 << 1)
#define KVM_ARM_DEV_PMU (1 << 2)
+struct kvm_hyperv_eventfd {
+ __u32 conn_id;
+ __s32 fd;
+ __u32 flags;
+ __u32 padding[3];
+};
+
+#define KVM_HYPERV_CONN_ID_MASK 0x00ffffff
+#define KVM_HYPERV_EVENTFD_DEASSIGN (1 << 0)
+
#endif /* __LINUX_KVM_H */
diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h
index 3a0a305c8c..3615a269d3 100644
--- a/linux-headers/linux/vfio.h
+++ b/linux-headers/linux/vfio.h
@@ -575,6 +575,33 @@ struct vfio_device_gfx_plane_info {
#define VFIO_DEVICE_GET_GFX_DMABUF _IO(VFIO_TYPE, VFIO_BASE + 15)
+/**
+ * VFIO_DEVICE_IOEVENTFD - _IOW(VFIO_TYPE, VFIO_BASE + 16,
+ * struct vfio_device_ioeventfd)
+ *
+ * Perform a write to the device at the specified device fd offset, with
+ * the specified data and width when the provided eventfd is triggered.
+ * vfio bus drivers may not support this for all regions, for all widths,
+ * or at all. vfio-pci currently only enables support for BAR regions,
+ * excluding the MSI-X vector table.
+ *
+ * Return: 0 on success, -errno on failure.
+ */
+struct vfio_device_ioeventfd {
+ __u32 argsz;
+ __u32 flags;
+#define VFIO_DEVICE_IOEVENTFD_8 (1 << 0) /* 1-byte write */
+#define VFIO_DEVICE_IOEVENTFD_16 (1 << 1) /* 2-byte write */
+#define VFIO_DEVICE_IOEVENTFD_32 (1 << 2) /* 4-byte write */
+#define VFIO_DEVICE_IOEVENTFD_64 (1 << 3) /* 8-byte write */
+#define VFIO_DEVICE_IOEVENTFD_SIZE_MASK (0xf)
+ __u64 offset; /* device fd offset of write */
+ __u64 data; /* data to be written */
+ __s32 fd; /* -1 for de-assignment */
+};
+
+#define VFIO_DEVICE_IOEVENTFD _IO(VFIO_TYPE, VFIO_BASE + 16)
+
/* -------- API for Type1 VFIO IOMMU -------- */
/**
diff --git a/linux-user/aarch64/sockbits.h b/linux-user/aarch64/sockbits.h
new file mode 100644
index 0000000000..0e4c8f012d
--- /dev/null
+++ b/linux-user/aarch64/sockbits.h
@@ -0,0 +1 @@
+#include "../generic/sockbits.h"
diff --git a/linux-user/alpha/sockbits.h b/linux-user/alpha/sockbits.h
new file mode 100644
index 0000000000..d54dc98c09
--- /dev/null
+++ b/linux-user/alpha/sockbits.h
@@ -0,0 +1,83 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or (at your option) any
+ * later version. See the COPYING file in the top-level directory.
+ */
+
+#ifndef ALPHA_SOCKBITS_H
+#define ALPHA_SOCKBITS_H
+
+/* For setsockopt(2) */
+#define TARGET_SOL_SOCKET 0xffff
+
+#define TARGET_SO_DEBUG 0x0001
+#define TARGET_SO_REUSEADDR 0x0004
+#define TARGET_SO_KEEPALIVE 0x0008
+#define TARGET_SO_DONTROUTE 0x0010
+#define TARGET_SO_BROADCAST 0x0020
+#define TARGET_SO_LINGER 0x0080
+#define TARGET_SO_OOBINLINE 0x0100
+#define TARGET_SO_REUSEPORT 0x0200
+
+#define TARGET_SO_TYPE 0x1008
+#define TARGET_SO_ERROR 0x1007
+#define TARGET_SO_SNDBUF 0x1001
+#define TARGET_SO_RCVBUF 0x1002
+#define TARGET_SO_SNDBUFFORCE 0x100a
+#define TARGET_SO_RCVBUFFORCE 0x100b
+#define TARGET_SO_RCVLOWAT 0x1010
+#define TARGET_SO_SNDLOWAT 0x1011
+#define TARGET_SO_RCVTIMEO 0x1012
+#define TARGET_SO_SNDTIMEO 0x1013
+#define TARGET_SO_ACCEPTCONN 0x1014
+#define TARGET_SO_PROTOCOL 0x1028
+#define TARGET_SO_DOMAIN 0x1029
+
+/* linux-specific, might as well be the same as on i386 */
+#define TARGET_SO_NO_CHECK 11
+#define TARGET_SO_PRIORITY 12
+#define TARGET_SO_BSDCOMPAT 14
+
+#define TARGET_SO_PASSCRED 17
+#define TARGET_SO_PEERCRED 18
+#define TARGET_SO_BINDTODEVICE 25
+
+/* Socket filtering */
+#define TARGET_SO_ATTACH_FILTER 26
+#define TARGET_SO_DETACH_FILTER 27
+
+#define TARGET_SO_PEERNAME 28
+#define TARGET_SO_TIMESTAMP 29
+#define TARGET_SCM_TIMESTAMP TARGET_SO_TIMESTAMP
+
+#define TARGET_SO_PEERSEC 30
+#define TARGET_SO_PASSSEC 34
+#define TARGET_SO_TIMESTAMPNS 35
+#define TARGET_SCM_TIMESTAMPNS TARGET_SO_TIMESTAMPNS
+
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+#define TARGET_SO_SECURITY_AUTHENTICATION 19
+#define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 20
+#define TARGET_SO_SECURITY_ENCRYPTION_NETWORK 21
+
+#define TARGET_SO_MARK 36
+
+#define TARGET_SO_TIMESTAMPING 37
+#define TARGET_SCM_TIMESTAMPING TARGET_SO_TIMESTAMPING
+
+#define TARGET_SO_RXQ_OVFL 40
+
+#define TARGET_SO_WIFI_STATUS 41
+#define TARGET_SCM_WIFI_STATUS TARGET_SO_WIFI_STATUS
+#define TARGET_SO_PEEK_OFF 42
+
+/* Instruct lower device to use last 4-bytes of skb data as FCS */
+#define TARGET_SO_NOFCS 43
+
+/* TARGET_O_NONBLOCK clashes with the bits used for socket types. Therefore we
+ * have to define SOCK_NONBLOCK to a different value here.
+ */
+#define TARGET_SOCK_NONBLOCK 0x40000000
+
+#endif
diff --git a/linux-user/arm/sockbits.h b/linux-user/arm/sockbits.h
new file mode 100644
index 0000000000..0e4c8f012d
--- /dev/null
+++ b/linux-user/arm/sockbits.h
@@ -0,0 +1 @@
+#include "../generic/sockbits.h"
diff --git a/linux-user/cris/sockbits.h b/linux-user/cris/sockbits.h
new file mode 100644
index 0000000000..0e4c8f012d
--- /dev/null
+++ b/linux-user/cris/sockbits.h
@@ -0,0 +1 @@
+#include "../generic/sockbits.h"
diff --git a/linux-user/generic/sockbits.h b/linux-user/generic/sockbits.h
new file mode 100644
index 0000000000..e44733c601
--- /dev/null
+++ b/linux-user/generic/sockbits.h
@@ -0,0 +1,58 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or (at your option) any
+ * later version. See the COPYING file in the top-level directory.
+ */
+
+#ifndef GENERIC_SOCKBITS_H
+#define GENERIC_SOCKBITS_H
+
+#define TARGET_SO_PASSSEC 34
+
+/* For setsockopt(2) */
+#define TARGET_SOL_SOCKET 1
+
+#define TARGET_SO_DEBUG 1
+#define TARGET_SO_REUSEADDR 2
+#define TARGET_SO_TYPE 3
+#define TARGET_SO_ERROR 4
+#define TARGET_SO_DONTROUTE 5
+#define TARGET_SO_BROADCAST 6
+#define TARGET_SO_SNDBUF 7
+#define TARGET_SO_RCVBUF 8
+#define TARGET_SO_SNDBUFFORCE 32
+#define TARGET_SO_RCVBUFFORCE 33
+#define TARGET_SO_KEEPALIVE 9
+#define TARGET_SO_OOBINLINE 10
+#define TARGET_SO_NO_CHECK 11
+#define TARGET_SO_PRIORITY 12
+#define TARGET_SO_LINGER 13
+#define TARGET_SO_BSDCOMPAT 14
+#define TARGET_SO_REUSEPORT 15
+#define TARGET_SO_PASSCRED 16
+#define TARGET_SO_PEERCRED 17
+#define TARGET_SO_RCVLOWAT 18
+#define TARGET_SO_SNDLOWAT 19
+#define TARGET_SO_RCVTIMEO 20
+#define TARGET_SO_SNDTIMEO 21
+
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+#define TARGET_SO_SECURITY_AUTHENTICATION 22
+#define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 23
+#define TARGET_SO_SECURITY_ENCRYPTION_NETWORK 24
+
+#define TARGET_SO_BINDTODEVICE 25
+
+/* Socket filtering */
+#define TARGET_SO_ATTACH_FILTER 26
+#define TARGET_SO_DETACH_FILTER 27
+
+#define TARGET_SO_PEERNAME 28
+#define TARGET_SO_TIMESTAMP 29
+#define TARGET_SCM_TIMESTAMP TARGET_SO_TIMESTAMP
+
+#define TARGET_SO_ACCEPTCONN 30
+
+#define TARGET_SO_PEERSEC 31
+#endif
diff --git a/linux-user/hppa/sockbits.h b/linux-user/hppa/sockbits.h
index 5044619e16..2641aea859 100644
--- a/linux-user/hppa/sockbits.h
+++ b/linux-user/hppa/sockbits.h
@@ -64,34 +64,7 @@
#define TARGET_SO_CNX_ADVICE 0x402E
-/** sock_type - Socket types - default values
- *
- *
- * @SOCK_STREAM - stream (connection) socket
- * @SOCK_DGRAM - datagram (conn.less) socket
- * @SOCK_RAW - raw socket
- * @SOCK_RDM - reliably-delivered message
- * @SOCK_SEQPACKET - sequential packet socket
- * @SOCK_DCCP - Datagram Congestion Control Protocol socket
- * @SOCK_PACKET - linux specific way of getting packets at the dev level.
- * For writing rarp and other similar things on the user
- * level.
- * @SOCK_CLOEXEC - sets the close-on-exec (FD_CLOEXEC) flag.
- * @SOCK_NONBLOCK - sets the O_NONBLOCK file status flag.
+/* TARGET_O_NONBLOCK clashes with the bits used for socket types. Therefore we
+ * have to define SOCK_NONBLOCK to a different value here.
*/
-enum sock_type {
- TARGET_SOCK_STREAM = 1,
- TARGET_SOCK_DGRAM = 2,
- TARGET_SOCK_RAW = 3,
- TARGET_SOCK_RDM = 4,
- TARGET_SOCK_SEQPACKET = 5,
- TARGET_SOCK_DCCP = 6,
- TARGET_SOCK_PACKET = 10,
- TARGET_SOCK_CLOEXEC = 010000000,
- TARGET_SOCK_NONBLOCK = 0x40000000,
-};
-
-#define TARGET_SOCK_MAX (TARGET_SOCK_PACKET + 1)
-#define TARGET_SOCK_TYPE_MASK 0xf /* Covers up to TARGET_SOCK_MAX-1. */
-
-#define ARCH_HAS_SOCKET_TYPES 1
+#define TARGET_SOCK_NONBLOCK 0x40000000
diff --git a/linux-user/i386/sockbits.h b/linux-user/i386/sockbits.h
new file mode 100644
index 0000000000..0e4c8f012d
--- /dev/null
+++ b/linux-user/i386/sockbits.h
@@ -0,0 +1 @@
+#include "../generic/sockbits.h"
diff --git a/linux-user/m68k/sockbits.h b/linux-user/m68k/sockbits.h
new file mode 100644
index 0000000000..0e4c8f012d
--- /dev/null
+++ b/linux-user/m68k/sockbits.h
@@ -0,0 +1 @@
+#include "../generic/sockbits.h"
diff --git a/linux-user/main.c b/linux-user/main.c
index 32347545c9..78d6d3e7eb 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -671,9 +671,8 @@ int main(int argc, char **argv, char **envp)
}
cpu_type = parse_cpu_model(cpu_model);
+ /* init tcg before creating CPUs and to get qemu_host_page_size */
tcg_exec_init(0);
- /* NOTE: we need to init the CPU at this stage to get
- qemu_host_page_size */
cpu = cpu_create(cpu_type);
env = cpu->env_ptr;
@@ -693,7 +692,7 @@ int main(int argc, char **argv, char **envp)
envlist_free(envlist);
/*
- * Now that page sizes are configured in cpu_init() we can do
+ * Now that page sizes are configured in tcg_exec_init() we can do
* proper page alignment for guest_base.
*/
guest_base = HOST_PAGE_ALIGN(guest_base);
diff --git a/linux-user/microblaze/cpu_loop.c b/linux-user/microblaze/cpu_loop.c
index 5ffb83dea2..5af12d5b21 100644
--- a/linux-user/microblaze/cpu_loop.c
+++ b/linux-user/microblaze/cpu_loop.c
@@ -105,8 +105,8 @@ void cpu_loop(CPUMBState *env)
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
default:
- printf ("Unhandled hw-exception: 0x%x\n",
- env->sregs[SR_ESR] & ESR_EC_MASK);
+ printf("Unhandled hw-exception: 0x%" PRIx64 "\n",
+ env->sregs[SR_ESR] & ESR_EC_MASK);
cpu_dump_state(cs, stderr, fprintf, 0);
exit(EXIT_FAILURE);
break;
diff --git a/linux-user/microblaze/sockbits.h b/linux-user/microblaze/sockbits.h
new file mode 100644
index 0000000000..0e4c8f012d
--- /dev/null
+++ b/linux-user/microblaze/sockbits.h
@@ -0,0 +1 @@
+#include "../generic/sockbits.h"
diff --git a/linux-user/mips/sockbits.h b/linux-user/mips/sockbits.h
new file mode 100644
index 0000000000..0f022cd598
--- /dev/null
+++ b/linux-user/mips/sockbits.h
@@ -0,0 +1,110 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or (at your option) any
+ * later version. See the COPYING file in the top-level directory.
+ */
+
+#ifndef MIPS_SOCKBITS_H
+#define MIPS_SOCKBITS_H
+/* MIPS special values for constants */
+
+/*
+ * For setsockopt(2)
+ *
+ * This defines are ABI conformant as far as Linux supports these ...
+ */
+#define TARGET_SOL_SOCKET 0xffff
+
+#define TARGET_SO_DEBUG 0x0001 /* Record debugging information. */
+#define TARGET_SO_REUSEADDR 0x0004 /* Allow reuse of local addresses. */
+#define TARGET_SO_KEEPALIVE 0x0008 /* Keep connections alive and send
+ SIGPIPE when they die. */
+#define TARGET_SO_DONTROUTE 0x0010 /* Don't do local routing. */
+#define TARGET_SO_BROADCAST 0x0020 /* Allow transmission of
+ broadcast messages. */
+#define TARGET_SO_LINGER 0x0080 /* Block on close of a reliable
+ * socket to transmit pending data.
+ */
+#define TARGET_SO_OOBINLINE 0x0100 /* Receive out-of-band data in-band.
+ */
+#define TARGET_SO_REUSEPORT 0x0200
+
+#define TARGET_SO_TYPE 0x1008 /* Compatible name for SO_STYLE. */
+#define TARGET_SO_STYLE SO_TYPE /* Synonym */
+#define TARGET_SO_ERROR 0x1007 /* get error status and clear */
+#define TARGET_SO_SNDBUF 0x1001 /* Send buffer size. */
+#define TARGET_SO_RCVBUF 0x1002 /* Receive buffer. */
+#define TARGET_SO_SNDLOWAT 0x1003 /* send low-water mark */
+#define TARGET_SO_RCVLOWAT 0x1004 /* receive low-water mark */
+#define TARGET_SO_SNDTIMEO 0x1005 /* send timeout */
+#define TARGET_SO_RCVTIMEO 0x1006 /* receive timeout */
+#define TARGET_SO_ACCEPTCONN 0x1009
+
+/* linux-specific, might as well be the same as on i386 */
+#define TARGET_SO_NO_CHECK 11
+#define TARGET_SO_PRIORITY 12
+#define TARGET_SO_BSDCOMPAT 14
+
+#define TARGET_SO_PASSCRED 17
+#define TARGET_SO_PEERCRED 18
+
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+#define TARGET_SO_SECURITY_AUTHENTICATION 22
+#define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 23
+#define TARGET_SO_SECURITY_ENCRYPTION_NETWORK 24
+
+#define TARGET_SO_BINDTODEVICE 25
+
+/* Socket filtering */
+#define TARGET_SO_ATTACH_FILTER 26
+#define TARGET_SO_DETACH_FILTER 27
+
+#define TARGET_SO_PEERNAME 28
+#define TARGET_SO_TIMESTAMP 29
+#define SCM_TIMESTAMP SO_TIMESTAMP
+
+#define TARGET_SO_PEERSEC 30
+#define TARGET_SO_SNDBUFFORCE 31
+#define TARGET_SO_RCVBUFFORCE 33
+#define TARGET_SO_PASSSEC 34
+
+/** sock_type - Socket types
+ *
+ * Please notice that for binary compat reasons MIPS has to
+ * override the enum sock_type in include/linux/net.h, so
+ * we define ARCH_HAS_SOCKET_TYPES here.
+ *
+ * @SOCK_DGRAM - datagram (conn.less) socket
+ * @SOCK_STREAM - stream (connection) socket
+ * @SOCK_RAW - raw socket
+ * @SOCK_RDM - reliably-delivered message
+ * @SOCK_SEQPACKET - sequential packet socket
+ * @SOCK_DCCP - Datagram Congestion Control Protocol socket
+ * @SOCK_PACKET - linux specific way of getting packets at the dev level.
+ * For writing rarp and other similar things on the user
+ * level.
+ * @SOCK_CLOEXEC - sets the close-on-exec (FD_CLOEXEC) flag.
+ * @SOCK_NONBLOCK - sets the O_NONBLOCK file status flag.
+ */
+
+#define TARGET_ARCH_HAS_SOCKET_TYPES 1
+
+enum sock_type {
+ TARGET_SOCK_DGRAM = 1,
+ TARGET_SOCK_STREAM = 2,
+ TARGET_SOCK_RAW = 3,
+ TARGET_SOCK_RDM = 4,
+ TARGET_SOCK_SEQPACKET = 5,
+ TARGET_SOCK_DCCP = 6,
+ TARGET_SOCK_PACKET = 10,
+};
+
+#define TARGET_SOCK_MAX (TARGET_SOCK_PACKET + 1)
+#define TARGET_SOCK_TYPE_MASK 0xf /* Covers up to TARGET_SOCK_MAX-1. */
+
+/* Flags for socket, socketpair, paccept */
+#define TARGET_SOCK_CLOEXEC TARGET_O_CLOEXEC
+#define TARGET_SOCK_NONBLOCK TARGET_O_NONBLOCK
+
+#endif
diff --git a/linux-user/mips64/sockbits.h b/linux-user/mips64/sockbits.h
new file mode 100644
index 0000000000..e6b6d31ac9
--- /dev/null
+++ b/linux-user/mips64/sockbits.h
@@ -0,0 +1 @@
+#include "../mips/sockbits.h"
diff --git a/linux-user/nios2/sockbits.h b/linux-user/nios2/sockbits.h
new file mode 100644
index 0000000000..0e4c8f012d
--- /dev/null
+++ b/linux-user/nios2/sockbits.h
@@ -0,0 +1 @@
+#include "../generic/sockbits.h"
diff --git a/linux-user/openrisc/sockbits.h b/linux-user/openrisc/sockbits.h
new file mode 100644
index 0000000000..0e4c8f012d
--- /dev/null
+++ b/linux-user/openrisc/sockbits.h
@@ -0,0 +1 @@
+#include "../generic/sockbits.h"
diff --git a/linux-user/ppc/sockbits.h b/linux-user/ppc/sockbits.h
new file mode 100644
index 0000000000..ee453347a3
--- /dev/null
+++ b/linux-user/ppc/sockbits.h
@@ -0,0 +1,26 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or (at your option) any
+ * later version. See the COPYING file in the top-level directory.
+ */
+
+#ifndef PPC_SOCKBITS_H
+#define PPC_SOCKBITS_H
+
+#include "../generic/sockbits.h"
+
+#undef TARGET_SO_RCVLOWAT
+#define TARGET_SO_RCVLOWAT 16
+#undef TARGET_SO_SNDLOWAT
+#define TARGET_SO_SNDLOWAT 17
+#undef TARGET_SO_RCVTIMEO
+#define TARGET_SO_RCVTIMEO 18
+#undef TARGET_SO_SNDTIMEO
+#define TARGET_SO_SNDTIMEO 19
+#undef TARGET_SO_PASSCRED
+#define TARGET_SO_PASSCRED 20
+#undef TARGET_SO_PEERCRED
+#define TARGET_SO_PEERCRED 21
+
+#endif
diff --git a/linux-user/riscv/sockbits.h b/linux-user/riscv/sockbits.h
new file mode 100644
index 0000000000..0e4c8f012d
--- /dev/null
+++ b/linux-user/riscv/sockbits.h
@@ -0,0 +1 @@
+#include "../generic/sockbits.h"
diff --git a/linux-user/s390x/sockbits.h b/linux-user/s390x/sockbits.h
new file mode 100644
index 0000000000..0e4c8f012d
--- /dev/null
+++ b/linux-user/s390x/sockbits.h
@@ -0,0 +1 @@
+#include "../generic/sockbits.h"
diff --git a/linux-user/sh4/sockbits.h b/linux-user/sh4/sockbits.h
new file mode 100644
index 0000000000..0e4c8f012d
--- /dev/null
+++ b/linux-user/sh4/sockbits.h
@@ -0,0 +1 @@
+#include "../generic/sockbits.h"
diff --git a/linux-user/socket.h b/linux-user/socket.h
index 7051cd2cf4..4c0b5c2dfa 100644
--- a/linux-user/socket.h
+++ b/linux-user/socket.h
@@ -1,342 +1,37 @@
-
-#if defined(TARGET_MIPS)
- /* MIPS special values for constants */
-
- /*
- * For setsockopt(2)
- *
- * This defines are ABI conformant as far as Linux supports these ...
- */
- #define TARGET_SOL_SOCKET 0xffff
-
- #define TARGET_SO_DEBUG 0x0001 /* Record debugging information. */
- #define TARGET_SO_REUSEADDR 0x0004 /* Allow reuse of local addresses. */
- #define TARGET_SO_KEEPALIVE 0x0008 /* Keep connections alive and send
- SIGPIPE when they die. */
- #define TARGET_SO_DONTROUTE 0x0010 /* Don't do local routing. */
- #define TARGET_SO_BROADCAST 0x0020 /* Allow transmission of
- broadcast messages. */
- #define TARGET_SO_LINGER 0x0080 /* Block on close of a reliable
- * socket to transmit pending data.
- */
- #define TARGET_SO_OOBINLINE 0x0100 /* Receive out-of-band data in-band.
- */
- #if 0
- /* To add: Allow local address and port reuse. */
- #define TARGET_SO_REUSEPORT 0x0200
- #endif
-
- #define TARGET_SO_TYPE 0x1008 /* Compatible name for SO_STYLE. */
- #define TARGET_SO_STYLE SO_TYPE /* Synonym */
- #define TARGET_SO_ERROR 0x1007 /* get error status and clear */
- #define TARGET_SO_SNDBUF 0x1001 /* Send buffer size. */
- #define TARGET_SO_RCVBUF 0x1002 /* Receive buffer. */
- #define TARGET_SO_SNDLOWAT 0x1003 /* send low-water mark */
- #define TARGET_SO_RCVLOWAT 0x1004 /* receive low-water mark */
- #define TARGET_SO_SNDTIMEO 0x1005 /* send timeout */
- #define TARGET_SO_RCVTIMEO 0x1006 /* receive timeout */
- #define TARGET_SO_ACCEPTCONN 0x1009
-
- /* linux-specific, might as well be the same as on i386 */
- #define TARGET_SO_NO_CHECK 11
- #define TARGET_SO_PRIORITY 12
- #define TARGET_SO_BSDCOMPAT 14
-
- #define TARGET_SO_PASSCRED 17
- #define TARGET_SO_PEERCRED 18
-
- /* Security levels - as per NRL IPv6 - don't actually do anything */
- #define TARGET_SO_SECURITY_AUTHENTICATION 22
- #define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 23
- #define TARGET_SO_SECURITY_ENCRYPTION_NETWORK 24
-
- #define TARGET_SO_BINDTODEVICE 25
-
- /* Socket filtering */
- #define TARGET_SO_ATTACH_FILTER 26
- #define TARGET_SO_DETACH_FILTER 27
-
- #define TARGET_SO_PEERNAME 28
- #define TARGET_SO_TIMESTAMP 29
- #define SCM_TIMESTAMP SO_TIMESTAMP
-
- #define TARGET_SO_PEERSEC 30
- #define TARGET_SO_SNDBUFFORCE 31
- #define TARGET_SO_RCVBUFFORCE 33
- #define TARGET_SO_PASSSEC 34
-
- /** sock_type - Socket types
- *
- * Please notice that for binary compat reasons MIPS has to
- * override the enum sock_type in include/linux/net.h, so
- * we define ARCH_HAS_SOCKET_TYPES here.
- *
- * @SOCK_DGRAM - datagram (conn.less) socket
- * @SOCK_STREAM - stream (connection) socket
- * @SOCK_RAW - raw socket
- * @SOCK_RDM - reliably-delivered message
- * @SOCK_SEQPACKET - sequential packet socket
- * @SOCK_DCCP - Datagram Congestion Control Protocol socket
- * @SOCK_PACKET - linux specific way of getting packets at the dev level.
- * For writing rarp and other similar things on the user
- * level.
- * @SOCK_CLOEXEC - sets the close-on-exec (FD_CLOEXEC) flag.
- * @SOCK_NONBLOCK - sets the O_NONBLOCK file status flag.
- */
-
- #define ARCH_HAS_SOCKET_TYPES 1
-
- enum sock_type {
- TARGET_SOCK_DGRAM = 1,
- TARGET_SOCK_STREAM = 2,
- TARGET_SOCK_RAW = 3,
- TARGET_SOCK_RDM = 4,
- TARGET_SOCK_SEQPACKET = 5,
- TARGET_SOCK_DCCP = 6,
- TARGET_SOCK_PACKET = 10,
- TARGET_SOCK_CLOEXEC = 02000000,
- TARGET_SOCK_NONBLOCK = 0200,
- };
-
- #define TARGET_SOCK_MAX (TARGET_SOCK_PACKET + 1)
- #define TARGET_SOCK_TYPE_MASK 0xf /* Covers up to TARGET_SOCK_MAX-1. */
-
-#elif defined(TARGET_ALPHA)
-
- /* For setsockopt(2) */
- #define TARGET_SOL_SOCKET 0xffff
-
- #define TARGET_SO_DEBUG 0x0001
- #define TARGET_SO_REUSEADDR 0x0004
- #define TARGET_SO_KEEPALIVE 0x0008
- #define TARGET_SO_DONTROUTE 0x0010
- #define TARGET_SO_BROADCAST 0x0020
- #define TARGET_SO_LINGER 0x0080
- #define TARGET_SO_OOBINLINE 0x0100
- /* To add :#define TARGET_SO_REUSEPORT 0x0200 */
-
- #define TARGET_SO_TYPE 0x1008
- #define TARGET_SO_ERROR 0x1007
- #define TARGET_SO_SNDBUF 0x1001
- #define TARGET_SO_RCVBUF 0x1002
- #define TARGET_SO_SNDBUFFORCE 0x100a
- #define TARGET_SO_RCVBUFFORCE 0x100b
- #define TARGET_SO_RCVLOWAT 0x1010
- #define TARGET_SO_SNDLOWAT 0x1011
- #define TARGET_SO_RCVTIMEO 0x1012
- #define TARGET_SO_SNDTIMEO 0x1013
- #define TARGET_SO_ACCEPTCONN 0x1014
- #define TARGET_SO_PROTOCOL 0x1028
- #define TARGET_SO_DOMAIN 0x1029
-
- /* linux-specific, might as well be the same as on i386 */
- #define TARGET_SO_NO_CHECK 11
- #define TARGET_SO_PRIORITY 12
- #define TARGET_SO_BSDCOMPAT 14
-
- #define TARGET_SO_PASSCRED 17
- #define TARGET_SO_PEERCRED 18
- #define TARGET_SO_BINDTODEVICE 25
-
- /* Socket filtering */
- #define TARGET_SO_ATTACH_FILTER 26
- #define TARGET_SO_DETACH_FILTER 27
-
- #define TARGET_SO_PEERNAME 28
- #define TARGET_SO_TIMESTAMP 29
- #define TARGET_SCM_TIMESTAMP TARGET_SO_TIMESTAMP
-
- #define TARGET_SO_PEERSEC 30
- #define TARGET_SO_PASSSEC 34
- #define TARGET_SO_TIMESTAMPNS 35
- #define TARGET_SCM_TIMESTAMPNS TARGET_SO_TIMESTAMPNS
-
- /* Security levels - as per NRL IPv6 - don't actually do anything */
- #define TARGET_SO_SECURITY_AUTHENTICATION 19
- #define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 20
- #define TARGET_SO_SECURITY_ENCRYPTION_NETWORK 21
-
- #define TARGET_SO_MARK 36
-
- #define TARGET_SO_TIMESTAMPING 37
- #define TARGET_SCM_TIMESTAMPING TARGET_SO_TIMESTAMPING
-
- #define TARGET_SO_RXQ_OVFL 40
-
- #define TARGET_SO_WIFI_STATUS 41
- #define TARGET_SCM_WIFI_STATUS TARGET_SO_WIFI_STATUS
- #define TARGET_SO_PEEK_OFF 42
-
- /* Instruct lower device to use last 4-bytes of skb data as FCS */
- #define TARGET_SO_NOFCS 43
-
- /** sock_type - Socket types
- *
- * Please notice that for binary compat reasons ALPHA has to
- * override the enum sock_type in include/linux/net.h, so
- * we define ARCH_HAS_SOCKET_TYPES here.
- *
- * @SOCK_DGRAM - datagram (conn.less) socket
- * @SOCK_STREAM - stream (connection) socket
- * @SOCK_RAW - raw socket
- * @SOCK_RDM - reliably-delivered message
- * @SOCK_SEQPACKET - sequential packet socket
- * @SOCK_DCCP - Datagram Congestion Control Protocol socket
- * @SOCK_PACKET - linux specific way of getting packets at the dev level.
- * For writing rarp and other similar things on the user
- * level.
- * @SOCK_CLOEXEC - sets the close-on-exec (FD_CLOEXEC) flag.
- * @SOCK_NONBLOCK - sets the O_NONBLOCK file status flag.
- */
-
- #define ARCH_HAS_SOCKET_TYPES 1
-
- enum sock_type {
- TARGET_SOCK_STREAM = 1,
- TARGET_SOCK_DGRAM = 2,
- TARGET_SOCK_RAW = 3,
- TARGET_SOCK_RDM = 4,
- TARGET_SOCK_SEQPACKET = 5,
- TARGET_SOCK_DCCP = 6,
- TARGET_SOCK_PACKET = 10,
- TARGET_SOCK_CLOEXEC = 010000000,
- TARGET_SOCK_NONBLOCK = 010000000000,
- };
-
- #define TARGET_SOCK_MAX (TARGET_SOCK_PACKET + 1)
- #define TARGET_SOCK_TYPE_MASK 0xf /* Covers up to TARGET_SOCK_MAX-1. */
-#elif defined(TARGET_HPPA)
-#include <hppa/sockbits.h>
-#else
-
-#if defined(TARGET_SPARC)
- /** sock_type - Socket types
- *
- * Please notice that for binary compat reasons SPARC has to
- * override the enum sock_type in include/linux/net.h, so
- * we define ARCH_HAS_SOCKET_TYPES here.
- *
- * @SOCK_DGRAM - datagram (conn.less) socket
- * @SOCK_STREAM - stream (connection) socket
- * @SOCK_RAW - raw socket
- * @SOCK_RDM - reliably-delivered message
- * @SOCK_SEQPACKET - sequential packet socket
- * @SOCK_DCCP - Datagram Congestion Control Protocol socket
- * @SOCK_PACKET - linux specific way of getting packets at the dev level.
- * For writing rarp and other similar things on the user
- * level.
- * @SOCK_CLOEXEC - sets the close-on-exec (FD_CLOEXEC) flag.
- * @SOCK_NONBLOCK - sets the O_NONBLOCK file status flag.
- */
-
- #define ARCH_HAS_SOCKET_TYPES 1
-
- enum sock_type {
- TARGET_SOCK_STREAM = 1,
- TARGET_SOCK_DGRAM = 2,
- TARGET_SOCK_RAW = 3,
- TARGET_SOCK_RDM = 4,
- TARGET_SOCK_SEQPACKET = 5,
- TARGET_SOCK_DCCP = 6,
- TARGET_SOCK_PACKET = 10,
- TARGET_SOCK_CLOEXEC = 020000000,
- TARGET_SOCK_NONBLOCK = 040000,
- };
-
- #define TARGET_SOCK_MAX (TARGET_SOCK_PACKET + 1)
- #define TARGET_SOCK_TYPE_MASK 0xf /* Covers up to TARGET_SOCK_MAX-1. */
-
- #define TARGET_SO_PASSSEC 31
-#else
- #define TARGET_SO_PASSSEC 34
-#endif
-
- /* For setsockopt(2) */
- #define TARGET_SOL_SOCKET 1
-
- #define TARGET_SO_DEBUG 1
- #define TARGET_SO_REUSEADDR 2
- #define TARGET_SO_TYPE 3
- #define TARGET_SO_ERROR 4
- #define TARGET_SO_DONTROUTE 5
- #define TARGET_SO_BROADCAST 6
- #define TARGET_SO_SNDBUF 7
- #define TARGET_SO_RCVBUF 8
- #define TARGET_SO_SNDBUFFORCE 32
- #define TARGET_SO_RCVBUFFORCE 33
- #define TARGET_SO_KEEPALIVE 9
- #define TARGET_SO_OOBINLINE 10
- #define TARGET_SO_NO_CHECK 11
- #define TARGET_SO_PRIORITY 12
- #define TARGET_SO_LINGER 13
- #define TARGET_SO_BSDCOMPAT 14
- /* To add :#define TARGET_SO_REUSEPORT 15 */
-#if defined(TARGET_PPC)
- #define TARGET_SO_RCVLOWAT 16
- #define TARGET_SO_SNDLOWAT 17
- #define TARGET_SO_RCVTIMEO 18
- #define TARGET_SO_SNDTIMEO 19
- #define TARGET_SO_PASSCRED 20
- #define TARGET_SO_PEERCRED 21
-#else
- #define TARGET_SO_PASSCRED 16
- #define TARGET_SO_PEERCRED 17
- #define TARGET_SO_RCVLOWAT 18
- #define TARGET_SO_SNDLOWAT 19
- #define TARGET_SO_RCVTIMEO 20
- #define TARGET_SO_SNDTIMEO 21
-#endif
-
- /* Security levels - as per NRL IPv6 - don't actually do anything */
- #define TARGET_SO_SECURITY_AUTHENTICATION 22
- #define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 23
- #define TARGET_SO_SECURITY_ENCRYPTION_NETWORK 24
-
- #define TARGET_SO_BINDTODEVICE 25
-
- /* Socket filtering */
- #define TARGET_SO_ATTACH_FILTER 26
- #define TARGET_SO_DETACH_FILTER 27
-
- #define TARGET_SO_PEERNAME 28
- #define TARGET_SO_TIMESTAMP 29
- #define TARGET_SCM_TIMESTAMP TARGET_SO_TIMESTAMP
-
- #define TARGET_SO_ACCEPTCONN 30
-
- #define TARGET_SO_PEERSEC 31
-
-#endif
-
-#ifndef ARCH_HAS_SOCKET_TYPES
- /** sock_type - Socket types - default values
- *
- *
- * @SOCK_STREAM - stream (connection) socket
- * @SOCK_DGRAM - datagram (conn.less) socket
- * @SOCK_RAW - raw socket
- * @SOCK_RDM - reliably-delivered message
- * @SOCK_SEQPACKET - sequential packet socket
- * @SOCK_DCCP - Datagram Congestion Control Protocol socket
- * @SOCK_PACKET - linux specific way of getting packets at the dev level.
- * For writing rarp and other similar things on the user
- * level.
- * @SOCK_CLOEXEC - sets the close-on-exec (FD_CLOEXEC) flag.
- * @SOCK_NONBLOCK - sets the O_NONBLOCK file status flag.
- */
- enum sock_type {
- TARGET_SOCK_STREAM = 1,
- TARGET_SOCK_DGRAM = 2,
- TARGET_SOCK_RAW = 3,
- TARGET_SOCK_RDM = 4,
- TARGET_SOCK_SEQPACKET = 5,
- TARGET_SOCK_DCCP = 6,
- TARGET_SOCK_PACKET = 10,
- TARGET_SOCK_CLOEXEC = 02000000,
- TARGET_SOCK_NONBLOCK = 04000,
- };
-
- #define TARGET_SOCK_MAX (TARGET_SOCK_PACKET + 1)
- #define TARGET_SOCK_TYPE_MASK 0xf /* Covers up to TARGET_SOCK_MAX-1. */
-
+#include "sockbits.h"
+
+#ifndef TARGET_ARCH_HAS_SOCKET_TYPES
+/** sock_type - Socket types - default values
+ *
+ *
+ * @SOCK_STREAM - stream (connection) socket
+ * @SOCK_DGRAM - datagram (conn.less) socket
+ * @SOCK_RAW - raw socket
+ * @SOCK_RDM - reliably-delivered message
+ * @SOCK_SEQPACKET - sequential packet socket
+ * @SOCK_DCCP - Datagram Congestion Control Protocol socket
+ * @SOCK_PACKET - linux specific way of getting packets at the dev level.
+ * For writing rarp and other similar things on the user
+ * level.
+ * @SOCK_CLOEXEC - sets the close-on-exec (FD_CLOEXEC) flag.
+ * @SOCK_NONBLOCK - sets the O_NONBLOCK file status flag.
+ */
+enum sock_type {
+ TARGET_SOCK_STREAM = 1,
+ TARGET_SOCK_DGRAM = 2,
+ TARGET_SOCK_RAW = 3,
+ TARGET_SOCK_RDM = 4,
+ TARGET_SOCK_SEQPACKET = 5,
+ TARGET_SOCK_DCCP = 6,
+ TARGET_SOCK_PACKET = 10,
+};
+
+#define TARGET_SOCK_MAX (TARGET_SOCK_PACKET + 1)
+#define TARGET_SOCK_TYPE_MASK 0xf /* Covers up to TARGET_SOCK_MAX-1. */
+
+/* Flags for socket, socketpair, accept4 */
+#define TARGET_SOCK_CLOEXEC TARGET_O_CLOEXEC
+#ifndef TARGET_SOCK_NONBLOCK
+#define TARGET_SOCK_NONBLOCK TARGET_O_NONBLOCK
#endif
+#endif /* TARGET_ARCH_HAS_SOCKET_TYPES */
diff --git a/linux-user/sparc/sockbits.h b/linux-user/sparc/sockbits.h
new file mode 100644
index 0000000000..0a822e3e1f
--- /dev/null
+++ b/linux-user/sparc/sockbits.h
@@ -0,0 +1,111 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or (at your option) any
+ * later version. See the COPYING file in the top-level directory.
+ */
+
+#ifndef SPARC_SOCKBITS_H
+#define SPARC_SOCKBITS_H
+
+/* For setsockopt(2) */
+#define TARGET_SOL_SOCKET 0xffff
+
+#define TARGET_SO_DEBUG 0x0001
+#define TARGET_SO_PASSCRED 0x0002
+#define TARGET_SO_REUSEADDR 0x0004
+#define TARGET_SO_KEEPALIVE 0x0008
+#define TARGET_SO_DONTROUTE 0x0010
+#define TARGET_SO_BROADCAST 0x0020
+#define TARGET_SO_PEERCRED 0x0040
+#define TARGET_SO_LINGER 0x0080
+#define TARGET_SO_OOBINLINE 0x0100
+#define TARGET_SO_REUSEPORT 0x0200
+#define TARGET_SO_BSDCOMPAT 0x0400
+#define TARGET_SO_RCVLOWAT 0x0800
+#define TARGET_SO_SNDLOWAT 0x1000
+#define TARGET_SO_RCVTIMEO 0x2000
+#define TARGET_SO_SNDTIMEO 0x4000
+#define TARGET_SO_ACCEPTCONN 0x8000
+
+#define TARGET_SO_SNDBUF 0x1001
+#define TARGET_SO_RCVBUF 0x1002
+#define TARGET_SO_SNDBUFFORCE 0x100a
+#define TARGET_SO_RCVBUFFORCE 0x100b
+#define TARGET_SO_ERROR 0x1007
+#define TARGET_SO_TYPE 0x1008
+#define TARGET_SO_PROTOCOL 0x1028
+#define TARGET_SO_DOMAIN 0x1029
+
+/* Linux specific, keep the same. */
+#define TARGET_SO_NO_CHECK 0x000b
+#define TARGET_SO_PRIORITY 0x000c
+
+#define TARGET_SO_BINDTODEVICE 0x000d
+
+#define TARGET_SO_ATTACH_FILTER 0x001a
+#define TARGET_SO_DETACH_FILTER 0x001b
+#define TARGET_SO_GET_FILTER TARGET_SO_ATTACH_FILTER
+
+#define TARGET_SO_PEERNAME 0x001c
+#define TARGET_SO_TIMESTAMP 0x001d
+#define TARGET_SCM_TIMESTAMP TARGET_SO_TIMESTAMP
+
+#define TARGET_SO_PEERSEC 0x001e
+#define TARGET_SO_PASSSEC 0x001f
+#define TARGET_SO_TIMESTAMPNS 0x0021
+#define TARGET_SCM_TIMESTAMPNS TARGET_SO_TIMESTAMPNS
+
+#define TARGET_SO_MARK 0x0022
+
+#define TARGET_SO_TIMESTAMPING 0x0023
+#define TARGET_SCM_TIMESTAMPING TARGET_SO_TIMESTAMPING
+
+#define TARGET_SO_RXQ_OVFL 0x0024
+
+#define TARGET_SO_WIFI_STATUS 0x0025
+#define TARGET_SCM_WIFI_STATUS TARGET_SO_WIFI_STATUS
+#define TARGET_SO_PEEK_OFF 0x0026
+
+/* Instruct lower device to use last 4-bytes of skb data as FCS */
+#define TARGET_SO_NOFCS 0x0027
+
+#define TARGET_SO_LOCK_FILTER 0x0028
+
+#define TARGET_SO_SELECT_ERR_QUEUE 0x0029
+
+#define TARGET_SO_BUSY_POLL 0x0030
+
+#define TARGET_SO_MAX_PACING_RATE 0x0031
+
+#define TARGET_SO_BPF_EXTENSIONS 0x0032
+
+#define TARGET_SO_INCOMING_CPU 0x0033
+
+#define TARGET_SO_ATTACH_BPF 0x0034
+#define TARGET_SO_DETACH_BPF TARGET_SO_DETACH_FILTER
+
+#define TARGET_SO_ATTACH_REUSEPORT_CBPF 0x0035
+#define TARGET_SO_ATTACH_REUSEPORT_EBPF 0x0036
+
+#define TARGET_SO_CNX_ADVICE 0x0037
+
+#define TARGET_SCM_TIMESTAMPING_OPT_STATS 0x0038
+
+#define TARGET_SO_MEMINFO 0x0039
+
+#define TARGET_SO_INCOMING_NAPI_ID 0x003a
+
+#define TARGET_SO_COOKIE 0x003b
+
+#define TARGET_SCM_TIMESTAMPING_PKTINFO 0x003c
+
+#define TARGET_SO_PEERGROUPS 0x003d
+
+#define TARGET_SO_ZEROCOPY 0x003e
+
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+#define TARGET_SO_SECURITY_AUTHENTICATION 0x5001
+#define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002
+#define TARGET_SO_SECURITY_ENCRYPTION_NETWORK 0x5004
+#endif
diff --git a/linux-user/sparc64/sockbits.h b/linux-user/sparc64/sockbits.h
new file mode 100644
index 0000000000..658899e4d3
--- /dev/null
+++ b/linux-user/sparc64/sockbits.h
@@ -0,0 +1 @@
+#include "../sparc/sockbits.h"
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index af8603f1b7..d02c16bbc6 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -405,6 +405,8 @@ enum {
QEMU_IFLA_BR_PAD,
QEMU_IFLA_BR_VLAN_STATS_ENABLED,
QEMU_IFLA_BR_MCAST_STATS_ENABLED,
+ QEMU_IFLA_BR_MCAST_IGMP_VERSION,
+ QEMU_IFLA_BR_MCAST_MLD_VERSION,
QEMU___IFLA_BR_MAX,
};
@@ -453,6 +455,12 @@ enum {
QEMU_IFLA_GSO_MAX_SIZE,
QEMU_IFLA_PAD,
QEMU_IFLA_XDP,
+ QEMU_IFLA_EVENT,
+ QEMU_IFLA_NEW_NETNSID,
+ QEMU_IFLA_IF_NETNSID,
+ QEMU_IFLA_CARRIER_UP_COUNT,
+ QEMU_IFLA_CARRIER_DOWN_COUNT,
+ QEMU_IFLA_NEW_IFINDEX,
QEMU___IFLA_MAX
};
@@ -484,6 +492,12 @@ enum {
QEMU_IFLA_BRPORT_FLUSH,
QEMU_IFLA_BRPORT_MULTICAST_ROUTER,
QEMU_IFLA_BRPORT_PAD,
+ QEMU_IFLA_BRPORT_MCAST_FLOOD,
+ QEMU_IFLA_BRPORT_MCAST_TO_UCAST,
+ QEMU_IFLA_BRPORT_VLAN_TUNNEL,
+ QEMU_IFLA_BRPORT_BCAST_FLOOD,
+ QEMU_IFLA_BRPORT_GROUP_FWD_MASK,
+ QEMU_IFLA_BRPORT_NEIGH_SUPPRESS,
QEMU___IFLA_BRPORT_MAX
};
@@ -516,6 +530,15 @@ enum {
QEMU___IFLA_INET6_MAX
};
+enum {
+ QEMU_IFLA_XDP_UNSPEC,
+ QEMU_IFLA_XDP_FD,
+ QEMU_IFLA_XDP_ATTACHED,
+ QEMU_IFLA_XDP_FLAGS,
+ QEMU_IFLA_XDP_PROG_ID,
+ QEMU___IFLA_XDP_MAX,
+};
+
typedef abi_long (*TargetFdDataFunc)(void *, size_t);
typedef abi_long (*TargetFdAddrFunc)(void *, abi_ulong, socklen_t);
typedef struct TargetFdTrans {
@@ -1825,6 +1848,7 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
/* Payload types which need a different size of payload on
* the target must adjust tgt_len here.
*/
+ tgt_len = len;
switch (cmsg->cmsg_level) {
case SOL_SOCKET:
switch (cmsg->cmsg_type) {
@@ -1834,8 +1858,8 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
default:
break;
}
+ break;
default:
- tgt_len = len;
break;
}
@@ -2182,6 +2206,10 @@ static abi_long host_to_target_data_bridge_nlattr(struct nlattr *nlattr,
case QEMU_IFLA_BR_NF_CALL_IPTABLES:
case QEMU_IFLA_BR_NF_CALL_IP6TABLES:
case QEMU_IFLA_BR_NF_CALL_ARPTABLES:
+ case QEMU_IFLA_BR_VLAN_STATS_ENABLED:
+ case QEMU_IFLA_BR_MCAST_STATS_ENABLED:
+ case QEMU_IFLA_BR_MCAST_IGMP_VERSION:
+ case QEMU_IFLA_BR_MCAST_MLD_VERSION:
break;
/* uint16_t */
case QEMU_IFLA_BR_PRIORITY:
@@ -2253,6 +2281,11 @@ static abi_long host_to_target_slave_data_bridge_nlattr(struct nlattr *nlattr,
case QEMU_IFLA_BRPORT_TOPOLOGY_CHANGE_ACK:
case QEMU_IFLA_BRPORT_CONFIG_PENDING:
case QEMU_IFLA_BRPORT_MULTICAST_ROUTER:
+ case QEMU_IFLA_BRPORT_MCAST_FLOOD:
+ case QEMU_IFLA_BRPORT_MCAST_TO_UCAST:
+ case QEMU_IFLA_BRPORT_VLAN_TUNNEL:
+ case QEMU_IFLA_BRPORT_BCAST_FLOOD:
+ case QEMU_IFLA_BRPORT_NEIGH_SUPPRESS:
break;
/* uint16_t */
case QEMU_IFLA_BRPORT_PRIORITY:
@@ -2260,6 +2293,7 @@ static abi_long host_to_target_slave_data_bridge_nlattr(struct nlattr *nlattr,
case QEMU_IFLA_BRPORT_DESIGNATED_COST:
case QEMU_IFLA_BRPORT_ID:
case QEMU_IFLA_BRPORT_NO:
+ case QEMU_IFLA_BRPORT_GROUP_FWD_MASK:
u16 = NLA_DATA(nlattr);
*u16 = tswap16(*u16);
break;
@@ -2434,6 +2468,27 @@ static abi_long host_to_target_data_spec_nlattr(struct nlattr *nlattr,
return 0;
}
+static abi_long host_to_target_data_xdp_nlattr(struct nlattr *nlattr,
+ void *context)
+{
+ uint32_t *u32;
+
+ switch (nlattr->nla_type) {
+ /* uint8_t */
+ case QEMU_IFLA_XDP_ATTACHED:
+ break;
+ /* uint32_t */
+ case QEMU_IFLA_XDP_PROG_ID:
+ u32 = NLA_DATA(nlattr);
+ *u32 = tswap32(*u32);
+ break;
+ default:
+ gemu_log("Unknown host XDP type: %d\n", nlattr->nla_type);
+ break;
+ }
+ return 0;
+}
+
static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr)
{
uint32_t *u32;
@@ -2559,6 +2614,10 @@ static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr)
return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len,
NULL,
host_to_target_data_spec_nlattr);
+ case QEMU_IFLA_XDP:
+ return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len,
+ NULL,
+ host_to_target_data_xdp_nlattr);
default:
gemu_log("Unknown host QEMU_IFLA type: %d\n", rtattr->rta_type);
break;
diff --git a/linux-user/tilegx/sockbits.h b/linux-user/tilegx/sockbits.h
new file mode 100644
index 0000000000..0e4c8f012d
--- /dev/null
+++ b/linux-user/tilegx/sockbits.h
@@ -0,0 +1 @@
+#include "../generic/sockbits.h"
diff --git a/linux-user/x86_64/sockbits.h b/linux-user/x86_64/sockbits.h
new file mode 100644
index 0000000000..0e4c8f012d
--- /dev/null
+++ b/linux-user/x86_64/sockbits.h
@@ -0,0 +1 @@
+#include "../generic/sockbits.h"
diff --git a/linux-user/xtensa/sockbits.h b/linux-user/xtensa/sockbits.h
new file mode 100644
index 0000000000..0e4c8f012d
--- /dev/null
+++ b/linux-user/xtensa/sockbits.h
@@ -0,0 +1 @@
+#include "../generic/sockbits.h"
diff --git a/memory.c b/memory.c
index fc7f9b782b..3212acc7f4 100644
--- a/memory.c
+++ b/memory.c
@@ -19,7 +19,6 @@
#include "cpu.h"
#include "exec/memory.h"
#include "exec/address-spaces.h"
-#include "exec/ioport.h"
#include "qapi/visitor.h"
#include "qemu/bitops.h"
#include "qemu/error-report.h"
@@ -173,38 +172,38 @@ struct MemoryRegionIoeventfd {
EventNotifier *e;
};
-static bool memory_region_ioeventfd_before(MemoryRegionIoeventfd a,
- MemoryRegionIoeventfd b)
+static bool memory_region_ioeventfd_before(MemoryRegionIoeventfd *a,
+ MemoryRegionIoeventfd *b)
{
- if (int128_lt(a.addr.start, b.addr.start)) {
+ if (int128_lt(a->addr.start, b->addr.start)) {
return true;
- } else if (int128_gt(a.addr.start, b.addr.start)) {
+ } else if (int128_gt(a->addr.start, b->addr.start)) {
return false;
- } else if (int128_lt(a.addr.size, b.addr.size)) {
+ } else if (int128_lt(a->addr.size, b->addr.size)) {
return true;
- } else if (int128_gt(a.addr.size, b.addr.size)) {
+ } else if (int128_gt(a->addr.size, b->addr.size)) {
return false;
- } else if (a.match_data < b.match_data) {
+ } else if (a->match_data < b->match_data) {
return true;
- } else if (a.match_data > b.match_data) {
+ } else if (a->match_data > b->match_data) {
return false;
- } else if (a.match_data) {
- if (a.data < b.data) {
+ } else if (a->match_data) {
+ if (a->data < b->data) {
return true;
- } else if (a.data > b.data) {
+ } else if (a->data > b->data) {
return false;
}
}
- if (a.e < b.e) {
+ if (a->e < b->e) {
return true;
- } else if (a.e > b.e) {
+ } else if (a->e > b->e) {
return false;
}
return false;
}
-static bool memory_region_ioeventfd_equal(MemoryRegionIoeventfd a,
- MemoryRegionIoeventfd b)
+static bool memory_region_ioeventfd_equal(MemoryRegionIoeventfd *a,
+ MemoryRegionIoeventfd *b)
{
return !memory_region_ioeventfd_before(a, b)
&& !memory_region_ioeventfd_before(b, a);
@@ -220,8 +219,6 @@ struct FlatRange {
bool readonly;
};
-typedef struct AddressSpaceOps AddressSpaceOps;
-
#define FOR_EACH_FLAT_RANGE(var, view) \
for (var = (view)->ranges; var < (view)->ranges + (view)->nr; ++var)
@@ -791,8 +788,8 @@ static void address_space_add_del_ioeventfds(AddressSpace *as,
while (iold < fds_old_nb || inew < fds_new_nb) {
if (iold < fds_old_nb
&& (inew == fds_new_nb
- || memory_region_ioeventfd_before(fds_old[iold],
- fds_new[inew]))) {
+ || memory_region_ioeventfd_before(&fds_old[iold],
+ &fds_new[inew]))) {
fd = &fds_old[iold];
section = (MemoryRegionSection) {
.fv = address_space_to_flatview(as),
@@ -804,8 +801,8 @@ static void address_space_add_del_ioeventfds(AddressSpace *as,
++iold;
} else if (inew < fds_new_nb
&& (iold == fds_old_nb
- || memory_region_ioeventfd_before(fds_new[inew],
- fds_old[iold]))) {
+ || memory_region_ioeventfd_before(&fds_new[inew],
+ &fds_old[iold]))) {
fd = &fds_new[inew];
section = (MemoryRegionSection) {
.fv = address_space_to_flatview(as),
@@ -1269,7 +1266,8 @@ static void unassigned_mem_write(void *opaque, hwaddr addr,
}
static bool unassigned_mem_accepts(void *opaque, hwaddr addr,
- unsigned size, bool is_write)
+ unsigned size, bool is_write,
+ MemTxAttrs attrs)
{
return false;
}
@@ -1347,7 +1345,8 @@ static const MemoryRegionOps ram_device_mem_ops = {
bool memory_region_access_valid(MemoryRegion *mr,
hwaddr addr,
unsigned size,
- bool is_write)
+ bool is_write,
+ MemTxAttrs attrs)
{
int access_size_min, access_size_max;
int access_size, i;
@@ -1373,7 +1372,7 @@ bool memory_region_access_valid(MemoryRegion *mr,
access_size = MAX(MIN(size, access_size_max), access_size_min);
for (i = 0; i < size; i += access_size) {
if (!mr->ops->valid.accepts(mr->opaque, addr + i, access_size,
- is_write)) {
+ is_write, attrs)) {
return false;
}
}
@@ -1416,7 +1415,7 @@ MemTxResult memory_region_dispatch_read(MemoryRegion *mr,
{
MemTxResult r;
- if (!memory_region_access_valid(mr, addr, size, false)) {
+ if (!memory_region_access_valid(mr, addr, size, false, attrs)) {
*pval = unassigned_mem_read(mr, addr, size);
return MEMTX_DECODE_ERROR;
}
@@ -1443,7 +1442,7 @@ static bool memory_region_dispatch_write_eventfds(MemoryRegion *mr,
ioeventfd.match_data = mr->ioeventfds[i].match_data;
ioeventfd.e = mr->ioeventfds[i].e;
- if (memory_region_ioeventfd_equal(ioeventfd, mr->ioeventfds[i])) {
+ if (memory_region_ioeventfd_equal(&ioeventfd, &mr->ioeventfds[i])) {
event_notifier_set(ioeventfd.e);
return true;
}
@@ -1458,7 +1457,7 @@ MemTxResult memory_region_dispatch_write(MemoryRegion *mr,
unsigned size,
MemTxAttrs attrs)
{
- if (!memory_region_access_valid(mr, addr, size, true)) {
+ if (!memory_region_access_valid(mr, addr, size, true, attrs)) {
unassigned_mem_write(mr, addr, data, size);
return MEMTX_DECODE_ERROR;
}
@@ -2213,7 +2212,7 @@ void memory_region_add_eventfd(MemoryRegion *mr,
}
memory_region_transaction_begin();
for (i = 0; i < mr->ioeventfd_nb; ++i) {
- if (memory_region_ioeventfd_before(mrfd, mr->ioeventfds[i])) {
+ if (memory_region_ioeventfd_before(&mrfd, &mr->ioeventfds[i])) {
break;
}
}
@@ -2248,7 +2247,7 @@ void memory_region_del_eventfd(MemoryRegion *mr,
}
memory_region_transaction_begin();
for (i = 0; i < mr->ioeventfd_nb; ++i) {
- if (memory_region_ioeventfd_equal(mrfd, mr->ioeventfds[i])) {
+ if (memory_region_ioeventfd_equal(&mrfd, &mr->ioeventfds[i])) {
break;
}
}
diff --git a/memory_ldst.inc.c b/memory_ldst.inc.c
index 25d6125747..15483987fe 100644
--- a/memory_ldst.inc.c
+++ b/memory_ldst.inc.c
@@ -33,7 +33,7 @@ static inline uint32_t glue(address_space_ldl_internal, SUFFIX)(ARG1_DECL,
bool release_lock = false;
RCU_READ_LOCK();
- mr = TRANSLATE(addr, &addr1, &l, false);
+ mr = TRANSLATE(addr, &addr1, &l, false, attrs);
if (l < 4 || !IS_DIRECT(mr, false)) {
release_lock |= prepare_mmio_access(mr);
@@ -109,7 +109,7 @@ static inline uint64_t glue(address_space_ldq_internal, SUFFIX)(ARG1_DECL,
bool release_lock = false;
RCU_READ_LOCK();
- mr = TRANSLATE(addr, &addr1, &l, false);
+ mr = TRANSLATE(addr, &addr1, &l, false, attrs);
if (l < 8 || !IS_DIRECT(mr, false)) {
release_lock |= prepare_mmio_access(mr);
@@ -183,7 +183,7 @@ uint32_t glue(address_space_ldub, SUFFIX)(ARG1_DECL,
bool release_lock = false;
RCU_READ_LOCK();
- mr = TRANSLATE(addr, &addr1, &l, false);
+ mr = TRANSLATE(addr, &addr1, &l, false, attrs);
if (!IS_DIRECT(mr, false)) {
release_lock |= prepare_mmio_access(mr);
@@ -219,7 +219,7 @@ static inline uint32_t glue(address_space_lduw_internal, SUFFIX)(ARG1_DECL,
bool release_lock = false;
RCU_READ_LOCK();
- mr = TRANSLATE(addr, &addr1, &l, false);
+ mr = TRANSLATE(addr, &addr1, &l, false, attrs);
if (l < 2 || !IS_DIRECT(mr, false)) {
release_lock |= prepare_mmio_access(mr);
@@ -296,7 +296,7 @@ void glue(address_space_stl_notdirty, SUFFIX)(ARG1_DECL,
bool release_lock = false;
RCU_READ_LOCK();
- mr = TRANSLATE(addr, &addr1, &l, true);
+ mr = TRANSLATE(addr, &addr1, &l, true, attrs);
if (l < 4 || !IS_DIRECT(mr, true)) {
release_lock |= prepare_mmio_access(mr);
@@ -333,7 +333,7 @@ static inline void glue(address_space_stl_internal, SUFFIX)(ARG1_DECL,
bool release_lock = false;
RCU_READ_LOCK();
- mr = TRANSLATE(addr, &addr1, &l, true);
+ mr = TRANSLATE(addr, &addr1, &l, true, attrs);
if (l < 4 || !IS_DIRECT(mr, true)) {
release_lock |= prepare_mmio_access(mr);
@@ -405,7 +405,7 @@ void glue(address_space_stb, SUFFIX)(ARG1_DECL,
bool release_lock = false;
RCU_READ_LOCK();
- mr = TRANSLATE(addr, &addr1, &l, true);
+ mr = TRANSLATE(addr, &addr1, &l, true, attrs);
if (!IS_DIRECT(mr, true)) {
release_lock |= prepare_mmio_access(mr);
r = memory_region_dispatch_write(mr, addr1, val, 1, attrs);
@@ -438,7 +438,7 @@ static inline void glue(address_space_stw_internal, SUFFIX)(ARG1_DECL,
bool release_lock = false;
RCU_READ_LOCK();
- mr = TRANSLATE(addr, &addr1, &l, true);
+ mr = TRANSLATE(addr, &addr1, &l, true, attrs);
if (l < 2 || !IS_DIRECT(mr, true)) {
release_lock |= prepare_mmio_access(mr);
@@ -511,7 +511,7 @@ static void glue(address_space_stq_internal, SUFFIX)(ARG1_DECL,
bool release_lock = false;
RCU_READ_LOCK();
- mr = TRANSLATE(addr, &addr1, &l, true);
+ mr = TRANSLATE(addr, &addr1, &l, true, attrs);
if (l < 8 || !IS_DIRECT(mr, true)) {
release_lock |= prepare_mmio_access(mr);
diff --git a/migration/exec.c b/migration/exec.c
index 9d0f82f1f0..0bbeb63c97 100644
--- a/migration/exec.c
+++ b/migration/exec.c
@@ -20,6 +20,7 @@
#include "qemu/osdep.h"
#include "channel.h"
#include "exec.h"
+#include "migration.h"
#include "io/channel-command.h"
#include "trace.h"
@@ -48,6 +49,9 @@ static gboolean exec_accept_incoming_migration(QIOChannel *ioc,
{
migration_channel_process_incoming(ioc);
object_unref(OBJECT(ioc));
+ if (!migrate_use_multifd()) {
+ migration_incoming_process();
+ }
return G_SOURCE_REMOVE;
}
diff --git a/migration/fd.c b/migration/fd.c
index 9a380bbbc4..fee34ffdc0 100644
--- a/migration/fd.c
+++ b/migration/fd.c
@@ -17,6 +17,7 @@
#include "qemu/osdep.h"
#include "channel.h"
#include "fd.h"
+#include "migration.h"
#include "monitor/monitor.h"
#include "io/channel-util.h"
#include "trace.h"
@@ -48,6 +49,9 @@ static gboolean fd_accept_incoming_migration(QIOChannel *ioc,
{
migration_channel_process_incoming(ioc);
object_unref(OBJECT(ioc));
+ if (!migrate_use_multifd()) {
+ migration_incoming_process();
+ }
return G_SOURCE_REMOVE;
}
diff --git a/migration/ram.c b/migration/ram.c
index e7d6cf6492..f4e29cadc6 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -246,7 +246,7 @@ int64_t ramblock_recv_bitmap_send(QEMUFile *file,
qemu_put_be64(file, RAMBLOCK_RECV_BITMAP_ENDING);
qemu_fflush(file);
- free(le_bitmap);
+ g_free(le_bitmap);
if (qemu_file_get_error(file)) {
return qemu_file_get_error(file);
@@ -3514,7 +3514,7 @@ int ram_dirty_bitmap_reload(MigrationState *s, RAMBlock *block)
ret = 0;
out:
- free(le_bitmap);
+ g_free(le_bitmap);
return ret;
}
diff --git a/migration/vmstate.c b/migration/vmstate.c
index 0a096360e2..6b9079bb51 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -136,6 +136,9 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
} else if (field->flags & VMS_STRUCT) {
ret = vmstate_load_state(f, field->vmsd, curr_elem,
field->vmsd->version_id);
+ } else if (field->flags & VMS_VSTRUCT) {
+ ret = vmstate_load_state(f, field->vmsd, curr_elem,
+ field->struct_version_id);
} else {
ret = field->info->get(f, curr_elem, size, field);
}
@@ -209,6 +212,8 @@ static const char *vmfield_get_type_name(VMStateField *field)
if (field->flags & VMS_STRUCT) {
type = "struct";
+ } else if (field->flags & VMS_VSTRUCT) {
+ type = "vstruct";
} else if (field->info->name) {
type = field->info->name;
}
@@ -309,7 +314,13 @@ bool vmstate_save_needed(const VMStateDescription *vmsd, void *opaque)
int vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
- void *opaque, QJSON *vmdesc)
+ void *opaque, QJSON *vmdesc_id)
+{
+ return vmstate_save_state_v(f, vmsd, opaque, vmdesc_id, vmsd->version_id);
+}
+
+int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
+ void *opaque, QJSON *vmdesc, int version_id)
{
int ret = 0;
VMStateField *field = vmsd->fields;
@@ -327,13 +338,15 @@ int vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
if (vmdesc) {
json_prop_str(vmdesc, "vmsd_name", vmsd->name);
- json_prop_int(vmdesc, "version", vmsd->version_id);
+ json_prop_int(vmdesc, "version", version_id);
json_start_array(vmdesc, "fields");
}
while (field->name) {
- if (!field->field_exists ||
- field->field_exists(opaque, vmsd->version_id)) {
+ if ((field->field_exists &&
+ field->field_exists(opaque, version_id)) ||
+ (!field->field_exists &&
+ field->version_id <= version_id)) {
void *first_elem = opaque + field->offset;
int i, n_elems = vmstate_n_elems(opaque, field);
int size = vmstate_size(opaque, field);
@@ -363,6 +376,10 @@ int vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
} else if (field->flags & VMS_STRUCT) {
ret = vmstate_save_state(f, field->vmsd, curr_elem,
vmdesc_loop);
+ } else if (field->flags & VMS_VSTRUCT) {
+ ret = vmstate_save_state_v(f, field->vmsd, curr_elem,
+ vmdesc_loop,
+ field->struct_version_id);
} else {
ret = field->info->put(f, curr_elem, size, field,
vmdesc_loop);
diff --git a/monitor.c b/monitor.c
index 46814af533..6d0cec552e 100644
--- a/monitor.c
+++ b/monitor.c
@@ -44,7 +44,6 @@
#include "qemu/readline.h"
#include "ui/console.h"
#include "ui/input.h"
-#include "sysemu/blockdev.h"
#include "sysemu/block-backend.h"
#include "audio/audio.h"
#include "disas/disas.h"
@@ -1179,8 +1178,7 @@ static void monitor_init_qmp_commands(void)
qmp_init_marshal(&qmp_commands);
qmp_register_command(&qmp_commands, "query-qmp-schema",
- qmp_query_qmp_schema,
- QCO_NO_OPTIONS);
+ qmp_query_qmp_schema, QCO_ALLOW_PRECONFIG);
qmp_register_command(&qmp_commands, "device_add", qmp_device_add,
QCO_NO_OPTIONS);
qmp_register_command(&qmp_commands, "netdev_add", qmp_netdev_add,
@@ -1190,7 +1188,7 @@ static void monitor_init_qmp_commands(void)
QTAILQ_INIT(&qmp_cap_negotiation_commands);
qmp_register_command(&qmp_cap_negotiation_commands, "qmp_capabilities",
- qmp_marshal_qmp_capabilities, QCO_NO_OPTIONS);
+ qmp_marshal_qmp_capabilities, QCO_ALLOW_PRECONFIG);
}
static bool qmp_cap_enabled(Monitor *mon, QMPCapability cap)
@@ -3371,6 +3369,12 @@ static void handle_hmp_command(Monitor *mon, const char *cmdline)
trace_handle_hmp_command(mon, cmdline);
+ if (runstate_check(RUN_STATE_PRECONFIG)) {
+ monitor_printf(mon, "HMP not available in preconfig state, "
+ "use QMP instead\n");
+ return;
+ }
+
cmd = monitor_parse_command(mon, cmdline, &cmdline, mon->cmd_table);
if (!cmd) {
return;
diff --git a/net/slirp.c b/net/slirp.c
index 692252445a..1e14318b4d 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -157,7 +157,8 @@ static int net_slirp_init(NetClientState *peer, const char *model,
const char *bootfile, const char *vdhcp_start,
const char *vnameserver, const char *vnameserver6,
const char *smb_export, const char *vsmbserver,
- const char **dnssearch, Error **errp)
+ const char **dnssearch, const char *vdomainname,
+ Error **errp)
{
/* default settings according to historic slirp */
struct in_addr net = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */
@@ -359,6 +360,11 @@ static int net_slirp_init(NetClientState *peer, const char *model,
ip6_dns.s6_addr[15] |= 3;
}
+ if (vdomainname && !*vdomainname) {
+ error_setg(errp, "'domainname' parameter cannot be empty");
+ return -1;
+ }
+
nc = qemu_new_net_client(&net_slirp_info, peer, model, name);
@@ -371,7 +377,7 @@ static int net_slirp_init(NetClientState *peer, const char *model,
s->slirp = slirp_init(restricted, ipv4, net, mask, host,
ipv6, ip6_prefix, vprefix6_len, ip6_host,
vhostname, tftp_export, bootfile, dhcp,
- dns, ip6_dns, dnssearch, s);
+ dns, ip6_dns, dnssearch, vdomainname, s);
QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);
for (config = slirp_configs; config; config = config->next) {
@@ -486,7 +492,9 @@ void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict)
goto fail_syntax;
}
- host_port = atoi(p);
+ if (qemu_strtoi(p, NULL, 10, &host_port)) {
+ goto fail_syntax;
+ }
err = slirp_remove_hostfwd(s->slirp, is_udp, host_addr, host_port);
@@ -958,7 +966,7 @@ int net_init_slirp(const Netdev *netdev, const char *name,
user->ipv6_host, user->hostname, user->tftp,
user->bootfile, user->dhcpstart,
user->dns, user->ipv6_dns, user->smb,
- user->smbserver, dnssearch, errp);
+ user->smbserver, dnssearch, user->domainname, errp);
while (slirp_configs) {
config = slirp_configs;
diff --git a/numa.c b/numa.c
index aac22a9612..33572bfa74 100644
--- a/numa.c
+++ b/numa.c
@@ -141,9 +141,8 @@ static void parse_numa_distance(NumaDistOptions *dist, Error **errp)
uint8_t val = dist->val;
if (src >= MAX_NODES || dst >= MAX_NODES) {
- error_setg(errp,
- "Invalid node %d, max possible could be %d",
- MAX(src, dst), MAX_NODES);
+ error_setg(errp, "Parameter '%s' expects an integer between 0 and %d",
+ src >= MAX_NODES ? "src" : "dst", MAX_NODES - 1);
return;
}
@@ -170,28 +169,11 @@ static void parse_numa_distance(NumaDistOptions *dist, Error **errp)
have_numa_distance = true;
}
-static int parse_numa(void *opaque, QemuOpts *opts, Error **errp)
+static
+void set_numa_options(MachineState *ms, NumaOptions *object, Error **errp)
{
- NumaOptions *object = NULL;
- MachineState *ms = opaque;
Error *err = NULL;
- {
- Visitor *v = opts_visitor_new(opts);
- visit_type_NumaOptions(v, NULL, &object, &err);
- visit_free(v);
- }
-
- if (err) {
- goto end;
- }
-
- /* Fix up legacy suffix-less format */
- if ((object->type == NUMA_OPTIONS_TYPE_NODE) && object->u.node.has_mem) {
- const char *mem_str = qemu_opt_get(opts, "mem");
- qemu_strtosz_MiB(mem_str, NULL, &object->u.node.mem);
- }
-
switch (object->type) {
case NUMA_OPTIONS_TYPE_NODE:
parse_numa_node(ms, &object->u.node, &err);
@@ -225,6 +207,31 @@ static int parse_numa(void *opaque, QemuOpts *opts, Error **errp)
}
end:
+ error_propagate(errp, err);
+}
+
+int parse_numa(void *opaque, QemuOpts *opts, Error **errp)
+{
+ NumaOptions *object = NULL;
+ MachineState *ms = MACHINE(opaque);
+ Error *err = NULL;
+ Visitor *v = opts_visitor_new(opts);
+
+ visit_type_NumaOptions(v, NULL, &object, &err);
+ visit_free(v);
+ if (err) {
+ goto end;
+ }
+
+ /* Fix up legacy suffix-less format */
+ if ((object->type == NUMA_OPTIONS_TYPE_NODE) && object->u.node.has_mem) {
+ const char *mem_str = qemu_opt_get(opts, "mem");
+ qemu_strtosz_MiB(mem_str, NULL, &object->u.node.mem);
+ }
+
+ set_numa_options(ms, object, &err);
+
+end:
qapi_free_NumaOptions(object);
if (err) {
error_report_err(err);
@@ -339,15 +346,11 @@ void numa_default_auto_assign_ram(MachineClass *mc, NodeInfo *nodes,
nodes[i].node_mem = size - usedmem;
}
-void parse_numa_opts(MachineState *ms)
+void numa_complete_configuration(MachineState *ms)
{
int i;
MachineClass *mc = MACHINE_GET_CLASS(ms);
- if (qemu_opts_foreach(qemu_find_opts("numa"), parse_numa, ms, NULL)) {
- exit(1);
- }
-
/*
* If memory hotplug is enabled (slots > 0) but without '-numa'
* options explicitly on CLI, guestes will break.
@@ -434,6 +437,24 @@ void parse_numa_opts(MachineState *ms)
}
}
+void parse_numa_opts(MachineState *ms)
+{
+ if (qemu_opts_foreach(qemu_find_opts("numa"), parse_numa, ms, NULL)) {
+ exit(1);
+ }
+}
+
+void qmp_set_numa_node(NumaOptions *cmd, Error **errp)
+{
+ if (!runstate_check(RUN_STATE_PRECONFIG)) {
+ error_setg(errp, "The command is permitted only in '%s' state",
+ RunState_str(RUN_STATE_PRECONFIG));
+ return;
+ }
+
+ set_numa_options(MACHINE(qdev_get_machine()), cmd, errp);
+}
+
void numa_cpu_pre_plug(const CPUArchId *slot, DeviceState *dev, Error **errp)
{
int node_id = object_property_get_int(OBJECT(dev), "node-id", &error_abort);
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 55728cb823..4b1de474a9 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -6,6 +6,7 @@
{ 'include': 'common.json' }
{ 'include': 'crypto.json' }
+{ 'include': 'job.json' }
{ 'include': 'sockets.json' }
##
@@ -1050,95 +1051,6 @@
'data': ['top', 'full', 'none', 'incremental'] }
##
-# @BlockJobType:
-#
-# Type of a block job.
-#
-# @commit: block commit job type, see "block-commit"
-#
-# @stream: block stream job type, see "block-stream"
-#
-# @mirror: drive mirror job type, see "drive-mirror"
-#
-# @backup: drive backup job type, see "drive-backup"
-#
-# Since: 1.7
-##
-{ 'enum': 'BlockJobType',
- 'data': ['commit', 'stream', 'mirror', 'backup'] }
-
-##
-# @BlockJobVerb:
-#
-# Represents command verbs that can be applied to a blockjob.
-#
-# @cancel: see @block-job-cancel
-#
-# @pause: see @block-job-pause
-#
-# @resume: see @block-job-resume
-#
-# @set-speed: see @block-job-set-speed
-#
-# @complete: see @block-job-complete
-#
-# @dismiss: see @block-job-dismiss
-#
-# @finalize: see @block-job-finalize
-#
-# Since: 2.12
-##
-{ 'enum': 'BlockJobVerb',
- 'data': ['cancel', 'pause', 'resume', 'set-speed', 'complete', 'dismiss',
- 'finalize' ] }
-
-##
-# @BlockJobStatus:
-#
-# Indicates the present state of a given blockjob in its lifetime.
-#
-# @undefined: Erroneous, default state. Should not ever be visible.
-#
-# @created: The job has been created, but not yet started.
-#
-# @running: The job is currently running.
-#
-# @paused: The job is running, but paused. The pause may be requested by
-# either the QMP user or by internal processes.
-#
-# @ready: The job is running, but is ready for the user to signal completion.
-# This is used for long-running jobs like mirror that are designed to
-# run indefinitely.
-#
-# @standby: The job is ready, but paused. This is nearly identical to @paused.
-# The job may return to @ready or otherwise be canceled.
-#
-# @waiting: The job is waiting for other jobs in the transaction to converge
-# to the waiting state. This status will likely not be visible for
-# the last job in a transaction.
-#
-# @pending: The job has finished its work, but has finalization steps that it
-# needs to make prior to completing. These changes may require
-# manual intervention by the management process if manual was set
-# to true. These changes may still fail.
-#
-# @aborting: The job is in the process of being aborted, and will finish with
-# an error. The job will afterwards report that it is @concluded.
-# This status may not be visible to the management process.
-#
-# @concluded: The job has finished all work. If manual was set to true, the job
-# will remain in the query list until it is dismissed.
-#
-# @null: The job is in the process of being dismantled. This state should not
-# ever be visible externally.
-#
-# Since: 2.12
-##
-{ 'enum': 'BlockJobStatus',
- 'data': ['undefined', 'created', 'running', 'paused', 'ready', 'standby',
- 'waiting', 'pending', 'aborting', 'concluded', 'null' ] }
-
-##
# @BlockJobInfo:
#
# Information about a long-running block device operation.
@@ -1148,7 +1060,12 @@
# @device: The job identifier. Originally the device name but other
# values are allowed since QEMU 2.7
#
-# @len: the maximum progress value
+# @len: Estimated @offset value at the completion of the job. This value can
+# arbitrarily change while the job is running, in both directions.
+#
+# @offset: Progress made until now. The unit is arbitrary and the value can
+# only meaningfully be used for the ratio of @offset to @len. The
+# value is monotonically increasing.
#
# @busy: false if the job is known to be in a quiescent state, with
# no pending I/O. Since 1.3.
@@ -1156,8 +1073,6 @@
# @paused: whether the job is paused or, if @busy is true, will
# pause itself as soon as possible. Since 1.3.
#
-# @offset: the current progress value
-#
# @speed: the rate limit, bytes per second
#
# @io-status: the status of the job (since 1.3)
@@ -1181,7 +1096,7 @@
'data': {'type': 'str', 'device': 'str', 'len': 'int',
'offset': 'int', 'busy': 'bool', 'paused': 'bool', 'speed': 'int',
'io-status': 'BlockDeviceIoStatus', 'ready': 'bool',
- 'status': 'BlockJobStatus',
+ 'status': 'JobStatus',
'auto-finalize': 'bool', 'auto-dismiss': 'bool',
'*error': 'str' } }
@@ -2338,8 +2253,7 @@
#
# This command returns immediately after marking the active background block
# operation for pausing. It is an error to call this command if no
-# operation is in progress. Pausing an already paused job has no cumulative
-# effect; a single block-job-resume command will resume the job.
+# operation is in progress or if the job is already paused.
#
# The operation will pause as soon as possible. No event is emitted when
# the operation is actually paused. Cancelling a paused job automatically
@@ -2363,7 +2277,7 @@
#
# This command returns immediately after resuming a paused background block
# operation. It is an error to call this command if no operation is in
-# progress. Resuming an already running job is not an error.
+# progress or if the job is not paused.
#
# This command also clears the error status of the job.
#
@@ -2414,7 +2328,7 @@
# QEMU 2.12+ job lifetime management semantics.
#
# This command will refuse to operate on any job that has not yet reached
-# its terminal state, BLOCK_JOB_STATUS_CONCLUDED. For jobs that make use of
+# its terminal state, JOB_STATUS_CONCLUDED. For jobs that make use of the
# BLOCK_JOB_READY event, block-job-cancel or block-job-complete will still need
# to be used as appropriate.
#
@@ -2510,7 +2424,7 @@
# @vxhs: Since 2.10
# @throttle: Since 2.11
# @nvme: Since 2.12
-# @copy-on-read: Since 2.13
+# @copy-on-read: Since 3.0
#
# Since: 2.9
##
@@ -2538,7 +2452,7 @@
# @x-check-cache-dropped: whether to check that page cache was dropped on live
# migration. May cause noticeable delays if the image
# file is large, do not use in production.
-# (default: off) (since: 2.13)
+# (default: off) (since: 3.0)
#
# Since: 2.9
##
@@ -4097,16 +4011,20 @@
} }
##
-# @x-blockdev-create:
+# @blockdev-create:
#
-# Create an image format on a given node.
-# TODO Replace with something asynchronous (block job?)
+# Starts a job to create an image format on a given node. The job is
+# automatically finalized, but a manual job-dismiss is required.
#
-# Since: 2.12
+# @job-id: Identifier for the newly created job.
+#
+# @options: Options for the image creation.
+#
+# Since: 3.0
##
-{ 'command': 'x-blockdev-create',
- 'data': 'BlockdevCreateOptions',
- 'boxed': true }
+{ 'command': 'blockdev-create',
+ 'data': { 'job-id': 'str',
+ 'options': 'BlockdevCreateOptions' } }
##
# @blockdev-open-tray:
@@ -4497,7 +4415,7 @@
#
##
{ 'event': 'BLOCK_JOB_COMPLETED',
- 'data': { 'type' : 'BlockJobType',
+ 'data': { 'type' : 'JobType',
'device': 'str',
'len' : 'int',
'offset': 'int',
@@ -4533,7 +4451,7 @@
#
##
{ 'event': 'BLOCK_JOB_CANCELLED',
- 'data': { 'type' : 'BlockJobType',
+ 'data': { 'type' : 'JobType',
'device': 'str',
'len' : 'int',
'offset': 'int',
@@ -4598,7 +4516,7 @@
#
##
{ 'event': 'BLOCK_JOB_READY',
- 'data': { 'type' : 'BlockJobType',
+ 'data': { 'type' : 'JobType',
'device': 'str',
'len' : 'int',
'offset': 'int',
@@ -4625,7 +4543,7 @@
#
##
{ 'event': 'BLOCK_JOB_PENDING',
- 'data': { 'type' : 'BlockJobType',
+ 'data': { 'type' : 'JobType',
'id' : 'str' } }
##
diff --git a/qapi/common.json b/qapi/common.json
index c811d04984..c367adc4b6 100644
--- a/qapi/common.json
+++ b/qapi/common.json
@@ -140,7 +140,7 @@
# prefix to produce the corresponding QEMU executable name. This
# is true even for "qemu-system-x86_64".
#
-# Since: 2.13
+# Since: 3.0
##
{ 'enum' : 'SysEmuTarget',
'data' : [ 'aarch64', 'alpha', 'arm', 'cris', 'hppa', 'i386', 'lm32',
diff --git a/qapi/introspect.json b/qapi/introspect.json
index c7f67b7d78..80a0a3e656 100644
--- a/qapi/introspect.json
+++ b/qapi/introspect.json
@@ -262,13 +262,16 @@
# @allow-oob: whether the command allows out-of-band execution.
# (Since: 2.12)
#
+# @allow-preconfig: command can be executed in preconfig runstate,
+# default: false (Since 3.0)
+#
# TODO: @success-response (currently irrelevant, because it's QGA, not QMP)
#
# Since: 2.5
##
{ 'struct': 'SchemaInfoCommand',
'data': { 'arg-type': 'str', 'ret-type': 'str',
- 'allow-oob': 'bool' } }
+ 'allow-oob': 'bool', 'allow-preconfig': 'bool' } }
##
# @SchemaInfoEvent:
diff --git a/qapi/job.json b/qapi/job.json
new file mode 100644
index 0000000000..17d10037c4
--- /dev/null
+++ b/qapi/job.json
@@ -0,0 +1,255 @@
+# -*- Mode: Python -*-
+
+##
+# == Background jobs
+##
+
+##
+# @JobType:
+#
+# Type of a background job.
+#
+# @commit: block commit job type, see "block-commit"
+#
+# @stream: block stream job type, see "block-stream"
+#
+# @mirror: drive mirror job type, see "drive-mirror"
+#
+# @backup: drive backup job type, see "drive-backup"
+#
+# @create: image creation job type, see "blockdev-create" (since 3.0)
+#
+# Since: 1.7
+##
+{ 'enum': 'JobType',
+ 'data': ['commit', 'stream', 'mirror', 'backup', 'create'] }
+
+##
+# @JobStatus:
+#
+# Indicates the present state of a given job in its lifetime.
+#
+# @undefined: Erroneous, default state. Should not ever be visible.
+#
+# @created: The job has been created, but not yet started.
+#
+# @running: The job is currently running.
+#
+# @paused: The job is running, but paused. The pause may be requested by
+# either the QMP user or by internal processes.
+#
+# @ready: The job is running, but is ready for the user to signal completion.
+# This is used for long-running jobs like mirror that are designed to
+# run indefinitely.
+#
+# @standby: The job is ready, but paused. This is nearly identical to @paused.
+# The job may return to @ready or otherwise be canceled.
+#
+# @waiting: The job is waiting for other jobs in the transaction to converge
+# to the waiting state. This status will likely not be visible for
+# the last job in a transaction.
+#
+# @pending: The job has finished its work, but has finalization steps that it
+# needs to make prior to completing. These changes may require
+# manual intervention by the management process if manual was set
+# to true. These changes may still fail.
+#
+# @aborting: The job is in the process of being aborted, and will finish with
+# an error. The job will afterwards report that it is @concluded.
+# This status may not be visible to the management process.
+#
+# @concluded: The job has finished all work. If manual was set to true, the job
+# will remain in the query list until it is dismissed.
+#
+# @null: The job is in the process of being dismantled. This state should not
+# ever be visible externally.
+#
+# Since: 2.12
+##
+{ 'enum': 'JobStatus',
+ 'data': ['undefined', 'created', 'running', 'paused', 'ready', 'standby',
+ 'waiting', 'pending', 'aborting', 'concluded', 'null' ] }
+
+##
+# @JobVerb:
+#
+# Represents command verbs that can be applied to a job.
+#
+# @cancel: see @block-job-cancel
+#
+# @pause: see @block-job-pause
+#
+# @resume: see @block-job-resume
+#
+# @set-speed: see @block-job-set-speed
+#
+# @complete: see @block-job-complete
+#
+# @dismiss: see @block-job-dismiss
+#
+# @finalize: see @block-job-finalize
+#
+# Since: 2.12
+##
+{ 'enum': 'JobVerb',
+ 'data': ['cancel', 'pause', 'resume', 'set-speed', 'complete', 'dismiss',
+ 'finalize' ] }
+
+##
+# @JOB_STATUS_CHANGE:
+#
+# Emitted when a job transitions to a different status.
+#
+# @id: The job identifier
+# @status: The new job status
+#
+# Since: 2.13
+##
+{ 'event': 'JOB_STATUS_CHANGE',
+ 'data': { 'id': 'str',
+ 'status': 'JobStatus' } }
+
+##
+# @job-pause:
+#
+# Pause an active job.
+#
+# This command returns immediately after marking the active job for pausing.
+# Pausing an already paused job is an error.
+#
+# The job will pause as soon as possible, which means transitioning into the
+# PAUSED state if it was RUNNING, or into STANDBY if it was READY. The
+# corresponding JOB_STATUS_CHANGE event will be emitted.
+#
+# Cancelling a paused job automatically resumes it.
+#
+# @id: The job identifier.
+#
+# Since: 2.13
+##
+{ 'command': 'job-pause', 'data': { 'id': 'str' } }
+
+##
+# @job-resume:
+#
+# Resume a paused job.
+#
+# This command returns immediately after resuming a paused job. Resuming an
+# already running job is an error.
+#
+# @id : The job identifier.
+#
+# Since: 2.13
+##
+{ 'command': 'job-resume', 'data': { 'id': 'str' } }
+
+##
+# @job-cancel:
+#
+# Instruct an active background job to cancel at the next opportunity.
+# This command returns immediately after marking the active job for
+# cancellation.
+#
+# The job will cancel as soon as possible and then emit a JOB_STATUS_CHANGE
+# event. Usually, the status will change to ABORTING, but it is possible that
+# a job successfully completes (e.g. because it was almost done and there was
+# no opportunity to cancel earlier than completing the job) and transitions to
+# PENDING instead.
+#
+# @id: The job identifier.
+#
+# Since: 2.13
+##
+{ 'command': 'job-cancel', 'data': { 'id': 'str' } }
+
+
+##
+# @job-complete:
+#
+# Manually trigger completion of an active job in the READY state.
+#
+# @id: The job identifier.
+#
+# Since: 2.13
+##
+{ 'command': 'job-complete', 'data': { 'id': 'str' } }
+
+##
+# @job-dismiss:
+#
+# Deletes a job that is in the CONCLUDED state. This command only needs to be
+# run explicitly for jobs that don't have automatic dismiss enabled.
+#
+# This command will refuse to operate on any job that has not yet reached its
+# terminal state, JOB_STATUS_CONCLUDED. For jobs that make use of JOB_READY
+# event, job-cancel or job-complete will still need to be used as appropriate.
+#
+# @id: The job identifier.
+#
+# Since: 2.13
+##
+{ 'command': 'job-dismiss', 'data': { 'id': 'str' } }
+
+##
+# @job-finalize:
+#
+# Instructs all jobs in a transaction (or a single job if it is not part of any
+# transaction) to finalize any graph changes and do any necessary cleanup. This
+# command requires that all involved jobs are in the PENDING state.
+#
+# For jobs in a transaction, instructing one job to finalize will force
+# ALL jobs in the transaction to finalize, so it is only necessary to instruct
+# a single member job to finalize.
+#
+# @id: The identifier of any job in the transaction, or of a job that is not
+# part of any transaction.
+#
+# Since: 2.13
+##
+{ 'command': 'job-finalize', 'data': { 'id': 'str' } }
+
+##
+# @JobInfo:
+#
+# Information about a job.
+#
+# @id: The job identifier
+#
+# @type: The kind of job that is being performed
+#
+# @status: Current job state/status
+#
+# @current-progress: Progress made until now. The unit is arbitrary and the
+# value can only meaningfully be used for the ratio of
+# @current-progress to @total-progress. The value is
+# monotonically increasing.
+#
+# @total-progress: Estimated @current-progress value at the completion of
+# the job. This value can arbitrarily change while the
+# job is running, in both directions.
+#
+# @error: If this field is present, the job failed; if it is
+# still missing in the CONCLUDED state, this indicates
+# successful completion.
+#
+# The value is a human-readable error message to describe
+# the reason for the job failure. It should not be parsed
+# by applications.
+#
+# Since: 2.13
+##
+{ 'struct': 'JobInfo',
+ 'data': { 'id': 'str', 'type': 'JobType', 'status': 'JobStatus',
+ 'current-progress': 'int', 'total-progress': 'int',
+ '*error': 'str' } }
+
+##
+# @query-jobs:
+#
+# Return information about jobs.
+#
+# Returns: a list with a @JobInfo for each active job
+#
+# Since: 2.13
+##
+{ 'command': 'query-jobs', 'returns': ['JobInfo'] }
diff --git a/qapi/migration.json b/qapi/migration.json
index 3ec418dabf..dc9cc85545 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -89,9 +89,9 @@
#
# @postcopy-active: like active, but now in postcopy mode. (since 2.5)
#
-# @postcopy-paused: during postcopy but paused. (since 2.13)
+# @postcopy-paused: during postcopy but paused. (since 3.0)
#
-# @postcopy-recover: trying to recover from a paused postcopy. (since 2.13)
+# @postcopy-recover: trying to recover from a paused postcopy. (since 3.0)
#
# @completed: migration is finished.
#
@@ -163,11 +163,11 @@
#
# @postcopy-blocktime: total time when all vCPU were blocked during postcopy
# live migration. This is only present when the postcopy-blocktime
-# migration capability is enabled. (Since 2.13)
+# migration capability is enabled. (Since 3.0)
#
# @postcopy-vcpu-blocktime: list of the postcopy blocktime per vCPU. This is
# only present when the postcopy-blocktime migration capability
-# is enabled. (Since 2.13)
+# is enabled. (Since 3.0)
#
#
# Since: 0.14.0
@@ -374,7 +374,7 @@
# (since 2.12)
#
# @postcopy-blocktime: Calculate downtime for postcopy live migration
-# (since 2.13)
+# (since 3.0)
#
# Since: 1.2
##
@@ -1034,7 +1034,7 @@
# @detach: this argument exists only for compatibility reasons and
# is ignored by QEMU
#
-# @resume: resume one paused migration, default "off". (since 2.13)
+# @resume: resume one paused migration, default "off". (since 3.0)
#
# Returns: nothing on success
#
@@ -1208,7 +1208,7 @@
# "arguments": { "uri": "tcp:192.168.1.200:12345" } }
# <- { "return": {} }
#
-# Since: 2.13
+# Since: 3.0
##
{ 'command': 'migrate-recover', 'data': { 'uri': 'str' },
'allow-oob': true }
@@ -1225,6 +1225,6 @@
# -> { "execute": "migrate-pause" }
# <- { "return": {} }
#
-# Since: 2.13
+# Since: 3.0
##
{ 'command': 'migrate-pause', 'allow-oob': true }
diff --git a/qapi/misc.json b/qapi/misc.json
index f5988cc0b5..f83a63a0ab 100644
--- a/qapi/misc.json
+++ b/qapi/misc.json
@@ -37,7 +37,8 @@
#
##
{ 'command': 'qmp_capabilities',
- 'data': { '*enable': [ 'QMPCapability' ] } }
+ 'data': { '*enable': [ 'QMPCapability' ] },
+ 'allow-preconfig': true }
##
# @QMPCapability:
@@ -155,7 +156,8 @@
# Note: This example has been shortened as the real response is too long.
#
##
-{ 'command': 'query-commands', 'returns': ['CommandInfo'] }
+{ 'command': 'query-commands', 'returns': ['CommandInfo'],
+ 'allow-preconfig': true }
##
# @LostTickPolicy:
@@ -558,11 +560,11 @@
# @props: properties describing to which node/socket/core/thread
# virtual CPU belongs to, provided if supported by board
#
-# @arch: base architecture of the cpu; deprecated since 2.13.0 in favor
+# @arch: base architecture of the cpu; deprecated since 3.0.0 in favor
# of @target
#
# @target: the QEMU system emulation target, which determines which
-# additional fields will be listed (since 2.13)
+# additional fields will be listed (since 3.0)
#
# Since: 2.12
#
@@ -1243,6 +1245,29 @@
{ 'command': 'cont' }
##
+# @exit-preconfig:
+#
+# Exit from "preconfig" state
+#
+# This command makes QEMU exit the preconfig state and proceed with
+# VM initialization using configuration data provided on the command line
+# and via the QMP monitor during the preconfig state. The command is only
+# available during the preconfig state (i.e. when the --preconfig command
+# line option was in use).
+#
+# Since 3.0
+#
+# Returns: nothing
+#
+# Example:
+#
+# -> { "execute": "exit-preconfig" }
+# <- { "return": {} }
+#
+##
+{ 'command': 'exit-preconfig', 'allow-preconfig': true }
+
+##
# @system_wakeup:
#
# Wakeup guest from suspend. Does nothing in case the guest isn't suspended.
@@ -1529,6 +1554,10 @@
#
# Returns: a list of ObjectPropertyInfo describing a devices properties
#
+# Note: objects can create properties at runtime, for example to describe
+# links between different devices and/or objects. These properties
+# are not included in the output of this command.
+#
# Since: 1.2
##
{ 'command': 'device-list-properties',
@@ -1542,6 +1571,10 @@
#
# @typename: the type name of an object
#
+# Note: objects can create properties at runtime, for example to describe
+# links between different devices and/or objects. These properties
+# are not included in the output of this command.
+#
# Returns: a list of ObjectPropertyInfo describing object properties
#
# Since: 2.12
@@ -2648,7 +2681,8 @@
#
##
{'command': 'query-command-line-options', 'data': { '*option': 'str' },
- 'returns': ['CommandLineOptionInfo'] }
+ 'returns': ['CommandLineOptionInfo'],
+ 'allow-preconfig': true }
##
# @X86CPURegister32:
@@ -3259,7 +3293,8 @@
# ]}
#
##
-{ 'command': 'query-hotpluggable-cpus', 'returns': ['HotpluggableCPU'] }
+{ 'command': 'query-hotpluggable-cpus', 'returns': ['HotpluggableCPU'],
+ 'allow-preconfig': true }
##
# @GuidInfo:
@@ -3483,3 +3518,17 @@
##
{ 'command': 'x-oob-test', 'data' : { 'lock': 'bool' },
'allow-oob': true }
+
+##
+# @set-numa-node:
+#
+# Runtime equivalent of '-numa' CLI option, available at
+# preconfigure stage to configure numa mapping before initializing
+# machine.
+#
+# Since 3.0
+##
+{ 'command': 'set-numa-node', 'boxed': true,
+ 'data': 'NumaOptions',
+ 'allow-preconfig': true
+}
diff --git a/qapi/net.json b/qapi/net.json
index b8adf1f03f..32681a1af7 100644
--- a/qapi/net.json
+++ b/qapi/net.json
@@ -160,6 +160,9 @@
# @dnssearch: list of DNS suffixes to search, passed as DHCP option
# to the guest
#
+# @domainname: guest-visible domain name of the virtual nameserver
+# (since 2.12)
+#
# @ipv6-prefix: IPv6 network prefix (default is fec0::) (since
# 2.6). The network prefix is given in the usual
# hexadecimal IPv6 address notation.
@@ -197,6 +200,7 @@
'*dhcpstart': 'str',
'*dns': 'str',
'*dnssearch': ['String'],
+ '*domainname': 'str',
'*ipv6-prefix': 'str',
'*ipv6-prefixlen': 'int',
'*ipv6-host': 'str',
@@ -498,7 +502,7 @@
#
# Since: 1.2
#
-# 'vlan': dropped in 2.13
+# 'vlan': dropped in 3.0
##
{ 'struct': 'NetLegacy',
'data': {
diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json
index 25bce78352..65b6dc2f6f 100644
--- a/qapi/qapi-schema.json
+++ b/qapi/qapi-schema.json
@@ -84,6 +84,7 @@
{ 'include': 'crypto.json' }
{ 'include': 'block.json' }
{ 'include': 'char.json' }
+{ 'include': 'job.json' }
{ 'include': 'net.json' }
{ 'include': 'rocker.json' }
{ 'include': 'tpm.json' }
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index f9377b27fd..935f9e159c 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -18,6 +18,7 @@
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qjson.h"
#include "qapi/qmp/qbool.h"
+#include "sysemu/sysemu.h"
QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp)
{
@@ -101,6 +102,13 @@ static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request,
return NULL;
}
+ if (runstate_check(RUN_STATE_PRECONFIG) &&
+ !(cmd->options & QCO_ALLOW_PRECONFIG)) {
+ error_setg(errp, "The command '%s' isn't permitted in '%s' state",
+ cmd->name, RunState_str(RUN_STATE_PRECONFIG));
+ return NULL;
+ }
+
if (!qdict_haskey(dict, "arguments")) {
args = qdict_new();
} else {
diff --git a/qapi/run-state.json b/qapi/run-state.json
index 1c9fff3aef..332e44897b 100644
--- a/qapi/run-state.json
+++ b/qapi/run-state.json
@@ -49,12 +49,15 @@
# @colo: guest is paused to save/restore VM state under colo checkpoint,
# VM can not get into this state unless colo capability is enabled
# for migration. (since 2.8)
+# @preconfig: QEMU is paused before board specific init callback is executed.
+# The state is reachable only if the --preconfig CLI option is used.
+# (Since 3.0)
##
{ 'enum': 'RunState',
'data': [ 'debug', 'inmigrate', 'internal-error', 'io-error', 'paused',
'postmigrate', 'prelaunch', 'finish-migrate', 'restore-vm',
'running', 'save-vm', 'shutdown', 'suspended', 'watchdog',
- 'guest-panicked', 'colo' ] }
+ 'guest-panicked', 'colo', 'preconfig' ] }
##
# @StatusInfo:
@@ -91,7 +94,8 @@
# "status": "running" } }
#
##
-{ 'command': 'query-status', 'returns': 'StatusInfo' }
+{ 'command': 'query-status', 'returns': 'StatusInfo',
+ 'allow-preconfig': true }
##
# @SHUTDOWN:
diff --git a/qapi/ui.json b/qapi/ui.json
index 3ad7835992..fc18a05f0f 100644
--- a/qapi/ui.json
+++ b/qapi/ui.json
@@ -1031,7 +1031,7 @@
# @core: Use OpenGL with Core (desktop) Context.
# @es: Use OpenGL with ES (embedded systems) Context.
#
- # Since: 2.13
+ # Since: 3.0
#
##
{ 'enum' : 'DisplayGLMode',
diff --git a/qemu-doc.texi b/qemu-doc.texi
index 0e0e0ae72b..f00706b999 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -2917,11 +2917,16 @@ The @code{-localtime} option has been replaced by @code{-rtc base=localtime}.
The @code{-startdate} option has been replaced by @code{-rtc base=@var{date}}.
-@subsection -virtioconsole (since 2.13.0)
+@subsection -virtioconsole (since 3.0.0)
Option @option{-virtioconsole} has been replaced by
@option{-device virtconsole}.
+@subsection -clock (since 3.0.0)
+
+The @code{-clock} option is ignored since QEMU version 1.7.0. There is no
+replacement since it is not needed anymore.
+
@section qemu-img command line arguments
@subsection convert -s (since 2.0.0)
@@ -2940,7 +2945,7 @@ from qcow2 images.
The ``query-cpus'' command is replaced by the ``query-cpus-fast'' command.
-@subsection query-cpus-fast "arch" output member (since 2.13.0)
+@subsection query-cpus-fast "arch" output member (since 3.0.0)
The ``arch'' output member of the ``query-cpus-fast'' command is
replaced by the ``target'' output member.
diff --git a/qemu-img.c b/qemu-img.c
index 2b5a5706b6..976b437da0 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -861,19 +861,23 @@ static void run_block_job(BlockJob *job, Error **errp)
int ret = 0;
aio_context_acquire(aio_context);
- block_job_ref(job);
+ job_ref(&job->job);
do {
+ float progress = 0.0f;
aio_poll(aio_context, true);
- qemu_progress_print(job->len ?
- ((float)job->offset / job->len * 100.f) : 0.0f, 0);
- } while (!job->ready && !job->completed);
+ if (job->job.progress_total) {
+ progress = (float)job->job.progress_current /
+ job->job.progress_total * 100.f;
+ }
+ qemu_progress_print(progress, 0);
+ } while (!job_is_ready(&job->job) && !job_is_completed(&job->job));
- if (!job->completed) {
- ret = block_job_complete_sync(job, errp);
+ if (!job_is_completed(&job->job)) {
+ ret = job_complete_sync(&job->job, errp);
} else {
- ret = job->ret;
+ ret = job->job.ret;
}
- block_job_unref(job);
+ job_unref(&job->job);
aio_context_release(aio_context);
/* publish completion progress only when success */
@@ -1014,7 +1018,7 @@ static int img_commit(int argc, char **argv)
aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context);
- commit_active_start("commit", bs, base_bs, BLOCK_JOB_DEFAULT, 0,
+ commit_active_start("commit", bs, base_bs, JOB_DEFAULT, 0,
BLOCKDEV_ON_ERROR_REPORT, NULL, common_block_job_cb,
&cbi, false, &local_err);
aio_context_release(aio_context);
diff --git a/qemu-nbd.c b/qemu-nbd.c
index 0af0560ad1..51b9d38c72 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -482,6 +482,12 @@ static const char *socket_activation_validate_opts(const char *device,
return NULL;
}
+static void qemu_nbd_shutdown(void)
+{
+ job_cancel_sync_all();
+ bdrv_close_all();
+}
+
int main(int argc, char **argv)
{
BlockBackend *blk;
@@ -928,7 +934,7 @@ int main(int argc, char **argv)
exit(EXIT_FAILURE);
}
bdrv_init();
- atexit(bdrv_close_all);
+ atexit(qemu_nbd_shutdown);
srcpath = argv[optind];
if (imageOpts) {
diff --git a/qemu-options.hx b/qemu-options.hx
index abbfa6ae9e..c0d3951e9f 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1906,8 +1906,8 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
"-netdev user,id=str[,ipv4[=on|off]][,net=addr[/mask]][,host=addr]\n"
" [,ipv6[=on|off]][,ipv6-net=addr[/int]][,ipv6-host=addr]\n"
" [,restrict=on|off][,hostname=host][,dhcpstart=addr]\n"
- " [,dns=addr][,ipv6-dns=addr][,dnssearch=domain][,tftp=dir]\n"
- " [,bootfile=f][,hostfwd=rule][,guestfwd=rule]"
+ " [,dns=addr][,ipv6-dns=addr][,dnssearch=domain][,domainname=domain]\n"
+ " [,tftp=dir][,bootfile=f][,hostfwd=rule][,guestfwd=rule]"
#ifndef _WIN32
"[,smb=dir[,smbserver=addr]]\n"
#endif
@@ -2135,6 +2135,9 @@ Example:
qemu-system-i386 -nic user,dnssearch=mgmt.example.org,dnssearch=example.org
@end example
+@item domainname=@var{domain}
+Specifies the client domain name reported by the built-in DHCP server.
+
@item tftp=@var{dir}
When using the user mode network stack, activate a built-in TFTP
server. The files in @var{dir} will be exposed as the root of a TFTP server.
@@ -3299,6 +3302,19 @@ STEXI
Run the emulation in single step mode.
ETEXI
+DEF("preconfig", 0, QEMU_OPTION_preconfig, \
+ "--preconfig pause QEMU before machine is initialized\n",
+ QEMU_ARCH_ALL)
+STEXI
+@item --preconfig
+@findex --preconfig
+Pause QEMU for interactive configuration before the machine is created,
+which allows querying and configuring properties that will affect
+machine initialization. Use the QMP command 'exit-preconfig' to exit
+the preconfig state and move to the next state (ie. run guest if -S
+isn't used or pause the second time if -S is used).
+ETEXI
+
DEF("S", 0, QEMU_OPTION_S, \
"-S freeze CPU at startup (use 'c' to start execution)\n",
QEMU_ARCH_ALL)
diff --git a/qemu-seccomp.c b/qemu-seccomp.c
index b770a77d33..148e4c6f24 100644
--- a/qemu-seccomp.c
+++ b/qemu-seccomp.c
@@ -13,6 +13,11 @@
* GNU GPL, version 2 or (at your option) any later version.
*/
#include "qemu/osdep.h"
+#include "qemu/config-file.h"
+#include "qemu/option.h"
+#include "qemu/module.h"
+#include "qemu/error-report.h"
+#include <sys/prctl.h>
#include <seccomp.h>
#include "sysemu/seccomp.h"
@@ -96,7 +101,7 @@ static const struct QemuSeccompSyscall blacklist[] = {
};
-int seccomp_start(uint32_t seccomp_opts)
+static int seccomp_start(uint32_t seccomp_opts)
{
int rc = 0;
unsigned int i = 0;
@@ -125,3 +130,117 @@ int seccomp_start(uint32_t seccomp_opts)
seccomp_release(ctx);
return rc;
}
+
+#ifdef CONFIG_SECCOMP
+int parse_sandbox(void *opaque, QemuOpts *opts, Error **errp)
+{
+ if (qemu_opt_get_bool(opts, "enable", false)) {
+ uint32_t seccomp_opts = QEMU_SECCOMP_SET_DEFAULT
+ | QEMU_SECCOMP_SET_OBSOLETE;
+ const char *value = NULL;
+
+ value = qemu_opt_get(opts, "obsolete");
+ if (value) {
+ if (g_str_equal(value, "allow")) {
+ seccomp_opts &= ~QEMU_SECCOMP_SET_OBSOLETE;
+ } else if (g_str_equal(value, "deny")) {
+ /* this is the default option, this if is here
+ * to provide a little bit of consistency for
+ * the command line */
+ } else {
+ error_report("invalid argument for obsolete");
+ return -1;
+ }
+ }
+
+ value = qemu_opt_get(opts, "elevateprivileges");
+ if (value) {
+ if (g_str_equal(value, "deny")) {
+ seccomp_opts |= QEMU_SECCOMP_SET_PRIVILEGED;
+ } else if (g_str_equal(value, "children")) {
+ seccomp_opts |= QEMU_SECCOMP_SET_PRIVILEGED;
+
+ /* calling prctl directly because we're
+ * not sure if host has CAP_SYS_ADMIN set*/
+ if (prctl(PR_SET_NO_NEW_PRIVS, 1)) {
+ error_report("failed to set no_new_privs "
+ "aborting");
+ return -1;
+ }
+ } else if (g_str_equal(value, "allow")) {
+ /* default value */
+ } else {
+ error_report("invalid argument for elevateprivileges");
+ return -1;
+ }
+ }
+
+ value = qemu_opt_get(opts, "spawn");
+ if (value) {
+ if (g_str_equal(value, "deny")) {
+ seccomp_opts |= QEMU_SECCOMP_SET_SPAWN;
+ } else if (g_str_equal(value, "allow")) {
+ /* default value */
+ } else {
+ error_report("invalid argument for spawn");
+ return -1;
+ }
+ }
+
+ value = qemu_opt_get(opts, "resourcecontrol");
+ if (value) {
+ if (g_str_equal(value, "deny")) {
+ seccomp_opts |= QEMU_SECCOMP_SET_RESOURCECTL;
+ } else if (g_str_equal(value, "allow")) {
+ /* default value */
+ } else {
+ error_report("invalid argument for resourcecontrol");
+ return -1;
+ }
+ }
+
+ if (seccomp_start(seccomp_opts) < 0) {
+ error_report("failed to install seccomp syscall filter "
+ "in the kernel");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static QemuOptsList qemu_sandbox_opts = {
+ .name = "sandbox",
+ .implied_opt_name = "enable",
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_sandbox_opts.head),
+ .desc = {
+ {
+ .name = "enable",
+ .type = QEMU_OPT_BOOL,
+ },
+ {
+ .name = "obsolete",
+ .type = QEMU_OPT_STRING,
+ },
+ {
+ .name = "elevateprivileges",
+ .type = QEMU_OPT_STRING,
+ },
+ {
+ .name = "spawn",
+ .type = QEMU_OPT_STRING,
+ },
+ {
+ .name = "resourcecontrol",
+ .type = QEMU_OPT_STRING,
+ },
+ { /* end of list */ }
+ },
+};
+
+static void seccomp_register(void)
+{
+ qemu_add_opts(&qemu_sandbox_opts);
+}
+opts_init(seccomp_register);
+#endif
diff --git a/qemu-tech.texi b/qemu-tech.texi
index 52a56ae25e..dcecba83cb 100644
--- a/qemu-tech.texi
+++ b/qemu-tech.texi
@@ -5,6 +5,7 @@
* CPU emulation::
* Translator Internals::
* QEMU compared to other emulators::
+* Managed start up options::
* Bibliography::
@end menu
@@ -314,6 +315,45 @@ VirtualBox [9], Xen [10] and KVM [11] are based on QEMU. QEMU-SystemC
[12] uses QEMU to simulate a system where some hardware devices are
developed in SystemC.
+@node Managed start up options
+@section Managed start up options
+
+In system mode emulation, it's possible to create a VM in a paused state using
+the -S command line option. In this state the machine is completely initialized
+according to command line options and ready to execute VM code but VCPU threads
+are not executing any code. The VM state in this paused state depends on the way
+QEMU was started. It could be in:
+@table @asis
+@item initial state (after reset/power on state)
+@item with direct kernel loading, the initial state could be amended to execute
+code loaded by QEMU in the VM's RAM and with incoming migration
+@item with incoming migration, initial state will by amended with the migrated
+machine state after migration completes.
+@end table
+
+This paused state is typically used by users to query machine state and/or
+additionally configure the machine (by hotplugging devices) in runtime before
+allowing VM code to run.
+
+However, at the -S pause point, it's impossible to configure options that affect
+initial VM creation (like: -smp/-m/-numa ...) or cold plug devices. That's
+when the --preconfig command line option should be used. It allows pausing QEMU
+before the initial VM creation, in a new preconfig state, where additional
+queries and configuration can be performed via QMP before moving on to
+the resulting configuration startup. In the preconfig state, QEMU only allows
+a limited set of commands over the QMP monitor, where the commands do not
+depend on an initialized machine, including but not limited to:
+@table @asis
+@item qmp_capabilities
+@item query-qmp-schema
+@item query-commands
+@item query-status
+@item exit-preconfig
+@end table
+The full list of commands is in QMP schema which could be queried with
+query-qmp-schema, where commands supported at preconfig state have option
+'allow-preconfig' set to true.
+
@node Bibliography
@section Bibliography
diff --git a/qmp.c b/qmp.c
index 25fdc9a5b2..73e46d795f 100644
--- a/qmp.c
+++ b/qmp.c
@@ -161,6 +161,16 @@ SpiceInfo *qmp_query_spice(Error **errp)
};
#endif
+void qmp_exit_preconfig(Error **errp)
+{
+ if (!runstate_check(RUN_STATE_PRECONFIG)) {
+ error_setg(errp, "The command is permitted only in '%s' state",
+ RunState_str(RUN_STATE_PRECONFIG));
+ return;
+ }
+ qemu_exit_preconfig_request();
+}
+
void qmp_cont(Error **errp)
{
BlockBackend *blk;
diff --git a/qom/object.c b/qom/object.c
index 0fc972030e..cb7a8cd589 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -1669,25 +1669,29 @@ gchar *object_get_canonical_path(Object *obj)
Object *root = object_get_root();
char *newpath, *path = NULL;
- while (obj != root) {
+ if (obj == root) {
+ return g_strdup("/");
+ }
+
+ do {
char *component = object_get_canonical_path_component(obj);
- if (path) {
- newpath = g_strdup_printf("%s/%s", component, path);
- g_free(component);
+ if (!component) {
+ /* A canonical path must be complete, so discard what was
+ * collected so far.
+ */
g_free(path);
- path = newpath;
- } else {
- path = component;
+ return NULL;
}
+ newpath = g_strdup_printf("/%s%s", component, path ? path : "");
+ g_free(path);
+ g_free(component);
+ path = newpath;
obj = obj->parent;
- }
-
- newpath = g_strdup_printf("/%s", path ? path : "");
- g_free(path);
+ } while (obj != root);
- return newpath;
+ return path;
}
Object *object_resolve_path_component(Object *parent, const gchar *part)
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index cb1b652388..e3d8c2cdfc 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -271,7 +271,7 @@ our @typeList = (
qr{hwaddr},
# external libraries
qr{xml${Ident}},
- qr{xendevicemodel_handle},
+ qr{xen\w+_handle},
# Glib definitions
qr{gchar},
qr{gshort},
diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
index 0c5da3a54d..3b0867c14f 100644
--- a/scripts/qapi/commands.py
+++ b/scripts/qapi/commands.py
@@ -193,13 +193,15 @@ out:
return ret
-def gen_register_command(name, success_response, allow_oob):
+def gen_register_command(name, success_response, allow_oob, allow_preconfig):
options = []
if not success_response:
options += ['QCO_NO_SUCCESS_RESP']
if allow_oob:
options += ['QCO_ALLOW_OOB']
+ if allow_preconfig:
+ options += ['QCO_ALLOW_PRECONFIG']
if not options:
options = ['QCO_NO_OPTIONS']
@@ -275,8 +277,8 @@ void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds);
c_prefix=c_name(self._prefix, protect=False)))
genc.add(gen_registry(self._regy, self._prefix))
- def visit_command(self, name, info, arg_type, ret_type,
- gen, success_response, boxed, allow_oob):
+ def visit_command(self, name, info, arg_type, ret_type, gen,
+ success_response, boxed, allow_oob, allow_preconfig):
if not gen:
return
self._genh.add(gen_command_decl(name, arg_type, boxed, ret_type))
@@ -285,7 +287,8 @@ void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds);
self._genc.add(gen_marshal_output(ret_type))
self._genh.add(gen_marshal_decl(name))
self._genc.add(gen_marshal(name, arg_type, boxed, ret_type))
- self._regy += gen_register_command(name, success_response, allow_oob)
+ self._regy += gen_register_command(name, success_response, allow_oob,
+ allow_preconfig)
def gen_commands(schema, output_dir, prefix):
diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py
index a032cec375..e82990f0f2 100644
--- a/scripts/qapi/common.py
+++ b/scripts/qapi/common.py
@@ -872,7 +872,8 @@ def check_keys(expr_elem, meta, required, optional=[]):
raise QAPISemError(info,
"'%s' of %s '%s' should only use false value"
% (key, meta, name))
- if (key == 'boxed' or key == 'allow-oob') and value is not True:
+ if (key == 'boxed' or key == 'allow-oob' or
+ key == 'allow-preconfig') and value is not True:
raise QAPISemError(info,
"'%s' of %s '%s' should only use true value"
% (key, meta, name))
@@ -922,7 +923,7 @@ def check_exprs(exprs):
meta = 'command'
check_keys(expr_elem, 'command', [],
['data', 'returns', 'gen', 'success-response',
- 'boxed', 'allow-oob'])
+ 'boxed', 'allow-oob', 'allow-preconfig'])
elif 'event' in expr:
meta = 'event'
check_keys(expr_elem, 'event', [], ['data', 'boxed'])
@@ -1044,8 +1045,8 @@ class QAPISchemaVisitor(object):
def visit_alternate_type(self, name, info, variants):
pass
- def visit_command(self, name, info, arg_type, ret_type,
- gen, success_response, boxed, allow_oob):
+ def visit_command(self, name, info, arg_type, ret_type, gen,
+ success_response, boxed, allow_oob, allow_preconfig):
pass
def visit_event(self, name, info, arg_type, boxed):
@@ -1422,7 +1423,7 @@ class QAPISchemaAlternateType(QAPISchemaType):
class QAPISchemaCommand(QAPISchemaEntity):
def __init__(self, name, info, doc, arg_type, ret_type,
- gen, success_response, boxed, allow_oob):
+ gen, success_response, boxed, allow_oob, allow_preconfig):
QAPISchemaEntity.__init__(self, name, info, doc)
assert not arg_type or isinstance(arg_type, str)
assert not ret_type or isinstance(ret_type, str)
@@ -1434,6 +1435,7 @@ class QAPISchemaCommand(QAPISchemaEntity):
self.success_response = success_response
self.boxed = boxed
self.allow_oob = allow_oob
+ self.allow_preconfig = allow_preconfig
def check(self, schema):
if self._arg_type_name:
@@ -1458,7 +1460,8 @@ class QAPISchemaCommand(QAPISchemaEntity):
visitor.visit_command(self.name, self.info,
self.arg_type, self.ret_type,
self.gen, self.success_response,
- self.boxed, self.allow_oob)
+ self.boxed, self.allow_oob,
+ self.allow_preconfig)
class QAPISchemaEvent(QAPISchemaEntity):
@@ -1678,6 +1681,7 @@ class QAPISchema(object):
success_response = expr.get('success-response', True)
boxed = expr.get('boxed', False)
allow_oob = expr.get('allow-oob', False)
+ allow_preconfig = expr.get('allow-preconfig', False)
if isinstance(data, OrderedDict):
data = self._make_implicit_object_type(
name, info, doc, 'arg', self._make_members(data, info))
@@ -1686,7 +1690,7 @@ class QAPISchema(object):
rets = self._make_array_type(rets[0], info)
self._def_entity(QAPISchemaCommand(name, info, doc, data, rets,
gen, success_response,
- boxed, allow_oob))
+ boxed, allow_oob, allow_preconfig))
def _def_event(self, expr, info, doc):
name = expr['event']
diff --git a/scripts/qapi/doc.py b/scripts/qapi/doc.py
index 9b312b2c51..b5630844f9 100644
--- a/scripts/qapi/doc.py
+++ b/scripts/qapi/doc.py
@@ -226,8 +226,8 @@ class QAPISchemaGenDocVisitor(qapi.common.QAPISchemaVisitor):
name=doc.symbol,
body=texi_entity(doc, 'Members')))
- def visit_command(self, name, info, arg_type, ret_type,
- gen, success_response, boxed, allow_oob):
+ def visit_command(self, name, info, arg_type, ret_type, gen,
+ success_response, boxed, allow_oob, allow_preconfig):
doc = self.cur_doc
if boxed:
body = texi_body(doc)
diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py
index f9e67e8227..5b6c72c7b2 100644
--- a/scripts/qapi/introspect.py
+++ b/scripts/qapi/introspect.py
@@ -171,14 +171,15 @@ const QLitObject %(c_name)s = %(c_string)s;
{'members': [{'type': self._use_type(m.type)}
for m in variants.variants]})
- def visit_command(self, name, info, arg_type, ret_type,
- gen, success_response, boxed, allow_oob):
+ def visit_command(self, name, info, arg_type, ret_type, gen,
+ success_response, boxed, allow_oob, allow_preconfig):
arg_type = arg_type or self._schema.the_empty_object_type
ret_type = ret_type or self._schema.the_empty_object_type
self._gen_qlit(name, 'command',
{'arg-type': self._use_type(arg_type),
'ret-type': self._use_type(ret_type),
- 'allow-oob': allow_oob})
+ 'allow-oob': allow_oob,
+ 'allow-preconfig': allow_preconfig})
def visit_event(self, name, info, arg_type, boxed):
arg_type = arg_type or self._schema.the_empty_object_type
diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh
index 947dec2852..feb75390aa 100755
--- a/scripts/update-linux-headers.sh
+++ b/scripts/update-linux-headers.sh
@@ -51,7 +51,8 @@ cp_portable() {
fi
header=$(basename "$f");
- sed -e 's/__u\([0-9][0-9]*\)/uint\1_t/g' \
+ sed -e 's/__aligned_u64/__u64 __attribute__((aligned(8)))/g' \
+ -e 's/__u\([0-9][0-9]*\)/uint\1_t/g' \
-e 's/u\([0-9][0-9]*\)/uint\1_t/g' \
-e 's/__s\([0-9][0-9]*\)/int\1_t/g' \
-e 's/__le\([0-9][0-9]*\)/uint\1_t/g' \
@@ -141,6 +142,20 @@ else
cp "$linux/COPYING" "$output/linux-headers"
fi
+# Recent kernel sources split the copyright/license info into multiple
+# files, which we need to copy. This set of licenses is the set that
+# are referred to by SPDX lines in the headers we currently copy.
+# We don't copy the Documentation/process/license-rules.rst which
+# is also referred to by COPYING, since it's explanatory rather than license.
+if [ -d "$linux/LICENSES" ]; then
+ mkdir -p "$output/linux-headers/LICENSES/preferred" \
+ "$output/linux-headers/LICENSES/exceptions"
+ for l in preferred/GPL-2.0 preferred/BSD-2-Clause preferred/BSD-3-Clause \
+ exceptions/Linux-syscall-note; do
+ cp "$linux/LICENSES/$l" "$output/linux-headers/LICENSES/$l"
+ done
+fi
+
cat <<EOF >$output/linux-headers/linux/virtio_config.h
#include "standard-headers/linux/virtio_config.h"
EOF
diff --git a/slirp/arp_table.c b/slirp/arp_table.c
index bac608f97f..f81963bb88 100644
--- a/slirp/arp_table.c
+++ b/slirp/arp_table.c
@@ -33,7 +33,7 @@ void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN])
int i;
DEBUG_CALL("arp_table_add");
- DEBUG_ARG("ip = %s", inet_ntoa(*(struct in_addr *)&ip_addr));
+ DEBUG_ARG("ip = %s", inet_ntoa((struct in_addr){.s_addr = ip_addr}));
DEBUG_ARGS((dfd, " hw addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
ethaddr[0], ethaddr[1], ethaddr[2],
ethaddr[3], ethaddr[4], ethaddr[5]));
@@ -67,7 +67,7 @@ bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
int i;
DEBUG_CALL("arp_table_search");
- DEBUG_ARG("ip = %s", inet_ntoa(*(struct in_addr *)&ip_addr));
+ DEBUG_ARG("ip = %s", inet_ntoa((struct in_addr){.s_addr = ip_addr}));
/* If broadcast address */
if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
diff --git a/slirp/bootp.c b/slirp/bootp.c
index 5dd1a415b5..9e7b53ba94 100644
--- a/slirp/bootp.c
+++ b/slirp/bootp.c
@@ -298,6 +298,14 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
q += val;
}
+ if (slirp->vdomainname) {
+ val = strlen(slirp->vdomainname);
+ *q++ = RFC1533_DOMAINNAME;
+ *q++ = val;
+ memcpy(q, slirp->vdomainname, val);
+ q += val;
+ }
+
if (slirp->vdnssearch) {
size_t spaceleft = sizeof(rbp->bp_vend) - (q - rbp->bp_vend);
val = slirp->vdnssearch_len;
diff --git a/slirp/libslirp.h b/slirp/libslirp.h
index 540b3e5903..740408a96e 100644
--- a/slirp/libslirp.h
+++ b/slirp/libslirp.h
@@ -16,7 +16,7 @@ Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
const char *tftp_path, const char *bootfile,
struct in_addr vdhcp_start, struct in_addr vnameserver,
struct in6_addr vnameserver6, const char **vdnssearch,
- void *opaque);
+ const char *vdomainname, void *opaque);
void slirp_cleanup(Slirp *slirp);
void slirp_pollfds_fill(GArray *pollfds, uint32_t *timeout);
diff --git a/slirp/ncsi.c b/slirp/ncsi.c
index d12ba3e494..7116034afc 100644
--- a/slirp/ncsi.c
+++ b/slirp/ncsi.c
@@ -1,7 +1,7 @@
/*
* NC-SI (Network Controller Sideband Interface) "echo" model
*
- * Copyright (C) 2016 IBM Corp.
+ * Copyright (C) 2016-2018 IBM Corp.
*
* This code is licensed under the GPL version 2 or later. See the
* COPYING file in the top-level directory.
@@ -11,6 +11,23 @@
#include "ncsi-pkt.h"
+static uint32_t ncsi_calculate_checksum(uint16_t *data, int len)
+{
+ uint32_t checksum = 0;
+ int i;
+
+ /*
+ * 32-bit unsigned sum of the NC-SI packet header and NC-SI packet
+ * payload interpreted as a series of 16-bit unsigned integer values.
+ */
+ for (i = 0; i < len; i++) {
+ checksum += htons(data[i]);
+ }
+
+ checksum = (~checksum + 1);
+ return checksum;
+}
+
/* Get Capabilities */
static int ncsi_rsp_handler_gc(struct ncsi_rsp_pkt_hdr *rnh)
{
@@ -35,6 +52,20 @@ static int ncsi_rsp_handler_gls(struct ncsi_rsp_pkt_hdr *rnh)
return 0;
}
+/* Get Parameters */
+static int ncsi_rsp_handler_gp(struct ncsi_rsp_pkt_hdr *rnh)
+{
+ struct ncsi_rsp_gp_pkt *rsp = (struct ncsi_rsp_gp_pkt *) rnh;
+
+ /* no MAC address filters or VLAN filters on the channel */
+ rsp->mac_cnt = 0;
+ rsp->mac_enable = 0;
+ rsp->vlan_cnt = 0;
+ rsp->vlan_enable = 0;
+
+ return 0;
+}
+
static const struct ncsi_rsp_handler {
unsigned char type;
int payload;
@@ -60,9 +91,9 @@ static const struct ncsi_rsp_handler {
{ NCSI_PKT_RSP_EGMF, 4, NULL },
{ NCSI_PKT_RSP_DGMF, 4, NULL },
{ NCSI_PKT_RSP_SNFC, 4, NULL },
- { NCSI_PKT_RSP_GVI, 36, NULL },
+ { NCSI_PKT_RSP_GVI, 40, NULL },
{ NCSI_PKT_RSP_GC, 32, ncsi_rsp_handler_gc },
- { NCSI_PKT_RSP_GP, -1, NULL },
+ { NCSI_PKT_RSP_GP, 40, ncsi_rsp_handler_gp },
{ NCSI_PKT_RSP_GCPS, 172, NULL },
{ NCSI_PKT_RSP_GNS, 172, NULL },
{ NCSI_PKT_RSP_GNPTS, 172, NULL },
@@ -87,6 +118,9 @@ void ncsi_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
(ncsi_reply + ETH_HLEN);
const struct ncsi_rsp_handler *handler = NULL;
int i;
+ int ncsi_rsp_len = sizeof(*nh);
+ uint32_t checksum;
+ uint32_t *pchecksum;
memset(ncsi_reply, 0, sizeof(ncsi_reply));
@@ -116,15 +150,18 @@ void ncsi_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
/* TODO: handle errors */
handler->handler(rnh);
}
+ ncsi_rsp_len += handler->payload;
} else {
rnh->common.length = 0;
rnh->code = htons(NCSI_PKT_RSP_C_UNAVAILABLE);
rnh->reason = htons(NCSI_PKT_RSP_R_UNKNOWN);
}
- /* TODO: add a checksum at the end of the frame but the specs
- * allows it to be zero */
+ /* Add the optional checksum at the end of the frame. */
+ checksum = ncsi_calculate_checksum((uint16_t *) rnh, ncsi_rsp_len);
+ pchecksum = (uint32_t *)((void *) rnh + ncsi_rsp_len);
+ *pchecksum = htonl(checksum);
+ ncsi_rsp_len += 4;
- slirp_output(slirp->opaque, ncsi_reply, ETH_HLEN + sizeof(*nh) +
- (handler ? handler->payload : 0) + 4);
+ slirp_output(slirp->opaque, ncsi_reply, ETH_HLEN + ncsi_rsp_len);
}
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 1cb6b07004..5c3bd6163f 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -286,7 +286,7 @@ Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
const char *tftp_path, const char *bootfile,
struct in_addr vdhcp_start, struct in_addr vnameserver,
struct in6_addr vnameserver6, const char **vdnssearch,
- void *opaque)
+ const char *vdomainname, void *opaque)
{
Slirp *slirp = g_malloc0(sizeof(Slirp));
@@ -317,6 +317,7 @@ Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
}
slirp->tftp_prefix = g_strdup(tftp_path);
slirp->bootp_filename = g_strdup(bootfile);
+ slirp->vdomainname = g_strdup(vdomainname);
slirp->vdhcp_startaddr = vdhcp_start;
slirp->vnameserver_addr = vnameserver;
slirp->vnameserver_addr6 = vnameserver6;
@@ -349,6 +350,7 @@ void slirp_cleanup(Slirp *slirp)
g_free(slirp->vdnssearch);
g_free(slirp->tftp_prefix);
g_free(slirp->bootp_filename);
+ g_free(slirp->vdomainname);
g_free(slirp);
}
@@ -676,13 +678,13 @@ void slirp_pollfds_poll(GArray *pollfds, int select_error)
/* continue; */
} else {
ret = sowrite(so);
+ if (ret > 0) {
+ /* Call tcp_output in case we need to send a window
+ * update to the guest, otherwise it will be stuck
+ * until it sends a window probe. */
+ tcp_output(sototcpcb(so));
+ }
}
- /*
- * XXXXX If we wrote something (a lot), there
- * could be a need for a window update.
- * In the worst case, the remote will send
- * a window probe to get things going again
- */
}
/*
diff --git a/slirp/slirp.h b/slirp/slirp.h
index 06febfc78b..10b410898a 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -193,6 +193,7 @@ struct Slirp {
char *bootp_filename;
size_t vdnssearch_len;
uint8_t *vdnssearch;
+ char *vdomainname;
/* tcp states */
struct socket tcb;
diff --git a/slirp/socket.c b/slirp/socket.c
index 61347d1a0c..e2a71c9b04 100644
--- a/slirp/socket.c
+++ b/slirp/socket.c
@@ -701,9 +701,9 @@ tcp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
memset(&addr, 0, addrlen);
DEBUG_CALL("tcp_listen");
- DEBUG_ARG("haddr = %s", inet_ntoa(*(struct in_addr *)&haddr));
+ DEBUG_ARG("haddr = %s", inet_ntoa((struct in_addr){.s_addr = haddr}));
DEBUG_ARG("hport = %d", ntohs(hport));
- DEBUG_ARG("laddr = %s", inet_ntoa(*(struct in_addr *)&laddr));
+ DEBUG_ARG("laddr = %s", inet_ntoa((struct in_addr){.s_addr = laddr}));
DEBUG_ARG("lport = %d", ntohs(lport));
DEBUG_ARG("flags = %x", flags);
@@ -754,6 +754,8 @@ tcp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
return NULL;
}
qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
+ opt = 1;
+ qemu_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(int));
getsockname(s,(struct sockaddr *)&addr,&addrlen);
so->so_ffamily = AF_INET;
diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c
index da0d53743f..8d0f94b75f 100644
--- a/slirp/tcp_subr.c
+++ b/slirp/tcp_subr.c
@@ -416,6 +416,8 @@ int tcp_fconnect(struct socket *so, unsigned short af)
socket_set_fast_reuse(s);
opt = 1;
qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt));
+ opt = 1;
+ qemu_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
addr = so->fhost.ss;
DEBUG_CALL(" connect()ing")
diff --git a/target/arm/arm-powerctl.c b/target/arm/arm-powerctl.c
index 25207cb850..ce55eeb682 100644
--- a/target/arm/arm-powerctl.c
+++ b/target/arm/arm-powerctl.c
@@ -15,7 +15,6 @@
#include "arm-powerctl.h"
#include "qemu/log.h"
#include "qemu/main-loop.h"
-#include "exec/exec-all.h"
#ifndef DEBUG_ARM_POWERCTL
#define DEBUG_ARM_POWERCTL 0
diff --git a/target/arm/arm_ldst.h b/target/arm/arm_ldst.h
index 01587b3ebb..5e0ac8bef0 100644
--- a/target/arm/arm_ldst.h
+++ b/target/arm/arm_ldst.h
@@ -20,7 +20,6 @@
#ifndef ARM_LDST_H
#define ARM_LDST_H
-#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
#include "qemu/bswap.h"
diff --git a/target/arm/crypto_helper.c b/target/arm/crypto_helper.c
index cc339ea7e0..f800266727 100644
--- a/target/arm/crypto_helper.c
+++ b/target/arm/crypto_helper.c
@@ -12,7 +12,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "exec/exec-all.h"
#include "exec/helper-proto.h"
#include "crypto/aes.h"
diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c
index e80cfb47c7..0c64c0292e 100644
--- a/target/arm/gdbstub.c
+++ b/target/arm/gdbstub.c
@@ -157,8 +157,7 @@ int arm_gen_dynamic_xml(CPUState *cs)
RegisterSysregXmlParam param = {cs, s};
cpu->dyn_xml.num_cpregs = 0;
- cpu->dyn_xml.cpregs_keys = g_malloc(sizeof(uint32_t *) *
- g_hash_table_size(cpu->cp_regs));
+ cpu->dyn_xml.cpregs_keys = g_new(uint32_t, g_hash_table_size(cpu->cp_regs));
g_string_printf(s, "<?xml version=\"1.0\"?>");
g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">");
g_string_append_printf(s, "<feature name=\"org.qemu.gdb.arm.sys.regs\">");
diff --git a/target/arm/helper-a64.c b/target/arm/helper-a64.c
index f92bdea732..7f6ad3000b 100644
--- a/target/arm/helper-a64.c
+++ b/target/arm/helper-a64.c
@@ -85,12 +85,12 @@ static inline uint32_t float_rel_to_flags(int res)
return flags;
}
-uint64_t HELPER(vfp_cmph_a64)(float16 x, float16 y, void *fp_status)
+uint64_t HELPER(vfp_cmph_a64)(uint32_t x, uint32_t y, void *fp_status)
{
return float_rel_to_flags(float16_compare_quiet(x, y, fp_status));
}
-uint64_t HELPER(vfp_cmpeh_a64)(float16 x, float16 y, void *fp_status)
+uint64_t HELPER(vfp_cmpeh_a64)(uint32_t x, uint32_t y, void *fp_status)
{
return float_rel_to_flags(float16_compare(x, y, fp_status));
}
@@ -214,7 +214,7 @@ uint64_t HELPER(neon_cgt_f64)(float64 a, float64 b, void *fpstp)
#define float64_three make_float64(0x4008000000000000ULL)
#define float64_one_point_five make_float64(0x3FF8000000000000ULL)
-float16 HELPER(recpsf_f16)(float16 a, float16 b, void *fpstp)
+uint32_t HELPER(recpsf_f16)(uint32_t a, uint32_t b, void *fpstp)
{
float_status *fpst = fpstp;
@@ -259,7 +259,7 @@ float64 HELPER(recpsf_f64)(float64 a, float64 b, void *fpstp)
return float64_muladd(a, b, float64_two, 0, fpst);
}
-float16 HELPER(rsqrtsf_f16)(float16 a, float16 b, void *fpstp)
+uint32_t HELPER(rsqrtsf_f16)(uint32_t a, uint32_t b, void *fpstp)
{
float_status *fpst = fpstp;
@@ -366,7 +366,7 @@ uint64_t HELPER(neon_addlp_u16)(uint64_t a)
}
/* Floating-point reciprocal exponent - see FPRecpX in ARM ARM */
-float16 HELPER(frecpx_f16)(float16 a, void *fpstp)
+uint32_t HELPER(frecpx_f16)(uint32_t a, void *fpstp)
{
float_status *fpst = fpstp;
uint16_t val16, sbit;
@@ -384,6 +384,8 @@ float16 HELPER(frecpx_f16)(float16 a, void *fpstp)
return nan;
}
+ a = float16_squash_input_denormal(a, fpst);
+
val16 = float16_val(a);
sbit = 0x8000 & val16;
exp = extract32(val16, 10, 5);
@@ -413,6 +415,8 @@ float32 HELPER(frecpx_f32)(float32 a, void *fpstp)
return nan;
}
+ a = float32_squash_input_denormal(a, fpst);
+
val32 = float32_val(a);
sbit = 0x80000000ULL & val32;
exp = extract32(val32, 23, 8);
@@ -442,6 +446,8 @@ float64 HELPER(frecpx_f64)(float64 a, void *fpstp)
return nan;
}
+ a = float64_squash_input_denormal(a, fpst);
+
val64 = float64_val(a);
sbit = 0x8000000000000000ULL & val64;
exp = extract64(float64_val(a), 52, 11);
@@ -695,7 +701,7 @@ void HELPER(casp_be_parallel)(CPUARMState *env, uint32_t rs, uint64_t addr,
#define ADVSIMD_HELPER(name, suffix) HELPER(glue(glue(advsimd_, name), suffix))
#define ADVSIMD_HALFOP(name) \
-float16 ADVSIMD_HELPER(name, h)(float16 a, float16 b, void *fpstp) \
+uint32_t ADVSIMD_HELPER(name, h)(uint32_t a, uint32_t b, void *fpstp) \
{ \
float_status *fpst = fpstp; \
return float16_ ## name(a, b, fpst); \
@@ -755,7 +761,8 @@ ADVSIMD_HALFOP(mulx)
ADVSIMD_TWOHALFOP(mulx)
/* fused multiply-accumulate */
-float16 HELPER(advsimd_muladdh)(float16 a, float16 b, float16 c, void *fpstp)
+uint32_t HELPER(advsimd_muladdh)(uint32_t a, uint32_t b, uint32_t c,
+ void *fpstp)
{
float_status *fpst = fpstp;
return float16_muladd(a, b, c, 0, fpst);
@@ -786,14 +793,14 @@ uint32_t HELPER(advsimd_muladd2h)(uint32_t two_a, uint32_t two_b,
#define ADVSIMD_CMPRES(test) (test) ? 0xffff : 0
-uint32_t HELPER(advsimd_ceq_f16)(float16 a, float16 b, void *fpstp)
+uint32_t HELPER(advsimd_ceq_f16)(uint32_t a, uint32_t b, void *fpstp)
{
float_status *fpst = fpstp;
int compare = float16_compare_quiet(a, b, fpst);
return ADVSIMD_CMPRES(compare == float_relation_equal);
}
-uint32_t HELPER(advsimd_cge_f16)(float16 a, float16 b, void *fpstp)
+uint32_t HELPER(advsimd_cge_f16)(uint32_t a, uint32_t b, void *fpstp)
{
float_status *fpst = fpstp;
int compare = float16_compare(a, b, fpst);
@@ -801,14 +808,14 @@ uint32_t HELPER(advsimd_cge_f16)(float16 a, float16 b, void *fpstp)
compare == float_relation_equal);
}
-uint32_t HELPER(advsimd_cgt_f16)(float16 a, float16 b, void *fpstp)
+uint32_t HELPER(advsimd_cgt_f16)(uint32_t a, uint32_t b, void *fpstp)
{
float_status *fpst = fpstp;
int compare = float16_compare(a, b, fpst);
return ADVSIMD_CMPRES(compare == float_relation_greater);
}
-uint32_t HELPER(advsimd_acge_f16)(float16 a, float16 b, void *fpstp)
+uint32_t HELPER(advsimd_acge_f16)(uint32_t a, uint32_t b, void *fpstp)
{
float_status *fpst = fpstp;
float16 f0 = float16_abs(a);
@@ -818,7 +825,7 @@ uint32_t HELPER(advsimd_acge_f16)(float16 a, float16 b, void *fpstp)
compare == float_relation_equal);
}
-uint32_t HELPER(advsimd_acgt_f16)(float16 a, float16 b, void *fpstp)
+uint32_t HELPER(advsimd_acgt_f16)(uint32_t a, uint32_t b, void *fpstp)
{
float_status *fpst = fpstp;
float16 f0 = float16_abs(a);
@@ -828,12 +835,12 @@ uint32_t HELPER(advsimd_acgt_f16)(float16 a, float16 b, void *fpstp)
}
/* round to integral */
-float16 HELPER(advsimd_rinth_exact)(float16 x, void *fp_status)
+uint32_t HELPER(advsimd_rinth_exact)(uint32_t x, void *fp_status)
{
return float16_round_to_int(x, fp_status);
}
-float16 HELPER(advsimd_rinth)(float16 x, void *fp_status)
+uint32_t HELPER(advsimd_rinth)(uint32_t x, void *fp_status)
{
int old_flags = get_float_exception_flags(fp_status), new_flags;
float16 ret;
@@ -857,7 +864,7 @@ float16 HELPER(advsimd_rinth)(float16 x, void *fp_status)
* setting the mode appropriately before calling the helper.
*/
-uint32_t HELPER(advsimd_f16tosinth)(float16 a, void *fpstp)
+uint32_t HELPER(advsimd_f16tosinth)(uint32_t a, void *fpstp)
{
float_status *fpst = fpstp;
@@ -869,7 +876,7 @@ uint32_t HELPER(advsimd_f16tosinth)(float16 a, void *fpstp)
return float16_to_int16(a, fpst);
}
-uint32_t HELPER(advsimd_f16touinth)(float16 a, void *fpstp)
+uint32_t HELPER(advsimd_f16touinth)(uint32_t a, void *fpstp)
{
float_status *fpst = fpstp;
@@ -885,7 +892,7 @@ uint32_t HELPER(advsimd_f16touinth)(float16 a, void *fpstp)
* Square Root and Reciprocal square root
*/
-float16 HELPER(sqrt_f16)(float16 a, void *fpstp)
+uint32_t HELPER(sqrt_f16)(uint32_t a, void *fpstp)
{
float_status *s = fpstp;
diff --git a/target/arm/helper.c b/target/arm/helper.c
index c0f739972e..f75aa6e9ca 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -863,6 +863,14 @@ static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri,
env->cp15.cpacr_el1 = value;
}
+static void cpacr_reset(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+ /* Call cpacr_write() so that we reset with the correct RAO bits set
+ * for our CPU features.
+ */
+ cpacr_write(env, ri, 0);
+}
+
static CPAccessResult cpacr_access(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
@@ -920,7 +928,7 @@ static const ARMCPRegInfo v6_cp_reginfo[] = {
{ .name = "CPACR", .state = ARM_CP_STATE_BOTH, .opc0 = 3,
.crn = 1, .crm = 0, .opc1 = 0, .opc2 = 2, .accessfn = cpacr_access,
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.cpacr_el1),
- .resetvalue = 0, .writefn = cpacr_write },
+ .resetfn = cpacr_reset, .writefn = cpacr_write },
REGINFO_SENTINEL
};
@@ -11344,35 +11352,35 @@ DO_VFP_cmp(d, float64)
/* Integer to float and float to integer conversions */
-#define CONV_ITOF(name, fsz, sign) \
- float##fsz HELPER(name)(uint32_t x, void *fpstp) \
-{ \
- float_status *fpst = fpstp; \
- return sign##int32_to_##float##fsz((sign##int32_t)x, fpst); \
+#define CONV_ITOF(name, ftype, fsz, sign) \
+ftype HELPER(name)(uint32_t x, void *fpstp) \
+{ \
+ float_status *fpst = fpstp; \
+ return sign##int32_to_##float##fsz((sign##int32_t)x, fpst); \
}
-#define CONV_FTOI(name, fsz, sign, round) \
-uint32_t HELPER(name)(float##fsz x, void *fpstp) \
-{ \
- float_status *fpst = fpstp; \
- if (float##fsz##_is_any_nan(x)) { \
- float_raise(float_flag_invalid, fpst); \
- return 0; \
- } \
- return float##fsz##_to_##sign##int32##round(x, fpst); \
+#define CONV_FTOI(name, ftype, fsz, sign, round) \
+uint32_t HELPER(name)(ftype x, void *fpstp) \
+{ \
+ float_status *fpst = fpstp; \
+ if (float##fsz##_is_any_nan(x)) { \
+ float_raise(float_flag_invalid, fpst); \
+ return 0; \
+ } \
+ return float##fsz##_to_##sign##int32##round(x, fpst); \
}
-#define FLOAT_CONVS(name, p, fsz, sign) \
-CONV_ITOF(vfp_##name##to##p, fsz, sign) \
-CONV_FTOI(vfp_to##name##p, fsz, sign, ) \
-CONV_FTOI(vfp_to##name##z##p, fsz, sign, _round_to_zero)
+#define FLOAT_CONVS(name, p, ftype, fsz, sign) \
+ CONV_ITOF(vfp_##name##to##p, ftype, fsz, sign) \
+ CONV_FTOI(vfp_to##name##p, ftype, fsz, sign, ) \
+ CONV_FTOI(vfp_to##name##z##p, ftype, fsz, sign, _round_to_zero)
-FLOAT_CONVS(si, h, 16, )
-FLOAT_CONVS(si, s, 32, )
-FLOAT_CONVS(si, d, 64, )
-FLOAT_CONVS(ui, h, 16, u)
-FLOAT_CONVS(ui, s, 32, u)
-FLOAT_CONVS(ui, d, 64, u)
+FLOAT_CONVS(si, h, uint32_t, 16, )
+FLOAT_CONVS(si, s, float32, 32, )
+FLOAT_CONVS(si, d, float64, 64, )
+FLOAT_CONVS(ui, h, uint32_t, 16, u)
+FLOAT_CONVS(ui, s, float32, 32, u)
+FLOAT_CONVS(ui, d, float64, 64, u)
#undef CONV_ITOF
#undef CONV_FTOI
@@ -11465,22 +11473,22 @@ static float16 do_postscale_fp16(float64 f, int shift, float_status *fpst)
return float64_to_float16(float64_scalbn(f, -shift, fpst), true, fpst);
}
-float16 HELPER(vfp_sltoh)(uint32_t x, uint32_t shift, void *fpst)
+uint32_t HELPER(vfp_sltoh)(uint32_t x, uint32_t shift, void *fpst)
{
return do_postscale_fp16(int32_to_float64(x, fpst), shift, fpst);
}
-float16 HELPER(vfp_ultoh)(uint32_t x, uint32_t shift, void *fpst)
+uint32_t HELPER(vfp_ultoh)(uint32_t x, uint32_t shift, void *fpst)
{
return do_postscale_fp16(uint32_to_float64(x, fpst), shift, fpst);
}
-float16 HELPER(vfp_sqtoh)(uint64_t x, uint32_t shift, void *fpst)
+uint32_t HELPER(vfp_sqtoh)(uint64_t x, uint32_t shift, void *fpst)
{
return do_postscale_fp16(int64_to_float64(x, fpst), shift, fpst);
}
-float16 HELPER(vfp_uqtoh)(uint64_t x, uint32_t shift, void *fpst)
+uint32_t HELPER(vfp_uqtoh)(uint64_t x, uint32_t shift, void *fpst)
{
return do_postscale_fp16(uint64_to_float64(x, fpst), shift, fpst);
}
@@ -11504,32 +11512,32 @@ static float64 do_prescale_fp16(float16 f, int shift, float_status *fpst)
}
}
-uint32_t HELPER(vfp_toshh)(float16 x, uint32_t shift, void *fpst)
+uint32_t HELPER(vfp_toshh)(uint32_t x, uint32_t shift, void *fpst)
{
return float64_to_int16(do_prescale_fp16(x, shift, fpst), fpst);
}
-uint32_t HELPER(vfp_touhh)(float16 x, uint32_t shift, void *fpst)
+uint32_t HELPER(vfp_touhh)(uint32_t x, uint32_t shift, void *fpst)
{
return float64_to_uint16(do_prescale_fp16(x, shift, fpst), fpst);
}
-uint32_t HELPER(vfp_toslh)(float16 x, uint32_t shift, void *fpst)
+uint32_t HELPER(vfp_toslh)(uint32_t x, uint32_t shift, void *fpst)
{
return float64_to_int32(do_prescale_fp16(x, shift, fpst), fpst);
}
-uint32_t HELPER(vfp_toulh)(float16 x, uint32_t shift, void *fpst)
+uint32_t HELPER(vfp_toulh)(uint32_t x, uint32_t shift, void *fpst)
{
return float64_to_uint32(do_prescale_fp16(x, shift, fpst), fpst);
}
-uint64_t HELPER(vfp_tosqh)(float16 x, uint32_t shift, void *fpst)
+uint64_t HELPER(vfp_tosqh)(uint32_t x, uint32_t shift, void *fpst)
{
return float64_to_int64(do_prescale_fp16(x, shift, fpst), fpst);
}
-uint64_t HELPER(vfp_touqh)(float16 x, uint32_t shift, void *fpst)
+uint64_t HELPER(vfp_touqh)(uint32_t x, uint32_t shift, void *fpst)
{
return float64_to_uint64(do_prescale_fp16(x, shift, fpst), fpst);
}
@@ -11565,7 +11573,7 @@ uint32_t HELPER(set_neon_rmode)(uint32_t rmode, CPUARMState *env)
}
/* Half precision conversions. */
-float32 HELPER(vfp_fcvt_f16_to_f32)(float16 a, void *fpstp, uint32_t ahp_mode)
+float32 HELPER(vfp_fcvt_f16_to_f32)(uint32_t a, void *fpstp, uint32_t ahp_mode)
{
/* Squash FZ16 to 0 for the duration of conversion. In this case,
* it would affect flushing input denormals.
@@ -11578,7 +11586,7 @@ float32 HELPER(vfp_fcvt_f16_to_f32)(float16 a, void *fpstp, uint32_t ahp_mode)
return r;
}
-float16 HELPER(vfp_fcvt_f32_to_f16)(float32 a, void *fpstp, uint32_t ahp_mode)
+uint32_t HELPER(vfp_fcvt_f32_to_f16)(float32 a, void *fpstp, uint32_t ahp_mode)
{
/* Squash FZ16 to 0 for the duration of conversion. In this case,
* it would affect flushing output denormals.
@@ -11591,7 +11599,7 @@ float16 HELPER(vfp_fcvt_f32_to_f16)(float32 a, void *fpstp, uint32_t ahp_mode)
return r;
}
-float64 HELPER(vfp_fcvt_f16_to_f64)(float16 a, void *fpstp, uint32_t ahp_mode)
+float64 HELPER(vfp_fcvt_f16_to_f64)(uint32_t a, void *fpstp, uint32_t ahp_mode)
{
/* Squash FZ16 to 0 for the duration of conversion. In this case,
* it would affect flushing input denormals.
@@ -11604,7 +11612,7 @@ float64 HELPER(vfp_fcvt_f16_to_f64)(float16 a, void *fpstp, uint32_t ahp_mode)
return r;
}
-float16 HELPER(vfp_fcvt_f64_to_f16)(float64 a, void *fpstp, uint32_t ahp_mode)
+uint32_t HELPER(vfp_fcvt_f64_to_f16)(float64 a, void *fpstp, uint32_t ahp_mode)
{
/* Squash FZ16 to 0 for the duration of conversion. In this case,
* it would affect flushing output denormals.
@@ -11742,7 +11750,7 @@ static bool round_to_inf(float_status *fpst, bool sign_bit)
g_assert_not_reached();
}
-float16 HELPER(recpe_f16)(float16 input, void *fpstp)
+uint32_t HELPER(recpe_f16)(uint32_t input, void *fpstp)
{
float_status *fpst = fpstp;
float16 f16 = float16_squash_input_denormal(input, fpst);
@@ -11937,7 +11945,7 @@ static uint64_t recip_sqrt_estimate(int *exp , int exp_off, uint64_t frac)
return extract64(estimate, 0, 8) << 44;
}
-float16 HELPER(rsqrte_f16)(float16 input, void *fpstp)
+uint32_t HELPER(rsqrte_f16)(uint32_t input, void *fpstp)
{
float_status *s = fpstp;
float16 f16 = float16_squash_input_denormal(input, s);
diff --git a/target/arm/iwmmxt_helper.c b/target/arm/iwmmxt_helper.c
index 7d87e1a0a8..f6a4fc5b7f 100644
--- a/target/arm/iwmmxt_helper.c
+++ b/target/arm/iwmmxt_helper.c
@@ -22,7 +22,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "exec/exec-all.h"
#include "exec/helper-proto.h"
/* iwMMXt macros extracted from GNU gdb. */
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 5141d0adc5..98f5006323 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -664,7 +664,8 @@ int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
/* MSI doorbell address is translated by an IOMMU */
rcu_read_lock();
- mr = address_space_translate(as, address, &xlat, &len, true);
+ mr = address_space_translate(as, address, &xlat, &len, true,
+ MEMTXATTRS_UNSPECIFIED);
if (!mr) {
goto unlock;
}
diff --git a/target/arm/neon_helper.c b/target/arm/neon_helper.c
index a1ec6537eb..c2c6491a83 100644
--- a/target/arm/neon_helper.c
+++ b/target/arm/neon_helper.c
@@ -9,7 +9,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "exec/exec-all.h"
#include "exec/helper-proto.h"
#include "fpu/softfloat.h"
diff --git a/target/arm/psci.c b/target/arm/psci.c
index eb7b88e926..a74d78802a 100644
--- a/target/arm/psci.c
+++ b/target/arm/psci.c
@@ -22,7 +22,6 @@
#include "sysemu/sysemu.h"
#include "internals.h"
#include "arm-powerctl.h"
-#include "exec/exec-all.h"
bool arm_is_psci_call(ARMCPU *cpu, int excp_type)
{
diff --git a/target/arm/vec_helper.c b/target/arm/vec_helper.c
index ec705cfca5..25e209da31 100644
--- a/target/arm/vec_helper.c
+++ b/target/arm/vec_helper.c
@@ -19,7 +19,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "exec/exec-all.h"
#include "exec/helper-proto.h"
#include "tcg/tcg-gvec-desc.h"
#include "fpu/softfloat.h"
diff --git a/target/cris/cpu.c b/target/cris/cpu.c
index db8d0884a1..a23aba2688 100644
--- a/target/cris/cpu.c
+++ b/target/cris/cpu.c
@@ -26,7 +26,6 @@
#include "cpu.h"
#include "qemu-common.h"
#include "mmu.h"
-#include "exec/exec-all.h"
static void cris_cpu_set_pc(CPUState *cs, vaddr value)
diff --git a/target/hppa/helper.c b/target/hppa/helper.c
index 858ec205b6..6539061e52 100644
--- a/target/hppa/helper.c
+++ b/target/hppa/helper.c
@@ -20,7 +20,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "exec/exec-all.h"
#include "fpu/softfloat.h"
#include "exec/helper-proto.h"
diff --git a/target/hppa/int_helper.c b/target/hppa/int_helper.c
index 787f3d6357..8d5edd3a20 100644
--- a/target/hppa/int_helper.c
+++ b/target/hppa/int_helper.c
@@ -19,8 +19,8 @@
#include "qemu/osdep.h"
#include "qemu/main-loop.h"
+#include "qemu/log.h"
#include "cpu.h"
-#include "exec/exec-all.h"
#include "exec/helper-proto.h"
#include "qom/cpu.h"
diff --git a/target/i386/hax-all.c b/target/i386/hax-all.c
index cad7531406..d2e512856b 100644
--- a/target/i386/hax-all.c
+++ b/target/i386/hax-all.c
@@ -26,8 +26,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "exec/address-spaces.h"
-#include "exec/exec-all.h"
-#include "exec/ioport.h"
#include "qemu-common.h"
#include "hax-i386.h"
diff --git a/target/i386/hax-mem.c b/target/i386/hax-mem.c
index f46e85544d..5c37e94caa 100644
--- a/target/i386/hax-mem.c
+++ b/target/i386/hax-mem.c
@@ -11,7 +11,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "exec/address-spaces.h"
-#include "exec/exec-all.h"
#include "qemu/error-report.h"
#include "target/i386/hax-i386.h"
diff --git a/target/i386/hax-windows.c b/target/i386/hax-windows.c
index b1ac737ae4..5729ad9b48 100644
--- a/target/i386/hax-windows.c
+++ b/target/i386/hax-windows.c
@@ -12,7 +12,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "exec/exec-all.h"
#include "hax-i386.h"
/*
diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c
index c36753954b..df69e6d0a7 100644
--- a/target/i386/hvf/hvf.c
+++ b/target/i386/hvf/hvf.c
@@ -65,8 +65,6 @@
#include <Hypervisor/hv_vmx.h>
#include "exec/address-spaces.h"
-#include "exec/exec-all.h"
-#include "exec/ioport.h"
#include "hw/i386/apic_internal.h"
#include "hw/boards.h"
#include "qemu/main-loop.h"
diff --git a/target/i386/hvf/x86_task.c b/target/i386/hvf/x86_task.c
index 4abf3db25e..7099335e89 100644
--- a/target/i386/hvf/x86_task.c
+++ b/target/i386/hvf/x86_task.c
@@ -26,9 +26,6 @@
#include <Hypervisor/hv.h>
#include <Hypervisor/hv_vmx.h>
-#include "exec/address-spaces.h"
-#include "exec/exec-all.h"
-#include "exec/ioport.h"
#include "hw/i386/apic_internal.h"
#include "hw/boards.h"
#include "qemu/main-loop.h"
diff --git a/target/i386/kvm.c b/target/i386/kvm.c
index 6511329d11..44f70733e7 100644
--- a/target/i386/kvm.c
+++ b/target/i386/kvm.c
@@ -40,7 +40,6 @@
#include "hw/i386/intel_iommu.h"
#include "hw/i386/x86-iommu.h"
-#include "exec/ioport.h"
#include "hw/pci/pci.h"
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
@@ -387,7 +386,7 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function,
ret &= ~(1U << KVM_FEATURE_PV_UNHALT);
}
} else if (function == KVM_CPUID_FEATURES && reg == R_EDX) {
- ret |= 1U << KVM_HINTS_DEDICATED;
+ ret |= 1U << KVM_HINTS_REALTIME;
found = 1;
}
diff --git a/target/i386/whpx-all.c b/target/i386/whpx-all.c
index 58435178a4..6b42096698 100644
--- a/target/i386/whpx-all.c
+++ b/target/i386/whpx-all.c
@@ -11,7 +11,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "exec/address-spaces.h"
-#include "exec/exec-all.h"
#include "exec/ioport.h"
#include "qemu-common.h"
#include "strings.h"
@@ -25,6 +24,7 @@
#include "qemu/queue.h"
#include "qapi/error.h"
#include "migration/blocker.h"
+#include "whp-dispatch.h"
#include <WinHvPlatform.h>
#include <WinHvEmulation.h>
@@ -160,8 +160,11 @@ struct whpx_vcpu {
};
static bool whpx_allowed;
+static bool whp_dispatch_initialized;
+static HMODULE hWinHvPlatform, hWinHvEmulation;
struct whpx_state whpx_global;
+struct WHPDispatch whp_dispatch;
/*
@@ -220,24 +223,31 @@ static void whpx_set_registers(CPUState *cpu)
struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr);
X86CPU *x86_cpu = X86_CPU(cpu);
- struct whpx_register_set vcxt = {0};
+ struct whpx_register_set vcxt;
HRESULT hr;
- int idx = 0;
+ int idx;
+ int idx_next;
int i;
int v86, r86;
assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));
+ memset(&vcxt, 0, sizeof(struct whpx_register_set));
+
v86 = (env->eflags & VM_MASK);
r86 = !(env->cr[0] & CR0_PE_MASK);
vcpu->tpr = cpu_get_apic_tpr(x86_cpu->apic_state);
vcpu->apic_base = cpu_get_apic_base(x86_cpu->apic_state);
+ idx = 0;
+
/* Indexes for first 16 registers match between HV and QEMU definitions */
- for (idx = 0; idx < CPU_NB_REGS64; idx += 1) {
- vcxt.values[idx].Reg64 = env->regs[idx];
+ idx_next = 16;
+ for (idx = 0; idx < CPU_NB_REGS; idx += 1) {
+ vcxt.values[idx].Reg64 = (uint64_t)env->regs[idx];
}
+ idx = idx_next;
/* Same goes for RIP and RFLAGS */
assert(whpx_register_names[idx] == WHvX64RegisterRip);
@@ -284,10 +294,12 @@ static void whpx_set_registers(CPUState *cpu)
/* 16 XMM registers */
assert(whpx_register_names[idx] == WHvX64RegisterXmm0);
- for (i = 0; i < 16; i += 1, idx += 1) {
+ idx_next = idx + 16;
+ for (i = 0; i < sizeof(env->xmm_regs) / sizeof(ZMMReg); i += 1, idx += 1) {
vcxt.values[idx].Reg128.Low64 = env->xmm_regs[i].ZMM_Q(0);
vcxt.values[idx].Reg128.High64 = env->xmm_regs[i].ZMM_Q(1);
}
+ idx = idx_next;
/* 8 FP registers */
assert(whpx_register_names[idx] == WHvX64RegisterFpMmx0);
@@ -355,10 +367,11 @@ static void whpx_set_registers(CPUState *cpu)
assert(idx == RTL_NUMBER_OF(whpx_register_names));
- hr = WHvSetVirtualProcessorRegisters(whpx->partition, cpu->cpu_index,
- whpx_register_names,
- RTL_NUMBER_OF(whpx_register_names),
- &vcxt.values[0]);
+ hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
+ whpx->partition, cpu->cpu_index,
+ whpx_register_names,
+ RTL_NUMBER_OF(whpx_register_names),
+ &vcxt.values[0]);
if (FAILED(hr)) {
error_report("WHPX: Failed to set virtual processor context, hr=%08lx",
@@ -377,24 +390,30 @@ static void whpx_get_registers(CPUState *cpu)
struct whpx_register_set vcxt;
uint64_t tpr, apic_base;
HRESULT hr;
- int idx = 0;
+ int idx;
+ int idx_next;
int i;
assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));
- hr = WHvGetVirtualProcessorRegisters(whpx->partition, cpu->cpu_index,
- whpx_register_names,
- RTL_NUMBER_OF(whpx_register_names),
- &vcxt.values[0]);
+ hr = whp_dispatch.WHvGetVirtualProcessorRegisters(
+ whpx->partition, cpu->cpu_index,
+ whpx_register_names,
+ RTL_NUMBER_OF(whpx_register_names),
+ &vcxt.values[0]);
if (FAILED(hr)) {
error_report("WHPX: Failed to get virtual processor context, hr=%08lx",
hr);
}
+ idx = 0;
+
/* Indexes for first 16 registers match between HV and QEMU definitions */
- for (idx = 0; idx < CPU_NB_REGS64; idx += 1) {
+ idx_next = 16;
+ for (idx = 0; idx < CPU_NB_REGS; idx += 1) {
env->regs[idx] = vcxt.values[idx].Reg64;
}
+ idx = idx_next;
/* Same goes for RIP and RFLAGS */
assert(whpx_register_names[idx] == WHvX64RegisterRip);
@@ -441,10 +460,12 @@ static void whpx_get_registers(CPUState *cpu)
/* 16 XMM registers */
assert(whpx_register_names[idx] == WHvX64RegisterXmm0);
- for (i = 0; i < 16; i += 1, idx += 1) {
+ idx_next = idx + 16;
+ for (i = 0; i < sizeof(env->xmm_regs) / sizeof(ZMMReg); i += 1, idx += 1) {
env->xmm_regs[i].ZMM_Q(0) = vcxt.values[idx].Reg128.Low64;
env->xmm_regs[i].ZMM_Q(1) = vcxt.values[idx].Reg128.High64;
}
+ idx = idx_next;
/* 8 FP registers */
assert(whpx_register_names[idx] == WHvX64RegisterFpMmx0);
@@ -545,9 +566,10 @@ static HRESULT CALLBACK whpx_emu_getreg_callback(
struct whpx_state *whpx = &whpx_global;
CPUState *cpu = (CPUState *)ctx;
- hr = WHvGetVirtualProcessorRegisters(whpx->partition, cpu->cpu_index,
- RegisterNames, RegisterCount,
- RegisterValues);
+ hr = whp_dispatch.WHvGetVirtualProcessorRegisters(
+ whpx->partition, cpu->cpu_index,
+ RegisterNames, RegisterCount,
+ RegisterValues);
if (FAILED(hr)) {
error_report("WHPX: Failed to get virtual processor registers,"
" hr=%08lx", hr);
@@ -566,9 +588,10 @@ static HRESULT CALLBACK whpx_emu_setreg_callback(
struct whpx_state *whpx = &whpx_global;
CPUState *cpu = (CPUState *)ctx;
- hr = WHvSetVirtualProcessorRegisters(whpx->partition, cpu->cpu_index,
- RegisterNames, RegisterCount,
- RegisterValues);
+ hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
+ whpx->partition, cpu->cpu_index,
+ RegisterNames, RegisterCount,
+ RegisterValues);
if (FAILED(hr)) {
error_report("WHPX: Failed to set virtual processor registers,"
" hr=%08lx", hr);
@@ -595,8 +618,8 @@ static HRESULT CALLBACK whpx_emu_translate_callback(
CPUState *cpu = (CPUState *)ctx;
WHV_TRANSLATE_GVA_RESULT res;
- hr = WHvTranslateGva(whpx->partition, cpu->cpu_index,
- Gva, TranslateFlags, &res, Gpa);
+ hr = whp_dispatch.WHvTranslateGva(whpx->partition, cpu->cpu_index,
+ Gva, TranslateFlags, &res, Gpa);
if (FAILED(hr)) {
error_report("WHPX: Failed to translate GVA, hr=%08lx", hr);
} else {
@@ -621,16 +644,18 @@ static int whpx_handle_mmio(CPUState *cpu, WHV_MEMORY_ACCESS_CONTEXT *ctx)
struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
WHV_EMULATOR_STATUS emu_status;
- hr = WHvEmulatorTryMmioEmulation(vcpu->emulator, cpu,
- &vcpu->exit_ctx.VpContext, ctx,
- &emu_status);
+ hr = whp_dispatch.WHvEmulatorTryMmioEmulation(
+ vcpu->emulator, cpu,
+ &vcpu->exit_ctx.VpContext, ctx,
+ &emu_status);
if (FAILED(hr)) {
error_report("WHPX: Failed to parse MMIO access, hr=%08lx", hr);
return -1;
}
if (!emu_status.EmulationSuccessful) {
- error_report("WHPX: Failed to emulate MMIO access");
+ error_report("WHPX: Failed to emulate MMIO access with"
+ " EmulatorReturnStatus: %u", emu_status.AsUINT32);
return -1;
}
@@ -644,16 +669,18 @@ static int whpx_handle_portio(CPUState *cpu,
struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
WHV_EMULATOR_STATUS emu_status;
- hr = WHvEmulatorTryIoEmulation(vcpu->emulator, cpu,
- &vcpu->exit_ctx.VpContext, ctx,
- &emu_status);
+ hr = whp_dispatch.WHvEmulatorTryIoEmulation(
+ vcpu->emulator, cpu,
+ &vcpu->exit_ctx.VpContext, ctx,
+ &emu_status);
if (FAILED(hr)) {
error_report("WHPX: Failed to parse PortIO access, hr=%08lx", hr);
return -1;
}
if (!emu_status.EmulationSuccessful) {
- error_report("WHPX: Failed to emulate PortMMIO access");
+ error_report("WHPX: Failed to emulate PortIO access with"
+ " EmulatorReturnStatus: %u", emu_status.AsUINT32);
return -1;
}
@@ -687,11 +714,14 @@ static void whpx_vcpu_pre_run(CPUState *cpu)
X86CPU *x86_cpu = X86_CPU(cpu);
int irq;
uint8_t tpr;
- WHV_X64_PENDING_INTERRUPTION_REGISTER new_int = {0};
+ WHV_X64_PENDING_INTERRUPTION_REGISTER new_int;
UINT32 reg_count = 0;
- WHV_REGISTER_VALUE reg_values[3] = {0};
+ WHV_REGISTER_VALUE reg_values[3];
WHV_REGISTER_NAME reg_names[3];
+ memset(&new_int, 0, sizeof(new_int));
+ memset(reg_values, 0, sizeof(reg_values));
+
qemu_mutex_lock_iothread();
/* Inject NMI */
@@ -768,8 +798,9 @@ static void whpx_vcpu_pre_run(CPUState *cpu)
qemu_mutex_unlock_iothread();
if (reg_count) {
- hr = WHvSetVirtualProcessorRegisters(whpx->partition, cpu->cpu_index,
- reg_names, reg_count, reg_values);
+ hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
+ whpx->partition, cpu->cpu_index,
+ reg_names, reg_count, reg_values);
if (FAILED(hr)) {
error_report("WHPX: Failed to set interrupt state registers,"
" hr=%08lx", hr);
@@ -877,8 +908,9 @@ static int whpx_vcpu_run(CPUState *cpu)
whpx_vcpu_kick(cpu);
}
- hr = WHvRunVirtualProcessor(whpx->partition, cpu->cpu_index,
- &vcpu->exit_ctx, sizeof(vcpu->exit_ctx));
+ hr = whp_dispatch.WHvRunVirtualProcessor(
+ whpx->partition, cpu->cpu_index,
+ &vcpu->exit_ctx, sizeof(vcpu->exit_ctx));
if (FAILED(hr)) {
error_report("WHPX: Failed to exec a virtual processor,"
@@ -912,11 +944,13 @@ static int whpx_vcpu_run(CPUState *cpu)
break;
case WHvRunVpExitReasonX64Cpuid: {
- WHV_REGISTER_VALUE reg_values[5] = {0};
+ WHV_REGISTER_VALUE reg_values[5];
WHV_REGISTER_NAME reg_names[5];
UINT32 reg_count = 5;
UINT64 rip, rax, rcx, rdx, rbx;
+ memset(reg_values, 0, sizeof(reg_values));
+
rip = vcpu->exit_ctx.VpContext.Rip +
vcpu->exit_ctx.VpContext.InstructionLength;
switch (vcpu->exit_ctx.CpuidAccess.Rax) {
@@ -949,11 +983,11 @@ static int whpx_vcpu_run(CPUState *cpu)
reg_values[3].Reg64 = rdx;
reg_values[4].Reg64 = rbx;
- hr = WHvSetVirtualProcessorRegisters(whpx->partition,
- cpu->cpu_index,
- reg_names,
- reg_count,
- reg_values);
+ hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
+ whpx->partition, cpu->cpu_index,
+ reg_names,
+ reg_count,
+ reg_values);
if (FAILED(hr)) {
error_report("WHPX: Failed to set CpuidAccess state registers,"
@@ -1065,8 +1099,8 @@ int whpx_init_vcpu(CPUState *cpu)
(void)migrate_add_blocker(whpx_migration_blocker, &local_error);
if (local_error) {
error_report_err(local_error);
- error_free(whpx_migration_blocker);
migrate_del_blocker(whpx_migration_blocker);
+ error_free(whpx_migration_blocker);
return -EINVAL;
}
}
@@ -1078,7 +1112,9 @@ int whpx_init_vcpu(CPUState *cpu)
return -ENOMEM;
}
- hr = WHvEmulatorCreateEmulator(&whpx_emu_callbacks, &vcpu->emulator);
+ hr = whp_dispatch.WHvEmulatorCreateEmulator(
+ &whpx_emu_callbacks,
+ &vcpu->emulator);
if (FAILED(hr)) {
error_report("WHPX: Failed to setup instruction completion support,"
" hr=%08lx", hr);
@@ -1086,11 +1122,12 @@ int whpx_init_vcpu(CPUState *cpu)
return -EINVAL;
}
- hr = WHvCreateVirtualProcessor(whpx->partition, cpu->cpu_index, 0);
+ hr = whp_dispatch.WHvCreateVirtualProcessor(
+ whpx->partition, cpu->cpu_index, 0);
if (FAILED(hr)) {
error_report("WHPX: Failed to create a virtual processor,"
" hr=%08lx", hr);
- WHvEmulatorDestroyEmulator(vcpu->emulator);
+ whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator);
g_free(vcpu);
return -EINVAL;
}
@@ -1131,8 +1168,8 @@ void whpx_destroy_vcpu(CPUState *cpu)
struct whpx_state *whpx = &whpx_global;
struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
- WHvDeleteVirtualProcessor(whpx->partition, cpu->cpu_index);
- WHvEmulatorDestroyEmulator(vcpu->emulator);
+ whp_dispatch.WHvDeleteVirtualProcessor(whpx->partition, cpu->cpu_index);
+ whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator);
g_free(cpu->hax_vcpu);
return;
}
@@ -1140,7 +1177,8 @@ void whpx_destroy_vcpu(CPUState *cpu)
void whpx_vcpu_kick(CPUState *cpu)
{
struct whpx_state *whpx = &whpx_global;
- WHvCancelRunVirtualProcessor(whpx->partition, cpu->cpu_index, 0);
+ whp_dispatch.WHvCancelRunVirtualProcessor(
+ whpx->partition, cpu->cpu_index, 0);
}
/*
@@ -1166,24 +1204,24 @@ static void whpx_update_mapping(hwaddr start_pa, ram_addr_t size,
*/
if (add) {
- hr = WHvMapGpaRange(whpx->partition,
- host_va,
- start_pa,
- size,
- (WHvMapGpaRangeFlagRead |
- WHvMapGpaRangeFlagExecute |
- (rom ? 0 : WHvMapGpaRangeFlagWrite)));
+ hr = whp_dispatch.WHvMapGpaRange(whpx->partition,
+ host_va,
+ start_pa,
+ size,
+ (WHvMapGpaRangeFlagRead |
+ WHvMapGpaRangeFlagExecute |
+ (rom ? 0 : WHvMapGpaRangeFlagWrite)));
} else {
- hr = WHvUnmapGpaRange(whpx->partition,
- start_pa,
- size);
+ hr = whp_dispatch.WHvUnmapGpaRange(whpx->partition,
+ start_pa,
+ size);
}
if (FAILED(hr)) {
error_report("WHPX: Failed to %s GPA range '%s' PA:%p, Size:%p bytes,"
" Host:%p, hr=%08lx",
(add ? "MAP" : "UNMAP"), name,
- (void *)start_pa, (void *)size, host_va, hr);
+ (void *)(uintptr_t)start_pa, (void *)size, host_va, hr);
}
}
@@ -1214,8 +1252,8 @@ static void whpx_process_section(MemoryRegionSection *section, int add)
host_va = (uintptr_t)memory_region_get_ram_ptr(mr)
+ section->offset_within_region + delta;
- whpx_update_mapping(start_pa, size, (void *)host_va, add,
- memory_region_is_rom(mr), mr->name);
+ whpx_update_mapping(start_pa, size, (void *)(uintptr_t)host_va, add,
+ memory_region_is_rom(mr), mr->name);
}
static void whpx_region_add(MemoryListener *listener,
@@ -1290,18 +1328,24 @@ static int whpx_accel_init(MachineState *ms)
whpx = &whpx_global;
+ if (!init_whp_dispatch()) {
+ ret = -ENOSYS;
+ goto error;
+ }
+
memset(whpx, 0, sizeof(struct whpx_state));
whpx->mem_quota = ms->ram_size;
- hr = WHvGetCapability(WHvCapabilityCodeHypervisorPresent, &whpx_cap,
- sizeof(whpx_cap), &whpx_cap_size);
+ hr = whp_dispatch.WHvGetCapability(
+ WHvCapabilityCodeHypervisorPresent, &whpx_cap,
+ sizeof(whpx_cap), &whpx_cap_size);
if (FAILED(hr) || !whpx_cap.HypervisorPresent) {
error_report("WHPX: No accelerator found, hr=%08lx", hr);
ret = -ENOSPC;
goto error;
}
- hr = WHvCreatePartition(&whpx->partition);
+ hr = whp_dispatch.WHvCreatePartition(&whpx->partition);
if (FAILED(hr)) {
error_report("WHPX: Failed to create partition, hr=%08lx", hr);
ret = -EINVAL;
@@ -1310,10 +1354,11 @@ static int whpx_accel_init(MachineState *ms)
memset(&prop, 0, sizeof(WHV_PARTITION_PROPERTY));
prop.ProcessorCount = smp_cpus;
- hr = WHvSetPartitionProperty(whpx->partition,
- WHvPartitionPropertyCodeProcessorCount,
- &prop,
- sizeof(WHV_PARTITION_PROPERTY));
+ hr = whp_dispatch.WHvSetPartitionProperty(
+ whpx->partition,
+ WHvPartitionPropertyCodeProcessorCount,
+ &prop,
+ sizeof(WHV_PARTITION_PROPERTY));
if (FAILED(hr)) {
error_report("WHPX: Failed to set partition core count to %d,"
@@ -1324,10 +1369,11 @@ static int whpx_accel_init(MachineState *ms)
memset(&prop, 0, sizeof(WHV_PARTITION_PROPERTY));
prop.ExtendedVmExits.X64CpuidExit = 1;
- hr = WHvSetPartitionProperty(whpx->partition,
- WHvPartitionPropertyCodeExtendedVmExits,
- &prop,
- sizeof(WHV_PARTITION_PROPERTY));
+ hr = whp_dispatch.WHvSetPartitionProperty(
+ whpx->partition,
+ WHvPartitionPropertyCodeExtendedVmExits,
+ &prop,
+ sizeof(WHV_PARTITION_PROPERTY));
if (FAILED(hr)) {
error_report("WHPX: Failed to enable partition extended X64CpuidExit"
@@ -1337,11 +1383,11 @@ static int whpx_accel_init(MachineState *ms)
}
UINT32 cpuidExitList[] = {1};
- hr = WHvSetPartitionProperty(whpx->partition,
- WHvPartitionPropertyCodeCpuidExitList,
- cpuidExitList,
- RTL_NUMBER_OF(cpuidExitList) * sizeof(UINT32));
-
+ hr = whp_dispatch.WHvSetPartitionProperty(
+ whpx->partition,
+ WHvPartitionPropertyCodeCpuidExitList,
+ cpuidExitList,
+ RTL_NUMBER_OF(cpuidExitList) * sizeof(UINT32));
if (FAILED(hr)) {
error_report("WHPX: Failed to set partition CpuidExitList hr=%08lx",
hr);
@@ -1349,7 +1395,7 @@ static int whpx_accel_init(MachineState *ms)
goto error;
}
- hr = WHvSetupPartition(whpx->partition);
+ hr = whp_dispatch.WHvSetupPartition(whpx->partition);
if (FAILED(hr)) {
error_report("WHPX: Failed to setup partition, hr=%08lx", hr);
ret = -EINVAL;
@@ -1366,7 +1412,7 @@ static int whpx_accel_init(MachineState *ms)
error:
if (NULL != whpx->partition) {
- WHvDeletePartition(whpx->partition);
+ whp_dispatch.WHvDeletePartition(whpx->partition);
whpx->partition = NULL;
}
@@ -1398,4 +1444,54 @@ static void whpx_type_init(void)
type_register_static(&whpx_accel_type);
}
+bool init_whp_dispatch(void)
+{
+ const char *lib_name;
+ HMODULE hLib;
+
+ if (whp_dispatch_initialized) {
+ return true;
+ }
+
+ #define WHP_LOAD_FIELD(return_type, function_name, signature) \
+ whp_dispatch.function_name = \
+ (function_name ## _t)GetProcAddress(hLib, #function_name); \
+ if (!whp_dispatch.function_name) { \
+ error_report("Could not load function %s from library %s.", \
+ #function_name, lib_name); \
+ goto error; \
+ } \
+
+ lib_name = "WinHvPlatform.dll";
+ hWinHvPlatform = LoadLibrary(lib_name);
+ if (!hWinHvPlatform) {
+ error_report("Could not load library %s.", lib_name);
+ goto error;
+ }
+ hLib = hWinHvPlatform;
+ LIST_WINHVPLATFORM_FUNCTIONS(WHP_LOAD_FIELD)
+
+ lib_name = "WinHvEmulation.dll";
+ hWinHvEmulation = LoadLibrary(lib_name);
+ if (!hWinHvEmulation) {
+ error_report("Could not load library %s.", lib_name);
+ goto error;
+ }
+ hLib = hWinHvEmulation;
+ LIST_WINHVEMULATION_FUNCTIONS(WHP_LOAD_FIELD)
+
+ whp_dispatch_initialized = true;
+ return true;
+
+ error:
+
+ if (hWinHvPlatform) {
+ FreeLibrary(hWinHvPlatform);
+ }
+ if (hWinHvEmulation) {
+ FreeLibrary(hWinHvEmulation);
+ }
+ return false;
+}
+
type_init(whpx_type_init);
diff --git a/target/lm32/cpu.c b/target/lm32/cpu.c
index 0003152469..b7499cb627 100644
--- a/target/lm32/cpu.c
+++ b/target/lm32/cpu.c
@@ -22,7 +22,6 @@
#include "qapi/error.h"
#include "cpu.h"
#include "qemu-common.h"
-#include "exec/exec-all.h"
static void lm32_cpu_set_pc(CPUState *cs, vaddr value)
diff --git a/target/lm32/op_helper.c b/target/lm32/op_helper.c
index 577f8306e3..234d55e056 100644
--- a/target/lm32/op_helper.c
+++ b/target/lm32/op_helper.c
@@ -102,12 +102,16 @@ void HELPER(wcsr_dc)(CPULM32State *env, uint32_t dc)
void HELPER(wcsr_im)(CPULM32State *env, uint32_t im)
{
+ qemu_mutex_lock_iothread();
lm32_pic_set_im(env->pic_state, im);
+ qemu_mutex_unlock_iothread();
}
void HELPER(wcsr_ip)(CPULM32State *env, uint32_t im)
{
+ qemu_mutex_lock_iothread();
lm32_pic_set_ip(env->pic_state, im);
+ qemu_mutex_unlock_iothread();
}
void HELPER(wcsr_jtx)(CPULM32State *env, uint32_t jtx)
diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
index a4ed8770aa..582e3a73b3 100644
--- a/target/m68k/cpu.c
+++ b/target/m68k/cpu.c
@@ -23,7 +23,6 @@
#include "cpu.h"
#include "qemu-common.h"
#include "migration/vmstate.h"
-#include "exec/exec-all.h"
#include "fpu/softfloat.h"
static void m68k_cpu_set_pc(CPUState *cs, vaddr value)
diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c
index 4dc1404800..9b546a2c18 100644
--- a/target/microblaze/cpu.c
+++ b/target/microblaze/cpu.c
@@ -72,6 +72,9 @@ static const struct {
{NULL, 0},
};
+/* If no specific version gets selected, default to the following. */
+#define DEFAULT_CPU_VERSION "10.0"
+
static void mb_cpu_set_pc(CPUState *cs, vaddr value)
{
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
@@ -125,6 +128,7 @@ static void mb_cpu_reset(CPUState *s)
env->mmu.c_mmu = 3;
env->mmu.c_mmu_tlb_access = 3;
env->mmu.c_mmu_zones = 16;
+ env->mmu.c_addr_mask = MAKE_64BIT_MASK(0, cpu->cfg.addr_size);
#endif
}
@@ -141,6 +145,7 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp)
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
CPUMBState *env = &cpu->env;
uint8_t version_code = 0;
+ const char *version;
int i = 0;
Error *local_err = NULL;
@@ -150,6 +155,12 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp)
return;
}
+ if (cpu->cfg.addr_size < 32 || cpu->cfg.addr_size > 64) {
+ error_setg(errp, "addr-size %d is out of range (32 - 64)",
+ cpu->cfg.addr_size);
+ return;
+ }
+
qemu_init_vcpu(cs);
env->pvr.regs[0] = PVR0_USE_EXC_MASK \
@@ -162,8 +173,9 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp)
| PVR2_FPU_EXC_MASK \
| 0;
- for (i = 0; mb_cpu_lookup[i].name && cpu->cfg.version; i++) {
- if (strcmp(mb_cpu_lookup[i].name, cpu->cfg.version) == 0) {
+ version = cpu->cfg.version ? cpu->cfg.version : DEFAULT_CPU_VERSION;
+ for (i = 0; mb_cpu_lookup[i].name && version; i++) {
+ if (strcmp(mb_cpu_lookup[i].name, version) == 0) {
version_code = mb_cpu_lookup[i].version_id;
break;
}
@@ -195,8 +207,10 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp)
env->pvr.regs[5] |= cpu->cfg.dcache_writeback ?
PVR5_DCACHE_WRITEBACK_MASK : 0;
- env->pvr.regs[10] = 0x0c000000; /* Default to spartan 3a dsp family. */
- env->pvr.regs[11] = PVR11_USE_MMU | (16 << 17);
+ env->pvr.regs[10] = 0x0c000000 | /* Default to spartan 3a dsp family. */
+ (cpu->cfg.addr_size - 32) << PVR10_ASIZE_SHIFT;
+ env->pvr.regs[11] = (cpu->cfg.use_mmu ? PVR11_USE_MMU : 0) |
+ 16 << 17;
mcc->parent_realize(dev, errp);
}
@@ -226,6 +240,14 @@ static Property mb_properties[] = {
DEFINE_PROP_UINT32("base-vectors", MicroBlazeCPU, cfg.base_vectors, 0),
DEFINE_PROP_BOOL("use-stack-protection", MicroBlazeCPU, cfg.stackprot,
false),
+ /*
+ * This is the C_ADDR_SIZE synth-time configuration option of the
+ * MicroBlaze cores. Supported values range between 32 and 64.
+ *
+ * When set to > 32, 32bit MicroBlaze can emit load/stores
+ * with extended addressing.
+ */
+ DEFINE_PROP_UINT8("addr-size", MicroBlazeCPU, cfg.addr_size, 32),
/* If use-fpu > 0 - FPU is enabled
* If use-fpu = 2 - Floating point conversion and square root instructions
* are enabled
diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h
index 5be71bc320..3c4e0ba80a 100644
--- a/target/microblaze/cpu.h
+++ b/target/microblaze/cpu.h
@@ -23,7 +23,7 @@
#include "qemu-common.h"
#include "cpu-qom.h"
-#define TARGET_LONG_BITS 32
+#define TARGET_LONG_BITS 64
#define CPUArchState struct CPUMBState
@@ -203,6 +203,7 @@ typedef struct CPUMBState CPUMBState;
/* Target family PVR mask */
#define PVR10_TARGET_FAMILY_MASK 0xFF000000
+#define PVR10_ASIZE_SHIFT 18
/* MMU descrtiption */
#define PVR11_USE_MMU 0xC0000000
@@ -238,19 +239,19 @@ typedef struct CPUMBState CPUMBState;
struct CPUMBState {
uint32_t debug;
uint32_t btaken;
- uint32_t btarget;
+ uint64_t btarget;
uint32_t bimm;
uint32_t imm;
- uint32_t regs[33];
- uint32_t sregs[24];
+ uint32_t regs[32];
+ uint64_t sregs[14];
float_status fp_status;
/* Stack protectors. Yes, it's a hw feature. */
uint32_t slr, shr;
/* lwx/swx reserved address */
#define RES_ADDR_NONE 0xffffffff /* Use 0xffffffff to indicate no reservation */
- uint32_t res_addr;
+ target_ulong res_addr;
uint32_t res_val;
/* Internal flags. */
@@ -277,7 +278,7 @@ struct CPUMBState {
/* These fields are preserved on reset. */
struct {
- uint32_t regs[16];
+ uint32_t regs[13];
} pvr;
};
@@ -297,6 +298,7 @@ struct MicroBlazeCPU {
struct {
bool stackprot;
uint32_t base_vectors;
+ uint8_t addr_size;
uint8_t use_fpu;
uint8_t use_hw_mul;
bool use_barrel;
@@ -340,8 +342,8 @@ int cpu_mb_signal_handler(int host_signum, void *pinfo,
/* FIXME: MB uses variable pages down to 1K but linux only uses 4k. */
#define TARGET_PAGE_BITS 12
-#define TARGET_PHYS_ADDR_SPACE_BITS 32
-#define TARGET_VIRT_ADDR_SPACE_BITS 32
+#define TARGET_PHYS_ADDR_SPACE_BITS 64
+#define TARGET_VIRT_ADDR_SPACE_BITS 64
#define CPU_RESOLVING_TYPE TYPE_MICROBLAZE_CPU
@@ -358,13 +360,17 @@ int cpu_mb_signal_handler(int host_signum, void *pinfo,
static inline int cpu_mmu_index (CPUMBState *env, bool ifetch)
{
- /* Are we in nommu mode?. */
- if (!(env->sregs[SR_MSR] & MSR_VM))
- return MMU_NOMMU_IDX;
+ MicroBlazeCPU *cpu = mb_env_get_cpu(env);
- if (env->sregs[SR_MSR] & MSR_UM)
- return MMU_USER_IDX;
- return MMU_KERNEL_IDX;
+ /* Are we in nommu mode?. */
+ if (!(env->sregs[SR_MSR] & MSR_VM) || !cpu->cfg.use_mmu) {
+ return MMU_NOMMU_IDX;
+ }
+
+ if (env->sregs[SR_MSR] & MSR_UM) {
+ return MMU_USER_IDX;
+ }
+ return MMU_KERNEL_IDX;
}
int mb_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int size, int rw,
diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c
index fac6ee9263..bc753793ec 100644
--- a/target/microblaze/helper.c
+++ b/target/microblaze/helper.c
@@ -54,22 +54,12 @@ int mb_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw,
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
CPUMBState *env = &cpu->env;
unsigned int hit;
- unsigned int mmu_available;
int r = 1;
int prot;
- mmu_available = 0;
- if (cpu->cfg.use_mmu) {
- mmu_available = 1;
- if ((cpu->cfg.pvr == C_PVR_FULL) &&
- (env->pvr.regs[11] & PVR11_USE_MMU) != PVR11_USE_MMU) {
- mmu_available = 0;
- }
- }
-
/* Translate if the MMU is available and enabled. */
- if (mmu_available && (env->sregs[SR_MSR] & MSR_VM)) {
- target_ulong vaddr, paddr;
+ if (mmu_idx != MMU_NOMMU_IDX) {
+ uint32_t vaddr, paddr;
struct microblaze_mmu_lookup lu;
hit = mmu_translate(&env->mmu, &lu, address, rw, mmu_idx);
@@ -152,7 +142,8 @@ void mb_cpu_do_interrupt(CPUState *cs)
env->sregs[SR_MSR] |= MSR_EIP;
qemu_log_mask(CPU_LOG_INT,
- "hw exception at pc=%x ear=%x esr=%x iflags=%x\n",
+ "hw exception at pc=%" PRIx64 " ear=%" PRIx64 " "
+ "esr=%" PRIx64 " iflags=%x\n",
env->sregs[SR_PC], env->sregs[SR_EAR],
env->sregs[SR_ESR], env->iflags);
log_cpu_state_mask(CPU_LOG_INT, cs, 0);
@@ -175,7 +166,8 @@ void mb_cpu_do_interrupt(CPUState *cs)
/* was the branch immprefixed?. */
if (env->bimm) {
qemu_log_mask(CPU_LOG_INT,
- "bimm exception at pc=%x iflags=%x\n",
+ "bimm exception at pc=%" PRIx64 " "
+ "iflags=%x\n",
env->sregs[SR_PC], env->iflags);
env->regs[17] -= 4;
log_cpu_state_mask(CPU_LOG_INT, cs, 0);
@@ -193,7 +185,8 @@ void mb_cpu_do_interrupt(CPUState *cs)
env->sregs[SR_MSR] |= MSR_EIP;
qemu_log_mask(CPU_LOG_INT,
- "exception at pc=%x ear=%x iflags=%x\n",
+ "exception at pc=%" PRIx64 " ear=%" PRIx64 " "
+ "iflags=%x\n",
env->sregs[SR_PC], env->sregs[SR_EAR], env->iflags);
log_cpu_state_mask(CPU_LOG_INT, cs, 0);
env->iflags &= ~(IMM_FLAG | D_FLAG);
@@ -230,7 +223,8 @@ void mb_cpu_do_interrupt(CPUState *cs)
}
#endif
qemu_log_mask(CPU_LOG_INT,
- "interrupt at pc=%x msr=%x %x iflags=%x\n",
+ "interrupt at pc=%" PRIx64 " msr=%" PRIx64 " %x "
+ "iflags=%x\n",
env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags);
env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM \
@@ -248,7 +242,8 @@ void mb_cpu_do_interrupt(CPUState *cs)
assert(!(env->iflags & D_FLAG));
t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1;
qemu_log_mask(CPU_LOG_INT,
- "break at pc=%x msr=%x %x iflags=%x\n",
+ "break at pc=%" PRIx64 " msr=%" PRIx64 " %x "
+ "iflags=%x\n",
env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags);
log_cpu_state_mask(CPU_LOG_INT, cs, 0);
env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
@@ -274,9 +269,10 @@ hwaddr mb_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
CPUMBState *env = &cpu->env;
target_ulong vaddr, paddr = 0;
struct microblaze_mmu_lookup lu;
+ int mmu_idx = cpu_mmu_index(env, false);
unsigned int hit;
- if (env->sregs[SR_MSR] & MSR_VM) {
+ if (mmu_idx != MMU_NOMMU_IDX) {
hit = mmu_translate(&env->mmu, &lu, addr, 0, 0);
if (hit) {
vaddr = addr & TARGET_PAGE_MASK;
diff --git a/target/microblaze/helper.h b/target/microblaze/helper.h
index 71a6c0858d..2f8bdea22b 100644
--- a/target/microblaze/helper.h
+++ b/target/microblaze/helper.h
@@ -25,12 +25,12 @@ DEF_HELPER_3(fcmp_ge, i32, env, i32, i32)
DEF_HELPER_FLAGS_2(pcmpbf, TCG_CALL_NO_RWG_SE, i32, i32, i32)
#if !defined(CONFIG_USER_ONLY)
-DEF_HELPER_2(mmu_read, i32, env, i32)
-DEF_HELPER_3(mmu_write, void, env, i32, i32)
+DEF_HELPER_3(mmu_read, i32, env, i32, i32)
+DEF_HELPER_4(mmu_write, void, env, i32, i32, i32)
#endif
-DEF_HELPER_5(memalign, void, env, i32, i32, i32, i32)
-DEF_HELPER_2(stackprot, void, env, i32)
+DEF_HELPER_5(memalign, void, env, tl, i32, i32, i32)
+DEF_HELPER_2(stackprot, void, env, tl)
DEF_HELPER_2(get, i32, i32, i32)
DEF_HELPER_3(put, void, i32, i32, i32)
diff --git a/target/microblaze/mmu.c b/target/microblaze/mmu.c
index 9d5e6aa8a5..f4ceaea520 100644
--- a/target/microblaze/mmu.c
+++ b/target/microblaze/mmu.c
@@ -22,8 +22,6 @@
#include "cpu.h"
#include "exec/exec-all.h"
-#define D(x)
-
static unsigned int tlb_decode_size(unsigned int f)
{
static const unsigned int sizes[] = {
@@ -81,34 +79,29 @@ unsigned int mmu_translate(struct microblaze_mmu *mmu,
{
unsigned int i, hit = 0;
unsigned int tlb_ex = 0, tlb_wr = 0, tlb_zsel;
- unsigned int tlb_size;
- uint32_t tlb_tag, tlb_rpn, mask, t0;
+ uint64_t tlb_tag, tlb_rpn, mask;
+ uint32_t tlb_size, t0;
lu->err = ERR_MISS;
for (i = 0; i < ARRAY_SIZE(mmu->rams[RAM_TAG]); i++) {
- uint32_t t, d;
+ uint64_t t, d;
/* Lookup and decode. */
t = mmu->rams[RAM_TAG][i];
- D(qemu_log("TLB %d valid=%d\n", i, t & TLB_VALID));
if (t & TLB_VALID) {
tlb_size = tlb_decode_size((t & TLB_PAGESZ_MASK) >> 7);
if (tlb_size < TARGET_PAGE_SIZE) {
- qemu_log("%d pages not supported\n", tlb_size);
+ qemu_log_mask(LOG_UNIMP, "%d pages not supported\n", tlb_size);
abort();
}
- mask = ~(tlb_size - 1);
+ mask = ~((uint64_t)tlb_size - 1);
tlb_tag = t & TLB_EPN_MASK;
if ((vaddr & mask) != (tlb_tag & mask)) {
- D(qemu_log("TLB %d vaddr=%x != tag=%x\n",
- i, vaddr & mask, tlb_tag & mask));
continue;
}
if (mmu->tids[i]
&& ((mmu->regs[MMU_R_PID] & 0xff) != mmu->tids[i])) {
- D(qemu_log("TLB %d pid=%x != tid=%x\n",
- i, mmu->regs[MMU_R_PID], mmu->tids[i]));
continue;
}
@@ -123,7 +116,8 @@ unsigned int mmu_translate(struct microblaze_mmu *mmu,
t0 &= 0x3;
if (tlb_zsel > mmu->c_mmu_zones) {
- qemu_log_mask(LOG_GUEST_ERROR, "tlb zone select out of range! %d\n", tlb_zsel);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "tlb zone select out of range! %d\n", tlb_zsel);
t0 = 1; /* Ignore. */
}
@@ -164,6 +158,7 @@ unsigned int mmu_translate(struct microblaze_mmu *mmu,
tlb_rpn = d & TLB_RPN_MASK;
lu->vaddr = tlb_tag;
+ lu->paddr = tlb_rpn & mmu->c_addr_mask;
lu->paddr = tlb_rpn;
lu->size = tlb_size;
lu->err = ERR_HIT;
@@ -173,13 +168,14 @@ unsigned int mmu_translate(struct microblaze_mmu *mmu,
}
}
done:
- D(qemu_log("MMU vaddr=%x rw=%d tlb_wr=%d tlb_ex=%d hit=%d\n",
- vaddr, rw, tlb_wr, tlb_ex, hit));
+ qemu_log_mask(CPU_LOG_MMU,
+ "MMU vaddr=%" PRIx64 " rw=%d tlb_wr=%d tlb_ex=%d hit=%d\n",
+ vaddr, rw, tlb_wr, tlb_ex, hit);
return hit;
}
/* Writes/reads to the MMU's special regs end up here. */
-uint32_t mmu_read(CPUMBState *env, uint32_t rn)
+uint32_t mmu_read(CPUMBState *env, bool ext, uint32_t rn)
{
unsigned int i;
uint32_t r = 0;
@@ -188,50 +184,65 @@ uint32_t mmu_read(CPUMBState *env, uint32_t rn)
qemu_log_mask(LOG_GUEST_ERROR, "MMU access on MMU-less system\n");
return 0;
}
+ if (ext && rn != MMU_R_TLBLO) {
+ qemu_log_mask(LOG_GUEST_ERROR, "Extended access only to TLBLO.\n");
+ return 0;
+ }
switch (rn) {
/* Reads to HI/LO trig reads from the mmu rams. */
case MMU_R_TLBLO:
case MMU_R_TLBHI:
if (!(env->mmu.c_mmu_tlb_access & 1)) {
- qemu_log_mask(LOG_GUEST_ERROR, "Invalid access to MMU reg %d\n", rn);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "Invalid access to MMU reg %d\n", rn);
return 0;
}
i = env->mmu.regs[MMU_R_TLBX] & 0xff;
- r = env->mmu.rams[rn & 1][i];
+ r = extract64(env->mmu.rams[rn & 1][i], ext * 32, 32);
if (rn == MMU_R_TLBHI)
env->mmu.regs[MMU_R_PID] = env->mmu.tids[i];
break;
case MMU_R_PID:
case MMU_R_ZPR:
if (!(env->mmu.c_mmu_tlb_access & 1)) {
- qemu_log_mask(LOG_GUEST_ERROR, "Invalid access to MMU reg %d\n", rn);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "Invalid access to MMU reg %d\n", rn);
return 0;
}
r = env->mmu.regs[rn];
break;
+ case MMU_R_TLBX:
+ r = env->mmu.regs[rn];
+ break;
case MMU_R_TLBSX:
qemu_log_mask(LOG_GUEST_ERROR, "TLBSX is write-only.\n");
break;
default:
- r = env->mmu.regs[rn];
+ qemu_log_mask(LOG_GUEST_ERROR, "Invalid MMU register %d.\n", rn);
break;
}
- D(qemu_log("%s rn=%d=%x\n", __func__, rn, r));
+ qemu_log_mask(CPU_LOG_MMU, "%s rn=%d=%x\n", __func__, rn, r);
return r;
}
-void mmu_write(CPUMBState *env, uint32_t rn, uint32_t v)
+void mmu_write(CPUMBState *env, bool ext, uint32_t rn, uint32_t v)
{
MicroBlazeCPU *cpu = mb_env_get_cpu(env);
+ uint64_t tmp64;
unsigned int i;
- D(qemu_log("%s rn=%d=%x old=%x\n", __func__, rn, v, env->mmu.regs[rn]));
+ qemu_log_mask(CPU_LOG_MMU,
+ "%s rn=%d=%x old=%x\n", __func__, rn, v, env->mmu.regs[rn]);
if (env->mmu.c_mmu < 2 || !env->mmu.c_mmu_tlb_access) {
qemu_log_mask(LOG_GUEST_ERROR, "MMU access on MMU-less system\n");
return;
}
+ if (ext && rn != MMU_R_TLBLO) {
+ qemu_log_mask(LOG_GUEST_ERROR, "Extended access only to TLBLO.\n");
+ return;
+ }
switch (rn) {
/* Writes to HI/LO trig writes to the mmu rams. */
@@ -240,18 +251,19 @@ void mmu_write(CPUMBState *env, uint32_t rn, uint32_t v)
i = env->mmu.regs[MMU_R_TLBX] & 0xff;
if (rn == MMU_R_TLBHI) {
if (i < 3 && !(v & TLB_VALID) && qemu_loglevel_mask(~0))
- qemu_log_mask(LOG_GUEST_ERROR, "invalidating index %x at pc=%x\n",
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "invalidating index %x at pc=%" PRIx64 "\n",
i, env->sregs[SR_PC]);
env->mmu.tids[i] = env->mmu.regs[MMU_R_PID] & 0xff;
mmu_flush_idx(env, i);
}
- env->mmu.rams[rn & 1][i] = v;
-
- D(qemu_log("%s ram[%d][%d]=%x\n", __func__, rn & 1, i, v));
+ tmp64 = env->mmu.rams[rn & 1][i];
+ env->mmu.rams[rn & 1][i] = deposit64(tmp64, ext * 32, 32, v);
break;
case MMU_R_ZPR:
if (env->mmu.c_mmu_tlb_access <= 1) {
- qemu_log_mask(LOG_GUEST_ERROR, "Invalid access to MMU reg %d\n", rn);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "Invalid access to MMU reg %d\n", rn);
return;
}
@@ -264,7 +276,8 @@ void mmu_write(CPUMBState *env, uint32_t rn, uint32_t v)
break;
case MMU_R_PID:
if (env->mmu.c_mmu_tlb_access <= 1) {
- qemu_log_mask(LOG_GUEST_ERROR, "Invalid access to MMU reg %d\n", rn);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "Invalid access to MMU reg %d\n", rn);
return;
}
@@ -283,7 +296,8 @@ void mmu_write(CPUMBState *env, uint32_t rn, uint32_t v)
int hit;
if (env->mmu.c_mmu_tlb_access <= 1) {
- qemu_log_mask(LOG_GUEST_ERROR, "Invalid access to MMU reg %d\n", rn);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "Invalid access to MMU reg %d\n", rn);
return;
}
@@ -291,12 +305,13 @@ void mmu_write(CPUMBState *env, uint32_t rn, uint32_t v)
v & TLB_EPN_MASK, 0, cpu_mmu_index(env, false));
if (hit) {
env->mmu.regs[MMU_R_TLBX] = lu.idx;
- } else
- env->mmu.regs[MMU_R_TLBX] |= 0x80000000;
+ } else {
+ env->mmu.regs[MMU_R_TLBX] |= R_TBLX_MISS_MASK;
+ }
break;
}
default:
- env->mmu.regs[rn] = v;
+ qemu_log_mask(LOG_GUEST_ERROR, "Invalid MMU register %d.\n", rn);
break;
}
}
diff --git a/target/microblaze/mmu.h b/target/microblaze/mmu.h
index 3b7a9983d5..a4272b6356 100644
--- a/target/microblaze/mmu.h
+++ b/target/microblaze/mmu.h
@@ -28,7 +28,7 @@
#define RAM_TAG 0
/* Tag portion */
-#define TLB_EPN_MASK 0xFFFFFC00 /* Effective Page Number */
+#define TLB_EPN_MASK MAKE_64BIT_MASK(10, 64 - 10)
#define TLB_PAGESZ_MASK 0x00000380
#define TLB_PAGESZ(x) (((x) & 0x7) << 7)
#define PAGESZ_1K 0
@@ -42,7 +42,7 @@
#define TLB_VALID 0x00000040 /* Entry is valid */
/* Data portion */
-#define TLB_RPN_MASK 0xFFFFFC00 /* Real Page Number */
+#define TLB_RPN_MASK MAKE_64BIT_MASK(10, 64 - 10)
#define TLB_PERM_MASK 0x00000300
#define TLB_EX 0x00000200 /* Instruction execution allowed */
#define TLB_WR 0x00000100 /* Writes permitted */
@@ -54,20 +54,25 @@
#define TLB_M 0x00000002 /* Memory is coherent */
#define TLB_G 0x00000001 /* Memory is guarded from prefetch */
+/* TLBX */
+#define R_TBLX_MISS_SHIFT 31
+#define R_TBLX_MISS_MASK (1U << R_TBLX_MISS_SHIFT)
+
#define TLB_ENTRIES 64
struct microblaze_mmu
{
/* Data and tag brams. */
- uint32_t rams[2][TLB_ENTRIES];
+ uint64_t rams[2][TLB_ENTRIES];
/* We keep a separate ram for the tids to avoid the 48 bit tag width. */
uint8_t tids[TLB_ENTRIES];
/* Control flops. */
- uint32_t regs[8];
+ uint32_t regs[3];
int c_mmu;
int c_mmu_tlb_access;
int c_mmu_zones;
+ uint64_t c_addr_mask; /* Mask to apply to physical addresses. */
};
struct microblaze_mmu_lookup
@@ -85,6 +90,6 @@ struct microblaze_mmu_lookup
unsigned int mmu_translate(struct microblaze_mmu *mmu,
struct microblaze_mmu_lookup *lu,
target_ulong vaddr, int rw, int mmu_idx);
-uint32_t mmu_read(CPUMBState *env, uint32_t rn);
-void mmu_write(CPUMBState *env, uint32_t rn, uint32_t v);
+uint32_t mmu_read(CPUMBState *env, bool ea, uint32_t rn);
+void mmu_write(CPUMBState *env, bool ea, uint32_t rn, uint32_t v);
void mmu_init(struct microblaze_mmu *mmu);
diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c
index 1b4fe796e7..7cdbbcccae 100644
--- a/target/microblaze/op_helper.c
+++ b/target/microblaze/op_helper.c
@@ -94,16 +94,17 @@ void helper_debug(CPUMBState *env)
{
int i;
- qemu_log("PC=%8.8x\n", env->sregs[SR_PC]);
- qemu_log("rmsr=%x resr=%x rear=%x debug[%x] imm=%x iflags=%x\n",
+ qemu_log("PC=%" PRIx64 "\n", env->sregs[SR_PC]);
+ qemu_log("rmsr=%" PRIx64 " resr=%" PRIx64 " rear=%" PRIx64 " "
+ "debug[%x] imm=%x iflags=%x\n",
env->sregs[SR_MSR], env->sregs[SR_ESR], env->sregs[SR_EAR],
env->debug, env->imm, env->iflags);
- qemu_log("btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n",
+ qemu_log("btaken=%d btarget=%" PRIx64 " mode=%s(saved=%s) eip=%d ie=%d\n",
env->btaken, env->btarget,
(env->sregs[SR_MSR] & MSR_UM) ? "user" : "kernel",
(env->sregs[SR_MSR] & MSR_UMS) ? "user" : "kernel",
- (env->sregs[SR_MSR] & MSR_EIP),
- (env->sregs[SR_MSR] & MSR_IE));
+ (bool)(env->sregs[SR_MSR] & MSR_EIP),
+ (bool)(env->sregs[SR_MSR] & MSR_IE));
for (i = 0; i < 32; i++) {
qemu_log("r%2.2d=%8.8x ", i, env->regs[i]);
if ((i + 1) % 4 == 0)
@@ -439,12 +440,14 @@ uint32_t helper_pcmpbf(uint32_t a, uint32_t b)
return 0;
}
-void helper_memalign(CPUMBState *env, uint32_t addr, uint32_t dr, uint32_t wr,
+void helper_memalign(CPUMBState *env, target_ulong addr,
+ uint32_t dr, uint32_t wr,
uint32_t mask)
{
if (addr & mask) {
qemu_log_mask(CPU_LOG_INT,
- "unaligned access addr=%x mask=%x, wr=%d dr=r%d\n",
+ "unaligned access addr=" TARGET_FMT_lx
+ " mask=%x, wr=%d dr=r%d\n",
addr, mask, wr, dr);
env->sregs[SR_EAR] = addr;
env->sregs[SR_ESR] = ESR_EC_UNALIGNED_DATA | (wr << 10) \
@@ -459,10 +462,11 @@ void helper_memalign(CPUMBState *env, uint32_t addr, uint32_t dr, uint32_t wr,
}
}
-void helper_stackprot(CPUMBState *env, uint32_t addr)
+void helper_stackprot(CPUMBState *env, target_ulong addr)
{
if (addr < env->slr || addr > env->shr) {
- qemu_log_mask(CPU_LOG_INT, "Stack protector violation at %x %x %x\n",
+ qemu_log_mask(CPU_LOG_INT, "Stack protector violation at "
+ TARGET_FMT_lx " %x %x\n",
addr, env->slr, env->shr);
env->sregs[SR_EAR] = addr;
env->sregs[SR_ESR] = ESR_EC_STACKPROT;
@@ -472,14 +476,14 @@ void helper_stackprot(CPUMBState *env, uint32_t addr)
#if !defined(CONFIG_USER_ONLY)
/* Writes/reads to the MMU's special regs end up here. */
-uint32_t helper_mmu_read(CPUMBState *env, uint32_t rn)
+uint32_t helper_mmu_read(CPUMBState *env, uint32_t ext, uint32_t rn)
{
- return mmu_read(env, rn);
+ return mmu_read(env, ext, rn);
}
-void helper_mmu_write(CPUMBState *env, uint32_t rn, uint32_t v)
+void helper_mmu_write(CPUMBState *env, uint32_t ext, uint32_t rn, uint32_t v)
{
- mmu_write(env, rn, v);
+ mmu_write(env, ext, rn, v);
}
void mb_cpu_unassigned_access(CPUState *cs, hwaddr addr,
diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c
index 0872dc9ded..b79600cba5 100644
--- a/target/microblaze/translate.c
+++ b/target/microblaze/translate.c
@@ -52,22 +52,22 @@
#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
-static TCGv env_debug;
-static TCGv cpu_R[32];
-static TCGv cpu_SR[18];
-static TCGv env_imm;
-static TCGv env_btaken;
-static TCGv env_btarget;
-static TCGv env_iflags;
+static TCGv_i32 env_debug;
+static TCGv_i32 cpu_R[32];
+static TCGv_i64 cpu_SR[14];
+static TCGv_i32 env_imm;
+static TCGv_i32 env_btaken;
+static TCGv_i64 env_btarget;
+static TCGv_i32 env_iflags;
static TCGv env_res_addr;
-static TCGv env_res_val;
+static TCGv_i32 env_res_val;
#include "exec/gen-icount.h"
/* This is the state at translation time. */
typedef struct DisasContext {
MicroBlazeCPU *cpu;
- target_ulong pc;
+ uint32_t pc;
/* Decoder. */
int type_b;
@@ -105,16 +105,15 @@ static const char *regnames[] =
static const char *special_regnames[] =
{
- "rpc", "rmsr", "sr2", "sr3", "sr4", "sr5", "sr6", "sr7",
- "sr8", "sr9", "sr10", "sr11", "sr12", "sr13", "sr14", "sr15",
- "sr16", "sr17", "sr18"
+ "rpc", "rmsr", "sr2", "rear", "sr4", "resr", "sr6", "rfsr",
+ "sr8", "sr9", "sr10", "rbtr", "sr12", "redr"
};
static inline void t_sync_flags(DisasContext *dc)
{
/* Synch the tb dependent flags between translator and runtime. */
if (dc->tb_flags != dc->synced_flags) {
- tcg_gen_movi_tl(env_iflags, dc->tb_flags);
+ tcg_gen_movi_i32(env_iflags, dc->tb_flags);
dc->synced_flags = dc->tb_flags;
}
}
@@ -124,7 +123,7 @@ static inline void t_gen_raise_exception(DisasContext *dc, uint32_t index)
TCGv_i32 tmp = tcg_const_i32(index);
t_sync_flags(dc);
- tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
+ tcg_gen_movi_i64(cpu_SR[SR_PC], dc->pc);
gen_helper_raise_exception(cpu_env, tmp);
tcg_temp_free_i32(tmp);
dc->is_jmp = DISAS_UPDATE;
@@ -143,41 +142,70 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
{
if (use_goto_tb(dc, dest)) {
tcg_gen_goto_tb(n);
- tcg_gen_movi_tl(cpu_SR[SR_PC], dest);
+ tcg_gen_movi_i64(cpu_SR[SR_PC], dest);
tcg_gen_exit_tb((uintptr_t)dc->tb + n);
} else {
- tcg_gen_movi_tl(cpu_SR[SR_PC], dest);
+ tcg_gen_movi_i64(cpu_SR[SR_PC], dest);
tcg_gen_exit_tb(0);
}
}
-static void read_carry(DisasContext *dc, TCGv d)
+static void read_carry(DisasContext *dc, TCGv_i32 d)
{
- tcg_gen_shri_tl(d, cpu_SR[SR_MSR], 31);
+ tcg_gen_extrl_i64_i32(d, cpu_SR[SR_MSR]);
+ tcg_gen_shri_i32(d, d, 31);
}
/*
* write_carry sets the carry bits in MSR based on bit 0 of v.
* v[31:1] are ignored.
*/
-static void write_carry(DisasContext *dc, TCGv v)
+static void write_carry(DisasContext *dc, TCGv_i32 v)
{
- TCGv t0 = tcg_temp_new();
- tcg_gen_shli_tl(t0, v, 31);
- tcg_gen_sari_tl(t0, t0, 31);
- tcg_gen_andi_tl(t0, t0, (MSR_C | MSR_CC));
- tcg_gen_andi_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR],
- ~(MSR_C | MSR_CC));
- tcg_gen_or_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], t0);
- tcg_temp_free(t0);
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ tcg_gen_extu_i32_i64(t0, v);
+ /* Deposit bit 0 into MSR_C and the alias MSR_CC. */
+ tcg_gen_deposit_i64(cpu_SR[SR_MSR], cpu_SR[SR_MSR], t0, 2, 1);
+ tcg_gen_deposit_i64(cpu_SR[SR_MSR], cpu_SR[SR_MSR], t0, 31, 1);
+ tcg_temp_free_i64(t0);
}
static void write_carryi(DisasContext *dc, bool carry)
{
- TCGv t0 = tcg_temp_new();
- tcg_gen_movi_tl(t0, carry);
+ TCGv_i32 t0 = tcg_temp_new_i32();
+ tcg_gen_movi_i32(t0, carry);
write_carry(dc, t0);
- tcg_temp_free(t0);
+ tcg_temp_free_i32(t0);
+}
+
+/*
+ * Returns true if the insn an illegal operation.
+ * If exceptions are enabled, an exception is raised.
+ */
+static bool trap_illegal(DisasContext *dc, bool cond)
+{
+ if (cond && (dc->tb_flags & MSR_EE_FLAG)
+ && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
+ tcg_gen_movi_i64(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
+ t_gen_raise_exception(dc, EXCP_HW_EXCP);
+ }
+ return cond;
+}
+
+/*
+ * Returns true if the insn is illegal in userspace.
+ * If exceptions are enabled, an exception is raised.
+ */
+static bool trap_userspace(DisasContext *dc, bool cond)
+{
+ int mem_index = cpu_mmu_index(&dc->cpu->env, false);
+ bool cond_user = cond && mem_index == MMU_USER_IDX;
+
+ if (cond_user && (dc->tb_flags & MSR_EE_FLAG)) {
+ tcg_gen_movi_i64(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
+ t_gen_raise_exception(dc, EXCP_HW_EXCP);
+ }
+ return cond_user;
}
/* True if ALU operand b is a small immediate that may deserve
@@ -188,13 +216,13 @@ static inline int dec_alu_op_b_is_small_imm(DisasContext *dc)
return dc->type_b && !(dc->tb_flags & IMM_FLAG);
}
-static inline TCGv *dec_alu_op_b(DisasContext *dc)
+static inline TCGv_i32 *dec_alu_op_b(DisasContext *dc)
{
if (dc->type_b) {
if (dc->tb_flags & IMM_FLAG)
- tcg_gen_ori_tl(env_imm, env_imm, dc->imm);
+ tcg_gen_ori_i32(env_imm, env_imm, dc->imm);
else
- tcg_gen_movi_tl(env_imm, (int32_t)((int16_t)dc->imm));
+ tcg_gen_movi_i32(env_imm, (int32_t)((int16_t)dc->imm));
return &env_imm;
} else
return &cpu_R[dc->rb];
@@ -203,7 +231,7 @@ static inline TCGv *dec_alu_op_b(DisasContext *dc)
static void dec_add(DisasContext *dc)
{
unsigned int k, c;
- TCGv cf;
+ TCGv_i32 cf;
k = dc->opcode & 4;
c = dc->opcode & 2;
@@ -217,15 +245,15 @@ static void dec_add(DisasContext *dc)
/* k - keep carry, no need to update MSR. */
/* If rd == r0, it's a nop. */
if (dc->rd) {
- tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
+ tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
if (c) {
/* c - Add carry into the result. */
- cf = tcg_temp_new();
+ cf = tcg_temp_new_i32();
read_carry(dc, cf);
- tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->rd], cf);
- tcg_temp_free(cf);
+ tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cf);
+ tcg_temp_free_i32(cf);
}
}
return;
@@ -233,31 +261,31 @@ static void dec_add(DisasContext *dc)
/* From now on, we can assume k is zero. So we need to update MSR. */
/* Extract carry. */
- cf = tcg_temp_new();
+ cf = tcg_temp_new_i32();
if (c) {
read_carry(dc, cf);
} else {
- tcg_gen_movi_tl(cf, 0);
+ tcg_gen_movi_i32(cf, 0);
}
if (dc->rd) {
- TCGv ncf = tcg_temp_new();
+ TCGv_i32 ncf = tcg_temp_new_i32();
gen_helper_carry(ncf, cpu_R[dc->ra], *(dec_alu_op_b(dc)), cf);
- tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
- tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->rd], cf);
+ tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
+ tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cf);
write_carry(dc, ncf);
- tcg_temp_free(ncf);
+ tcg_temp_free_i32(ncf);
} else {
gen_helper_carry(cf, cpu_R[dc->ra], *(dec_alu_op_b(dc)), cf);
write_carry(dc, cf);
}
- tcg_temp_free(cf);
+ tcg_temp_free_i32(cf);
}
static void dec_sub(DisasContext *dc)
{
unsigned int u, cmp, k, c;
- TCGv cf, na;
+ TCGv_i32 cf, na;
u = dc->imm & 2;
k = dc->opcode & 4;
@@ -283,15 +311,15 @@ static void dec_sub(DisasContext *dc)
/* k - keep carry, no need to update MSR. */
/* If rd == r0, it's a nop. */
if (dc->rd) {
- tcg_gen_sub_tl(cpu_R[dc->rd], *(dec_alu_op_b(dc)), cpu_R[dc->ra]);
+ tcg_gen_sub_i32(cpu_R[dc->rd], *(dec_alu_op_b(dc)), cpu_R[dc->ra]);
if (c) {
/* c - Add carry into the result. */
- cf = tcg_temp_new();
+ cf = tcg_temp_new_i32();
read_carry(dc, cf);
- tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->rd], cf);
- tcg_temp_free(cf);
+ tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cf);
+ tcg_temp_free_i32(cf);
}
}
return;
@@ -299,41 +327,38 @@ static void dec_sub(DisasContext *dc)
/* From now on, we can assume k is zero. So we need to update MSR. */
/* Extract carry. And complement a into na. */
- cf = tcg_temp_new();
- na = tcg_temp_new();
+ cf = tcg_temp_new_i32();
+ na = tcg_temp_new_i32();
if (c) {
read_carry(dc, cf);
} else {
- tcg_gen_movi_tl(cf, 1);
+ tcg_gen_movi_i32(cf, 1);
}
/* d = b + ~a + c. carry defaults to 1. */
- tcg_gen_not_tl(na, cpu_R[dc->ra]);
+ tcg_gen_not_i32(na, cpu_R[dc->ra]);
if (dc->rd) {
- TCGv ncf = tcg_temp_new();
+ TCGv_i32 ncf = tcg_temp_new_i32();
gen_helper_carry(ncf, na, *(dec_alu_op_b(dc)), cf);
- tcg_gen_add_tl(cpu_R[dc->rd], na, *(dec_alu_op_b(dc)));
- tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->rd], cf);
+ tcg_gen_add_i32(cpu_R[dc->rd], na, *(dec_alu_op_b(dc)));
+ tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cf);
write_carry(dc, ncf);
- tcg_temp_free(ncf);
+ tcg_temp_free_i32(ncf);
} else {
gen_helper_carry(cf, na, *(dec_alu_op_b(dc)), cf);
write_carry(dc, cf);
}
- tcg_temp_free(cf);
- tcg_temp_free(na);
+ tcg_temp_free_i32(cf);
+ tcg_temp_free_i32(na);
}
static void dec_pattern(DisasContext *dc)
{
unsigned int mode;
- if ((dc->tb_flags & MSR_EE_FLAG)
- && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
- && !dc->cpu->cfg.use_pcmp_instr) {
- tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
- t_gen_raise_exception(dc, EXCP_HW_EXCP);
+ if (trap_illegal(dc, !dc->cpu->cfg.use_pcmp_instr)) {
+ return;
}
mode = dc->opcode & 3;
@@ -347,14 +372,14 @@ static void dec_pattern(DisasContext *dc)
case 2:
LOG_DIS("pcmpeq r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
if (dc->rd) {
- tcg_gen_setcond_tl(TCG_COND_EQ, cpu_R[dc->rd],
+ tcg_gen_setcond_i32(TCG_COND_EQ, cpu_R[dc->rd],
cpu_R[dc->ra], cpu_R[dc->rb]);
}
break;
case 3:
LOG_DIS("pcmpne r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
if (dc->rd) {
- tcg_gen_setcond_tl(TCG_COND_NE, cpu_R[dc->rd],
+ tcg_gen_setcond_i32(TCG_COND_NE, cpu_R[dc->rd],
cpu_R[dc->ra], cpu_R[dc->rb]);
}
break;
@@ -381,9 +406,9 @@ static void dec_and(DisasContext *dc)
return;
if (not) {
- tcg_gen_andc_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
+ tcg_gen_andc_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
} else
- tcg_gen_and_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
+ tcg_gen_and_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
}
static void dec_or(DisasContext *dc)
@@ -395,7 +420,7 @@ static void dec_or(DisasContext *dc)
LOG_DIS("or r%d r%d r%d imm=%x\n", dc->rd, dc->ra, dc->rb, dc->imm);
if (dc->rd)
- tcg_gen_or_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
+ tcg_gen_or_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
}
static void dec_xor(DisasContext *dc)
@@ -407,43 +432,54 @@ static void dec_xor(DisasContext *dc)
LOG_DIS("xor r%d\n", dc->rd);
if (dc->rd)
- tcg_gen_xor_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
+ tcg_gen_xor_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
}
-static inline void msr_read(DisasContext *dc, TCGv d)
+static inline void msr_read(DisasContext *dc, TCGv_i32 d)
{
- tcg_gen_mov_tl(d, cpu_SR[SR_MSR]);
+ tcg_gen_extrl_i64_i32(d, cpu_SR[SR_MSR]);
}
-static inline void msr_write(DisasContext *dc, TCGv v)
+static inline void msr_write(DisasContext *dc, TCGv_i32 v)
{
- TCGv t;
+ TCGv_i64 t;
- t = tcg_temp_new();
+ t = tcg_temp_new_i64();
dc->cpustate_changed = 1;
/* PVR bit is not writable. */
- tcg_gen_andi_tl(t, v, ~MSR_PVR);
- tcg_gen_andi_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], MSR_PVR);
- tcg_gen_or_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], t);
- tcg_temp_free(t);
+ tcg_gen_extu_i32_i64(t, v);
+ tcg_gen_andi_i64(t, t, ~MSR_PVR);
+ tcg_gen_andi_i64(cpu_SR[SR_MSR], cpu_SR[SR_MSR], MSR_PVR);
+ tcg_gen_or_i64(cpu_SR[SR_MSR], cpu_SR[SR_MSR], t);
+ tcg_temp_free_i64(t);
}
static void dec_msr(DisasContext *dc)
{
CPUState *cs = CPU(dc->cpu);
- TCGv t0, t1;
- unsigned int sr, to, rn;
- int mem_index = cpu_mmu_index(&dc->cpu->env, false);
+ TCGv_i32 t0, t1;
+ unsigned int sr, rn;
+ bool to, clrset, extended = false;
- sr = dc->imm & ((1 << 14) - 1);
- to = dc->imm & (1 << 14);
+ sr = extract32(dc->imm, 0, 14);
+ to = extract32(dc->imm, 14, 1);
+ clrset = extract32(dc->imm, 15, 1) == 0;
dc->type_b = 1;
- if (to)
+ if (to) {
dc->cpustate_changed = 1;
+ }
+
+ /* Extended MSRs are only available if addr_size > 32. */
+ if (dc->cpu->cfg.addr_size > 32) {
+ /* The E-bit is encoded differently for To/From MSR. */
+ static const unsigned int e_bit[] = { 19, 24 };
+
+ extended = extract32(dc->imm, e_bit[to], 1);
+ }
/* msrclr and msrset. */
- if (!(dc->imm & (1 << 15))) {
- unsigned int clr = dc->ir & (1 << 16);
+ if (clrset) {
+ bool clr = extract32(dc->ir, 16, 1);
LOG_DIS("msr%s r%d imm=%x\n", clr ? "clr" : "set",
dc->rd, dc->imm);
@@ -453,52 +489,51 @@ static void dec_msr(DisasContext *dc)
return;
}
- if ((dc->tb_flags & MSR_EE_FLAG)
- && mem_index == MMU_USER_IDX && (dc->imm != 4 && dc->imm != 0)) {
- tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
- t_gen_raise_exception(dc, EXCP_HW_EXCP);
+ if (trap_userspace(dc, dc->imm != 4 && dc->imm != 0)) {
return;
}
if (dc->rd)
msr_read(dc, cpu_R[dc->rd]);
- t0 = tcg_temp_new();
- t1 = tcg_temp_new();
+ t0 = tcg_temp_new_i32();
+ t1 = tcg_temp_new_i32();
msr_read(dc, t0);
- tcg_gen_mov_tl(t1, *(dec_alu_op_b(dc)));
+ tcg_gen_mov_i32(t1, *(dec_alu_op_b(dc)));
if (clr) {
- tcg_gen_not_tl(t1, t1);
- tcg_gen_and_tl(t0, t0, t1);
+ tcg_gen_not_i32(t1, t1);
+ tcg_gen_and_i32(t0, t0, t1);
} else
- tcg_gen_or_tl(t0, t0, t1);
+ tcg_gen_or_i32(t0, t0, t1);
msr_write(dc, t0);
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc + 4);
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(t1);
+ tcg_gen_movi_i64(cpu_SR[SR_PC], dc->pc + 4);
dc->is_jmp = DISAS_UPDATE;
return;
}
- if (to) {
- if ((dc->tb_flags & MSR_EE_FLAG)
- && mem_index == MMU_USER_IDX) {
- tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
- t_gen_raise_exception(dc, EXCP_HW_EXCP);
- return;
- }
+ if (trap_userspace(dc, to)) {
+ return;
}
#if !defined(CONFIG_USER_ONLY)
/* Catch read/writes to the mmu block. */
if ((sr & ~0xff) == 0x1000) {
+ TCGv_i32 tmp_ext = tcg_const_i32(extended);
+ TCGv_i32 tmp_sr;
+
sr &= 7;
+ tmp_sr = tcg_const_i32(sr);
LOG_DIS("m%ss sr%d r%d imm=%x\n", to ? "t" : "f", sr, dc->ra, dc->imm);
- if (to)
- gen_helper_mmu_write(cpu_env, tcg_const_tl(sr), cpu_R[dc->ra]);
- else
- gen_helper_mmu_read(cpu_R[dc->rd], cpu_env, tcg_const_tl(sr));
+ if (to) {
+ gen_helper_mmu_write(cpu_env, tmp_ext, tmp_sr, cpu_R[dc->ra]);
+ } else {
+ gen_helper_mmu_read(cpu_R[dc->rd], cpu_env, tmp_ext, tmp_sr);
+ }
+ tcg_temp_free_i32(tmp_sr);
+ tcg_temp_free_i32(tmp_ext);
return;
}
#endif
@@ -511,20 +546,18 @@ static void dec_msr(DisasContext *dc)
case 1:
msr_write(dc, cpu_R[dc->ra]);
break;
- case 0x3:
- tcg_gen_mov_tl(cpu_SR[SR_EAR], cpu_R[dc->ra]);
- break;
- case 0x5:
- tcg_gen_mov_tl(cpu_SR[SR_ESR], cpu_R[dc->ra]);
- break;
- case 0x7:
- tcg_gen_andi_tl(cpu_SR[SR_FSR], cpu_R[dc->ra], 31);
+ case SR_EAR:
+ case SR_ESR:
+ case SR_FSR:
+ tcg_gen_extu_i32_i64(cpu_SR[sr], cpu_R[dc->ra]);
break;
case 0x800:
- tcg_gen_st_tl(cpu_R[dc->ra], cpu_env, offsetof(CPUMBState, slr));
+ tcg_gen_st_i32(cpu_R[dc->ra],
+ cpu_env, offsetof(CPUMBState, slr));
break;
case 0x802:
- tcg_gen_st_tl(cpu_R[dc->ra], cpu_env, offsetof(CPUMBState, shr));
+ tcg_gen_st_i32(cpu_R[dc->ra],
+ cpu_env, offsetof(CPUMBState, shr));
break;
default:
cpu_abort(CPU(dc->cpu), "unknown mts reg %x\n", sr);
@@ -535,44 +568,32 @@ static void dec_msr(DisasContext *dc)
switch (sr) {
case 0:
- tcg_gen_movi_tl(cpu_R[dc->rd], dc->pc);
+ tcg_gen_movi_i32(cpu_R[dc->rd], dc->pc);
break;
case 1:
msr_read(dc, cpu_R[dc->rd]);
break;
- case 0x3:
- tcg_gen_mov_tl(cpu_R[dc->rd], cpu_SR[SR_EAR]);
- break;
- case 0x5:
- tcg_gen_mov_tl(cpu_R[dc->rd], cpu_SR[SR_ESR]);
- break;
- case 0x7:
- tcg_gen_mov_tl(cpu_R[dc->rd], cpu_SR[SR_FSR]);
- break;
- case 0xb:
- tcg_gen_mov_tl(cpu_R[dc->rd], cpu_SR[SR_BTR]);
+ case SR_EAR:
+ if (extended) {
+ tcg_gen_extrh_i64_i32(cpu_R[dc->rd], cpu_SR[sr]);
+ break;
+ }
+ case SR_ESR:
+ case SR_FSR:
+ case SR_BTR:
+ tcg_gen_extrl_i64_i32(cpu_R[dc->rd], cpu_SR[sr]);
break;
case 0x800:
- tcg_gen_ld_tl(cpu_R[dc->rd], cpu_env, offsetof(CPUMBState, slr));
+ tcg_gen_ld_i32(cpu_R[dc->rd],
+ cpu_env, offsetof(CPUMBState, slr));
break;
case 0x802:
- tcg_gen_ld_tl(cpu_R[dc->rd], cpu_env, offsetof(CPUMBState, shr));
+ tcg_gen_ld_i32(cpu_R[dc->rd],
+ cpu_env, offsetof(CPUMBState, shr));
break;
- case 0x2000:
- case 0x2001:
- case 0x2002:
- case 0x2003:
- case 0x2004:
- case 0x2005:
- case 0x2006:
- case 0x2007:
- case 0x2008:
- case 0x2009:
- case 0x200a:
- case 0x200b:
- case 0x200c:
+ case 0x2000 ... 0x200c:
rn = sr & 0xf;
- tcg_gen_ld_tl(cpu_R[dc->rd],
+ tcg_gen_ld_i32(cpu_R[dc->rd],
cpu_env, offsetof(CPUMBState, pvr.regs[rn]));
break;
default:
@@ -582,21 +603,17 @@ static void dec_msr(DisasContext *dc)
}
if (dc->rd == 0) {
- tcg_gen_movi_tl(cpu_R[0], 0);
+ tcg_gen_movi_i32(cpu_R[0], 0);
}
}
/* Multiplier unit. */
static void dec_mul(DisasContext *dc)
{
- TCGv tmp;
+ TCGv_i32 tmp;
unsigned int subcode;
- if ((dc->tb_flags & MSR_EE_FLAG)
- && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
- && !dc->cpu->cfg.use_hw_mul) {
- tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
- t_gen_raise_exception(dc, EXCP_HW_EXCP);
+ if (trap_illegal(dc, !dc->cpu->cfg.use_hw_mul)) {
return;
}
@@ -604,7 +621,7 @@ static void dec_mul(DisasContext *dc)
if (dc->type_b) {
LOG_DIS("muli r%d r%d %x\n", dc->rd, dc->ra, dc->imm);
- tcg_gen_mul_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
+ tcg_gen_mul_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
return;
}
@@ -613,29 +630,31 @@ static void dec_mul(DisasContext *dc)
/* nop??? */
}
- tmp = tcg_temp_new();
+ tmp = tcg_temp_new_i32();
switch (subcode) {
case 0:
LOG_DIS("mul r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
- tcg_gen_mul_tl(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
+ tcg_gen_mul_i32(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
break;
case 1:
LOG_DIS("mulh r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
- tcg_gen_muls2_tl(tmp, cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
+ tcg_gen_muls2_i32(tmp, cpu_R[dc->rd],
+ cpu_R[dc->ra], cpu_R[dc->rb]);
break;
case 2:
LOG_DIS("mulhsu r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
- tcg_gen_mulsu2_tl(tmp, cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
+ tcg_gen_mulsu2_i32(tmp, cpu_R[dc->rd],
+ cpu_R[dc->ra], cpu_R[dc->rb]);
break;
case 3:
LOG_DIS("mulhu r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
- tcg_gen_mulu2_tl(tmp, cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
+ tcg_gen_mulu2_i32(tmp, cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
break;
default:
cpu_abort(CPU(dc->cpu), "unknown MUL insn %x\n", subcode);
break;
}
- tcg_temp_free(tmp);
+ tcg_temp_free_i32(tmp);
}
/* Div unit. */
@@ -646,10 +665,8 @@ static void dec_div(DisasContext *dc)
u = dc->imm & 2;
LOG_DIS("div\n");
- if ((dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
- && !dc->cpu->cfg.use_div) {
- tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
- t_gen_raise_exception(dc, EXCP_HW_EXCP);
+ if (trap_illegal(dc, !dc->cpu->cfg.use_div)) {
+ return;
}
if (u)
@@ -659,20 +676,16 @@ static void dec_div(DisasContext *dc)
gen_helper_divs(cpu_R[dc->rd], cpu_env, *(dec_alu_op_b(dc)),
cpu_R[dc->ra]);
if (!dc->rd)
- tcg_gen_movi_tl(cpu_R[dc->rd], 0);
+ tcg_gen_movi_i32(cpu_R[dc->rd], 0);
}
static void dec_barrel(DisasContext *dc)
{
- TCGv t0;
+ TCGv_i32 t0;
unsigned int imm_w, imm_s;
bool s, t, e = false, i = false;
- if ((dc->tb_flags & MSR_EE_FLAG)
- && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
- && !dc->cpu->cfg.use_barrel) {
- tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
- t_gen_raise_exception(dc, EXCP_HW_EXCP);
+ if (trap_illegal(dc, !dc->cpu->cfg.use_barrel)) {
return;
}
@@ -710,45 +723,45 @@ static void dec_barrel(DisasContext *dc)
imm_s, width);
}
} else {
- t0 = tcg_temp_new();
+ t0 = tcg_temp_new_i32();
- tcg_gen_mov_tl(t0, *(dec_alu_op_b(dc)));
- tcg_gen_andi_tl(t0, t0, 31);
+ tcg_gen_mov_i32(t0, *(dec_alu_op_b(dc)));
+ tcg_gen_andi_i32(t0, t0, 31);
if (s) {
- tcg_gen_shl_tl(cpu_R[dc->rd], cpu_R[dc->ra], t0);
+ tcg_gen_shl_i32(cpu_R[dc->rd], cpu_R[dc->ra], t0);
} else {
if (t) {
- tcg_gen_sar_tl(cpu_R[dc->rd], cpu_R[dc->ra], t0);
+ tcg_gen_sar_i32(cpu_R[dc->rd], cpu_R[dc->ra], t0);
} else {
- tcg_gen_shr_tl(cpu_R[dc->rd], cpu_R[dc->ra], t0);
+ tcg_gen_shr_i32(cpu_R[dc->rd], cpu_R[dc->ra], t0);
}
}
- tcg_temp_free(t0);
+ tcg_temp_free_i32(t0);
}
}
static void dec_bit(DisasContext *dc)
{
CPUState *cs = CPU(dc->cpu);
- TCGv t0;
+ TCGv_i32 t0;
unsigned int op;
- int mem_index = cpu_mmu_index(&dc->cpu->env, false);
op = dc->ir & ((1 << 9) - 1);
switch (op) {
case 0x21:
/* src. */
- t0 = tcg_temp_new();
+ t0 = tcg_temp_new_i32();
LOG_DIS("src r%d r%d\n", dc->rd, dc->ra);
- tcg_gen_andi_tl(t0, cpu_SR[SR_MSR], MSR_CC);
+ tcg_gen_extrl_i64_i32(t0, cpu_SR[SR_MSR]);
+ tcg_gen_andi_i32(t0, t0, MSR_CC);
write_carry(dc, cpu_R[dc->ra]);
if (dc->rd) {
- tcg_gen_shri_tl(cpu_R[dc->rd], cpu_R[dc->ra], 1);
- tcg_gen_or_tl(cpu_R[dc->rd], cpu_R[dc->rd], t0);
+ tcg_gen_shri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1);
+ tcg_gen_or_i32(cpu_R[dc->rd], cpu_R[dc->rd], t0);
}
- tcg_temp_free(t0);
+ tcg_temp_free_i32(t0);
break;
case 0x1:
@@ -760,9 +773,9 @@ static void dec_bit(DisasContext *dc)
write_carry(dc, cpu_R[dc->ra]);
if (dc->rd) {
if (op == 0x41)
- tcg_gen_shri_tl(cpu_R[dc->rd], cpu_R[dc->ra], 1);
+ tcg_gen_shri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1);
else
- tcg_gen_sari_tl(cpu_R[dc->rd], cpu_R[dc->ra], 1);
+ tcg_gen_sari_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1);
}
break;
case 0x60:
@@ -779,29 +792,16 @@ static void dec_bit(DisasContext *dc)
case 0x76:
/* wdc. */
LOG_DIS("wdc r%d\n", dc->ra);
- if ((dc->tb_flags & MSR_EE_FLAG)
- && mem_index == MMU_USER_IDX) {
- tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
- t_gen_raise_exception(dc, EXCP_HW_EXCP);
- return;
- }
+ trap_userspace(dc, true);
break;
case 0x68:
/* wic. */
LOG_DIS("wic r%d\n", dc->ra);
- if ((dc->tb_flags & MSR_EE_FLAG)
- && mem_index == MMU_USER_IDX) {
- tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
- t_gen_raise_exception(dc, EXCP_HW_EXCP);
- return;
- }
+ trap_userspace(dc, true);
break;
case 0xe0:
- if ((dc->tb_flags & MSR_EE_FLAG)
- && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
- && !dc->cpu->cfg.use_pcmp_instr) {
- tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
- t_gen_raise_exception(dc, EXCP_HW_EXCP);
+ if (trap_illegal(dc, !dc->cpu->cfg.use_pcmp_instr)) {
+ return;
}
if (dc->cpu->cfg.use_pcmp_instr) {
tcg_gen_clzi_i32(cpu_R[dc->rd], cpu_R[dc->ra], 32);
@@ -828,101 +828,128 @@ static inline void sync_jmpstate(DisasContext *dc)
{
if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {
if (dc->jmp == JMP_DIRECT) {
- tcg_gen_movi_tl(env_btaken, 1);
+ tcg_gen_movi_i32(env_btaken, 1);
}
dc->jmp = JMP_INDIRECT;
- tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
+ tcg_gen_movi_i64(env_btarget, dc->jmp_pc);
}
}
static void dec_imm(DisasContext *dc)
{
LOG_DIS("imm %x\n", dc->imm << 16);
- tcg_gen_movi_tl(env_imm, (dc->imm << 16));
+ tcg_gen_movi_i32(env_imm, (dc->imm << 16));
dc->tb_flags |= IMM_FLAG;
dc->clear_imm = 0;
}
-static inline TCGv *compute_ldst_addr(DisasContext *dc, TCGv *t)
+static inline void compute_ldst_addr(DisasContext *dc, bool ea, TCGv t)
{
- unsigned int extimm = dc->tb_flags & IMM_FLAG;
- /* Should be set to one if r1 is used by loadstores. */
- int stackprot = 0;
+ bool extimm = dc->tb_flags & IMM_FLAG;
+ /* Should be set to true if r1 is used by loadstores. */
+ bool stackprot = false;
+ TCGv_i32 t32;
/* All load/stores use ra. */
if (dc->ra == 1 && dc->cpu->cfg.stackprot) {
- stackprot = 1;
+ stackprot = true;
}
/* Treat the common cases first. */
if (!dc->type_b) {
- /* If any of the regs is r0, return a ptr to the other. */
+ if (ea) {
+ int addr_size = dc->cpu->cfg.addr_size;
+
+ if (addr_size == 32) {
+ tcg_gen_extu_i32_tl(t, cpu_R[dc->rb]);
+ return;
+ }
+
+ tcg_gen_concat_i32_i64(t, cpu_R[dc->rb], cpu_R[dc->ra]);
+ if (addr_size < 64) {
+ /* Mask off out of range bits. */
+ tcg_gen_andi_i64(t, t, MAKE_64BIT_MASK(0, addr_size));
+ }
+ return;
+ }
+
+ /* If any of the regs is r0, set t to the value of the other reg. */
if (dc->ra == 0) {
- return &cpu_R[dc->rb];
+ tcg_gen_extu_i32_tl(t, cpu_R[dc->rb]);
+ return;
} else if (dc->rb == 0) {
- return &cpu_R[dc->ra];
+ tcg_gen_extu_i32_tl(t, cpu_R[dc->ra]);
+ return;
}
if (dc->rb == 1 && dc->cpu->cfg.stackprot) {
- stackprot = 1;
+ stackprot = true;
}
- *t = tcg_temp_new();
- tcg_gen_add_tl(*t, cpu_R[dc->ra], cpu_R[dc->rb]);
+ t32 = tcg_temp_new_i32();
+ tcg_gen_add_i32(t32, cpu_R[dc->ra], cpu_R[dc->rb]);
+ tcg_gen_extu_i32_tl(t, t32);
+ tcg_temp_free_i32(t32);
if (stackprot) {
- gen_helper_stackprot(cpu_env, *t);
+ gen_helper_stackprot(cpu_env, t);
}
- return t;
+ return;
}
/* Immediate. */
+ t32 = tcg_temp_new_i32();
if (!extimm) {
- if (dc->imm == 0) {
- return &cpu_R[dc->ra];
- }
- *t = tcg_temp_new();
- tcg_gen_movi_tl(*t, (int32_t)((int16_t)dc->imm));
- tcg_gen_add_tl(*t, cpu_R[dc->ra], *t);
+ tcg_gen_addi_i32(t32, cpu_R[dc->ra], (int16_t)dc->imm);
} else {
- *t = tcg_temp_new();
- tcg_gen_add_tl(*t, cpu_R[dc->ra], *(dec_alu_op_b(dc)));
+ tcg_gen_add_i32(t32, cpu_R[dc->ra], *(dec_alu_op_b(dc)));
}
+ tcg_gen_extu_i32_tl(t, t32);
+ tcg_temp_free_i32(t32);
if (stackprot) {
- gen_helper_stackprot(cpu_env, *t);
+ gen_helper_stackprot(cpu_env, t);
}
- return t;
+ return;
}
static void dec_load(DisasContext *dc)
{
- TCGv t, v, *addr;
- unsigned int size, rev = 0, ex = 0;
+ TCGv_i32 v;
+ TCGv addr;
+ unsigned int size;
+ bool rev = false, ex = false, ea = false;
+ int mem_index = cpu_mmu_index(&dc->cpu->env, false);
TCGMemOp mop;
mop = dc->opcode & 3;
size = 1 << mop;
if (!dc->type_b) {
- rev = (dc->ir >> 9) & 1;
- ex = (dc->ir >> 10) & 1;
+ ea = extract32(dc->ir, 7, 1);
+ rev = extract32(dc->ir, 9, 1);
+ ex = extract32(dc->ir, 10, 1);
}
mop |= MO_TE;
if (rev) {
mop ^= MO_BSWAP;
}
- if (size > 4 && (dc->tb_flags & MSR_EE_FLAG)
- && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
- tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
- t_gen_raise_exception(dc, EXCP_HW_EXCP);
+ if (trap_illegal(dc, size > 4)) {
return;
}
- LOG_DIS("l%d%s%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "",
- ex ? "x" : "");
+ if (trap_userspace(dc, ea)) {
+ return;
+ }
+
+ LOG_DIS("l%d%s%s%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "",
+ ex ? "x" : "",
+ ea ? "ea" : "");
t_sync_flags(dc);
- addr = compute_ldst_addr(dc, &t);
+ addr = tcg_temp_new();
+ compute_ldst_addr(dc, ea, addr);
+ /* Extended addressing bypasses the MMU. */
+ mem_index = ea ? MMU_NOMMU_IDX : mem_index;
/*
* When doing reverse accesses we need to do two things.
@@ -941,17 +968,10 @@ static void dec_load(DisasContext *dc)
11 -> 00 */
TCGv low = tcg_temp_new();
- /* Force addr into the temp. */
- if (addr != &t) {
- t = tcg_temp_new();
- tcg_gen_mov_tl(t, *addr);
- addr = &t;
- }
-
- tcg_gen_andi_tl(low, t, 3);
+ tcg_gen_andi_tl(low, addr, 3);
tcg_gen_sub_tl(low, tcg_const_tl(3), low);
- tcg_gen_andi_tl(t, t, ~3);
- tcg_gen_or_tl(t, t, low);
+ tcg_gen_andi_tl(addr, addr, ~3);
+ tcg_gen_or_tl(addr, addr, low);
tcg_temp_free(low);
break;
}
@@ -959,14 +979,7 @@ static void dec_load(DisasContext *dc)
case 2:
/* 00 -> 10
10 -> 00. */
- /* Force addr into the temp. */
- if (addr != &t) {
- t = tcg_temp_new();
- tcg_gen_xori_tl(t, *addr, 2);
- addr = &t;
- } else {
- tcg_gen_xori_tl(t, t, 2);
- }
+ tcg_gen_xori_tl(addr, addr, 2);
break;
default:
cpu_abort(CPU(dc->cpu), "Invalid reverse size\n");
@@ -976,13 +989,7 @@ static void dec_load(DisasContext *dc)
/* lwx does not throw unaligned access errors, so force alignment */
if (ex) {
- /* Force addr into the temp. */
- if (addr != &t) {
- t = tcg_temp_new();
- tcg_gen_mov_tl(t, *addr);
- addr = &t;
- }
- tcg_gen_andi_tl(t, t, ~3);
+ tcg_gen_andi_tl(addr, addr, ~3);
}
/* If we get a fault on a dslot, the jmpstate better be in sync. */
@@ -995,90 +1002,92 @@ static void dec_load(DisasContext *dc)
* into v. If the load succeeds, we verify alignment of the
* address and if that succeeds we write into the destination reg.
*/
- v = tcg_temp_new();
- tcg_gen_qemu_ld_tl(v, *addr, cpu_mmu_index(&dc->cpu->env, false), mop);
+ v = tcg_temp_new_i32();
+ tcg_gen_qemu_ld_i32(v, addr, mem_index, mop);
if ((dc->cpu->env.pvr.regs[2] & PVR2_UNALIGNED_EXC_MASK) && size > 1) {
- tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
- gen_helper_memalign(cpu_env, *addr, tcg_const_tl(dc->rd),
- tcg_const_tl(0), tcg_const_tl(size - 1));
+ tcg_gen_movi_i64(cpu_SR[SR_PC], dc->pc);
+ gen_helper_memalign(cpu_env, addr, tcg_const_i32(dc->rd),
+ tcg_const_i32(0), tcg_const_i32(size - 1));
}
if (ex) {
- tcg_gen_mov_tl(env_res_addr, *addr);
- tcg_gen_mov_tl(env_res_val, v);
+ tcg_gen_mov_tl(env_res_addr, addr);
+ tcg_gen_mov_i32(env_res_val, v);
}
if (dc->rd) {
- tcg_gen_mov_tl(cpu_R[dc->rd], v);
+ tcg_gen_mov_i32(cpu_R[dc->rd], v);
}
- tcg_temp_free(v);
+ tcg_temp_free_i32(v);
if (ex) { /* lwx */
/* no support for AXI exclusive so always clear C */
write_carryi(dc, 0);
}
- if (addr == &t)
- tcg_temp_free(t);
+ tcg_temp_free(addr);
}
static void dec_store(DisasContext *dc)
{
- TCGv t, *addr, swx_addr;
+ TCGv addr;
TCGLabel *swx_skip = NULL;
- unsigned int size, rev = 0, ex = 0;
+ unsigned int size;
+ bool rev = false, ex = false, ea = false;
+ int mem_index = cpu_mmu_index(&dc->cpu->env, false);
TCGMemOp mop;
mop = dc->opcode & 3;
size = 1 << mop;
if (!dc->type_b) {
- rev = (dc->ir >> 9) & 1;
- ex = (dc->ir >> 10) & 1;
+ ea = extract32(dc->ir, 7, 1);
+ rev = extract32(dc->ir, 9, 1);
+ ex = extract32(dc->ir, 10, 1);
}
mop |= MO_TE;
if (rev) {
mop ^= MO_BSWAP;
}
- if (size > 4 && (dc->tb_flags & MSR_EE_FLAG)
- && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
- tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
- t_gen_raise_exception(dc, EXCP_HW_EXCP);
+ if (trap_illegal(dc, size > 4)) {
return;
}
- LOG_DIS("s%d%s%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "",
- ex ? "x" : "");
+ trap_userspace(dc, ea);
+
+ LOG_DIS("s%d%s%s%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "",
+ ex ? "x" : "",
+ ea ? "ea" : "");
t_sync_flags(dc);
/* If we get a fault on a dslot, the jmpstate better be in sync. */
sync_jmpstate(dc);
- addr = compute_ldst_addr(dc, &t);
+ /* SWX needs a temp_local. */
+ addr = ex ? tcg_temp_local_new() : tcg_temp_new();
+ compute_ldst_addr(dc, ea, addr);
+ /* Extended addressing bypasses the MMU. */
+ mem_index = ea ? MMU_NOMMU_IDX : mem_index;
- swx_addr = tcg_temp_local_new();
if (ex) { /* swx */
- TCGv tval;
+ TCGv_i32 tval;
- /* Force addr into the swx_addr. */
- tcg_gen_mov_tl(swx_addr, *addr);
- addr = &swx_addr;
/* swx does not throw unaligned access errors, so force alignment */
- tcg_gen_andi_tl(swx_addr, swx_addr, ~3);
+ tcg_gen_andi_tl(addr, addr, ~3);
write_carryi(dc, 1);
swx_skip = gen_new_label();
- tcg_gen_brcond_tl(TCG_COND_NE, env_res_addr, swx_addr, swx_skip);
+ tcg_gen_brcond_tl(TCG_COND_NE, env_res_addr, addr, swx_skip);
/* Compare the value loaded at lwx with current contents of
the reserved location.
FIXME: This only works for system emulation where we can expect
this compare and the following write to be atomic. For user
emulation we need to add atomicity between threads. */
- tval = tcg_temp_new();
- tcg_gen_qemu_ld_tl(tval, swx_addr, cpu_mmu_index(&dc->cpu->env, false),
- MO_TEUL);
- tcg_gen_brcond_tl(TCG_COND_NE, env_res_val, tval, swx_skip);
+ tval = tcg_temp_new_i32();
+ tcg_gen_qemu_ld_i32(tval, addr, cpu_mmu_index(&dc->cpu->env, false),
+ MO_TEUL);
+ tcg_gen_brcond_i32(TCG_COND_NE, env_res_val, tval, swx_skip);
write_carryi(dc, 0);
- tcg_temp_free(tval);
+ tcg_temp_free_i32(tval);
}
if (rev && size != 4) {
@@ -1092,17 +1101,10 @@ static void dec_store(DisasContext *dc)
11 -> 00 */
TCGv low = tcg_temp_new();
- /* Force addr into the temp. */
- if (addr != &t) {
- t = tcg_temp_new();
- tcg_gen_mov_tl(t, *addr);
- addr = &t;
- }
-
- tcg_gen_andi_tl(low, t, 3);
+ tcg_gen_andi_tl(low, addr, 3);
tcg_gen_sub_tl(low, tcg_const_tl(3), low);
- tcg_gen_andi_tl(t, t, ~3);
- tcg_gen_or_tl(t, t, low);
+ tcg_gen_andi_tl(addr, addr, ~3);
+ tcg_gen_or_tl(addr, addr, low);
tcg_temp_free(low);
break;
}
@@ -1111,79 +1113,74 @@ static void dec_store(DisasContext *dc)
/* 00 -> 10
10 -> 00. */
/* Force addr into the temp. */
- if (addr != &t) {
- t = tcg_temp_new();
- tcg_gen_xori_tl(t, *addr, 2);
- addr = &t;
- } else {
- tcg_gen_xori_tl(t, t, 2);
- }
+ tcg_gen_xori_tl(addr, addr, 2);
break;
default:
cpu_abort(CPU(dc->cpu), "Invalid reverse size\n");
break;
}
}
- tcg_gen_qemu_st_tl(cpu_R[dc->rd], *addr, cpu_mmu_index(&dc->cpu->env, false), mop);
+ tcg_gen_qemu_st_i32(cpu_R[dc->rd], addr, mem_index, mop);
/* Verify alignment if needed. */
if ((dc->cpu->env.pvr.regs[2] & PVR2_UNALIGNED_EXC_MASK) && size > 1) {
- tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
+ tcg_gen_movi_i64(cpu_SR[SR_PC], dc->pc);
/* FIXME: if the alignment is wrong, we should restore the value
* in memory. One possible way to achieve this is to probe
* the MMU prior to the memaccess, thay way we could put
* the alignment checks in between the probe and the mem
* access.
*/
- gen_helper_memalign(cpu_env, *addr, tcg_const_tl(dc->rd),
- tcg_const_tl(1), tcg_const_tl(size - 1));
+ gen_helper_memalign(cpu_env, addr, tcg_const_i32(dc->rd),
+ tcg_const_i32(1), tcg_const_i32(size - 1));
}
if (ex) {
gen_set_label(swx_skip);
}
- tcg_temp_free(swx_addr);
- if (addr == &t)
- tcg_temp_free(t);
+ tcg_temp_free(addr);
}
static inline void eval_cc(DisasContext *dc, unsigned int cc,
- TCGv d, TCGv a, TCGv b)
+ TCGv_i32 d, TCGv_i32 a)
{
+ static const int mb_to_tcg_cc[] = {
+ [CC_EQ] = TCG_COND_EQ,
+ [CC_NE] = TCG_COND_NE,
+ [CC_LT] = TCG_COND_LT,
+ [CC_LE] = TCG_COND_LE,
+ [CC_GE] = TCG_COND_GE,
+ [CC_GT] = TCG_COND_GT,
+ };
+
switch (cc) {
- case CC_EQ:
- tcg_gen_setcond_tl(TCG_COND_EQ, d, a, b);
- break;
- case CC_NE:
- tcg_gen_setcond_tl(TCG_COND_NE, d, a, b);
- break;
- case CC_LT:
- tcg_gen_setcond_tl(TCG_COND_LT, d, a, b);
- break;
- case CC_LE:
- tcg_gen_setcond_tl(TCG_COND_LE, d, a, b);
- break;
- case CC_GE:
- tcg_gen_setcond_tl(TCG_COND_GE, d, a, b);
- break;
- case CC_GT:
- tcg_gen_setcond_tl(TCG_COND_GT, d, a, b);
- break;
- default:
- cpu_abort(CPU(dc->cpu), "Unknown condition code %x.\n", cc);
- break;
+ case CC_EQ:
+ case CC_NE:
+ case CC_LT:
+ case CC_LE:
+ case CC_GE:
+ case CC_GT:
+ tcg_gen_setcondi_i32(mb_to_tcg_cc[cc], d, a, 0);
+ break;
+ default:
+ cpu_abort(CPU(dc->cpu), "Unknown condition code %x.\n", cc);
+ break;
}
}
-static void eval_cond_jmp(DisasContext *dc, TCGv pc_true, TCGv pc_false)
+static void eval_cond_jmp(DisasContext *dc, TCGv_i64 pc_true, TCGv_i64 pc_false)
{
- TCGLabel *l1 = gen_new_label();
- /* Conditional jmp. */
- tcg_gen_mov_tl(cpu_SR[SR_PC], pc_false);
- tcg_gen_brcondi_tl(TCG_COND_EQ, env_btaken, 0, l1);
- tcg_gen_mov_tl(cpu_SR[SR_PC], pc_true);
- gen_set_label(l1);
+ TCGv_i64 tmp_btaken = tcg_temp_new_i64();
+ TCGv_i64 tmp_zero = tcg_const_i64(0);
+
+ tcg_gen_extu_i32_i64(tmp_btaken, env_btaken);
+ tcg_gen_movcond_i64(TCG_COND_NE, cpu_SR[SR_PC],
+ tmp_btaken, tmp_zero,
+ pc_true, pc_false);
+
+ tcg_temp_free_i64(tmp_btaken);
+ tcg_temp_free_i64(tmp_zero);
}
static void dec_bcc(DisasContext *dc)
@@ -1199,28 +1196,28 @@ static void dec_bcc(DisasContext *dc)
if (dslot) {
dc->delayed_branch = 2;
dc->tb_flags |= D_FLAG;
- tcg_gen_st_tl(tcg_const_tl(dc->type_b && (dc->tb_flags & IMM_FLAG)),
+ tcg_gen_st_i32(tcg_const_i32(dc->type_b && (dc->tb_flags & IMM_FLAG)),
cpu_env, offsetof(CPUMBState, bimm));
}
if (dec_alu_op_b_is_small_imm(dc)) {
int32_t offset = (int32_t)((int16_t)dc->imm); /* sign-extend. */
- tcg_gen_movi_tl(env_btarget, dc->pc + offset);
+ tcg_gen_movi_i64(env_btarget, dc->pc + offset);
dc->jmp = JMP_DIRECT_CC;
dc->jmp_pc = dc->pc + offset;
} else {
dc->jmp = JMP_INDIRECT;
- tcg_gen_movi_tl(env_btarget, dc->pc);
- tcg_gen_add_tl(env_btarget, env_btarget, *(dec_alu_op_b(dc)));
+ tcg_gen_extu_i32_i64(env_btarget, *(dec_alu_op_b(dc)));
+ tcg_gen_addi_i64(env_btarget, env_btarget, dc->pc);
+ tcg_gen_andi_i64(env_btarget, env_btarget, UINT32_MAX);
}
- eval_cc(dc, cc, env_btaken, cpu_R[dc->ra], tcg_const_tl(0));
+ eval_cc(dc, cc, env_btaken, cpu_R[dc->ra]);
}
static void dec_br(DisasContext *dc)
{
unsigned int dslot, link, abs, mbar;
- int mem_index = cpu_mmu_index(&dc->cpu->env, false);
dslot = dc->ir & (1 << 20);
abs = dc->ir & (1 << 19);
@@ -1240,7 +1237,7 @@ static void dec_br(DisasContext *dc)
tcg_gen_st_i32(tmp_1, cpu_env,
-offsetof(MicroBlazeCPU, env)
+offsetof(CPUState, halted));
- tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc + 4);
+ tcg_gen_movi_i64(cpu_SR[SR_PC], dc->pc + 4);
gen_helper_raise_exception(cpu_env, tmp_hlt);
tcg_temp_free_i32(tmp_hlt);
tcg_temp_free_i32(tmp_1);
@@ -1261,23 +1258,21 @@ static void dec_br(DisasContext *dc)
if (dslot) {
dc->delayed_branch = 2;
dc->tb_flags |= D_FLAG;
- tcg_gen_st_tl(tcg_const_tl(dc->type_b && (dc->tb_flags & IMM_FLAG)),
+ tcg_gen_st_i32(tcg_const_i32(dc->type_b && (dc->tb_flags & IMM_FLAG)),
cpu_env, offsetof(CPUMBState, bimm));
}
if (link && dc->rd)
- tcg_gen_movi_tl(cpu_R[dc->rd], dc->pc);
+ tcg_gen_movi_i32(cpu_R[dc->rd], dc->pc);
dc->jmp = JMP_INDIRECT;
if (abs) {
- tcg_gen_movi_tl(env_btaken, 1);
- tcg_gen_mov_tl(env_btarget, *(dec_alu_op_b(dc)));
+ tcg_gen_movi_i32(env_btaken, 1);
+ tcg_gen_extu_i32_i64(env_btarget, *(dec_alu_op_b(dc)));
if (link && !dslot) {
if (!(dc->tb_flags & IMM_FLAG) && (dc->imm == 8 || dc->imm == 0x18))
t_gen_raise_exception(dc, EXCP_BREAK);
if (dc->imm == 0) {
- if ((dc->tb_flags & MSR_EE_FLAG) && mem_index == MMU_USER_IDX) {
- tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
- t_gen_raise_exception(dc, EXCP_HW_EXCP);
+ if (trap_userspace(dc, true)) {
return;
}
@@ -1289,116 +1284,115 @@ static void dec_br(DisasContext *dc)
dc->jmp = JMP_DIRECT;
dc->jmp_pc = dc->pc + (int32_t)((int16_t)dc->imm);
} else {
- tcg_gen_movi_tl(env_btaken, 1);
- tcg_gen_movi_tl(env_btarget, dc->pc);
- tcg_gen_add_tl(env_btarget, env_btarget, *(dec_alu_op_b(dc)));
+ tcg_gen_movi_i32(env_btaken, 1);
+ tcg_gen_extu_i32_i64(env_btarget, *(dec_alu_op_b(dc)));
+ tcg_gen_addi_i64(env_btarget, env_btarget, dc->pc);
+ tcg_gen_andi_i64(env_btarget, env_btarget, UINT32_MAX);
}
}
}
static inline void do_rti(DisasContext *dc)
{
- TCGv t0, t1;
- t0 = tcg_temp_new();
- t1 = tcg_temp_new();
- tcg_gen_shri_tl(t0, cpu_SR[SR_MSR], 1);
- tcg_gen_ori_tl(t1, cpu_SR[SR_MSR], MSR_IE);
- tcg_gen_andi_tl(t0, t0, (MSR_VM | MSR_UM));
-
- tcg_gen_andi_tl(t1, t1, ~(MSR_VM | MSR_UM));
- tcg_gen_or_tl(t1, t1, t0);
+ TCGv_i32 t0, t1;
+ t0 = tcg_temp_new_i32();
+ t1 = tcg_temp_new_i32();
+ tcg_gen_extrl_i64_i32(t1, cpu_SR[SR_MSR]);
+ tcg_gen_shri_i32(t0, t1, 1);
+ tcg_gen_ori_i32(t1, t1, MSR_IE);
+ tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM));
+
+ tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM));
+ tcg_gen_or_i32(t1, t1, t0);
msr_write(dc, t1);
- tcg_temp_free(t1);
- tcg_temp_free(t0);
+ tcg_temp_free_i32(t1);
+ tcg_temp_free_i32(t0);
dc->tb_flags &= ~DRTI_FLAG;
}
static inline void do_rtb(DisasContext *dc)
{
- TCGv t0, t1;
- t0 = tcg_temp_new();
- t1 = tcg_temp_new();
- tcg_gen_andi_tl(t1, cpu_SR[SR_MSR], ~MSR_BIP);
- tcg_gen_shri_tl(t0, t1, 1);
- tcg_gen_andi_tl(t0, t0, (MSR_VM | MSR_UM));
-
- tcg_gen_andi_tl(t1, t1, ~(MSR_VM | MSR_UM));
- tcg_gen_or_tl(t1, t1, t0);
+ TCGv_i32 t0, t1;
+ t0 = tcg_temp_new_i32();
+ t1 = tcg_temp_new_i32();
+ tcg_gen_extrl_i64_i32(t1, cpu_SR[SR_MSR]);
+ tcg_gen_andi_i32(t1, t1, ~MSR_BIP);
+ tcg_gen_shri_i32(t0, t1, 1);
+ tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM));
+
+ tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM));
+ tcg_gen_or_i32(t1, t1, t0);
msr_write(dc, t1);
- tcg_temp_free(t1);
- tcg_temp_free(t0);
+ tcg_temp_free_i32(t1);
+ tcg_temp_free_i32(t0);
dc->tb_flags &= ~DRTB_FLAG;
}
static inline void do_rte(DisasContext *dc)
{
- TCGv t0, t1;
- t0 = tcg_temp_new();
- t1 = tcg_temp_new();
-
- tcg_gen_ori_tl(t1, cpu_SR[SR_MSR], MSR_EE);
- tcg_gen_andi_tl(t1, t1, ~MSR_EIP);
- tcg_gen_shri_tl(t0, t1, 1);
- tcg_gen_andi_tl(t0, t0, (MSR_VM | MSR_UM));
-
- tcg_gen_andi_tl(t1, t1, ~(MSR_VM | MSR_UM));
- tcg_gen_or_tl(t1, t1, t0);
+ TCGv_i32 t0, t1;
+ t0 = tcg_temp_new_i32();
+ t1 = tcg_temp_new_i32();
+
+ tcg_gen_extrl_i64_i32(t1, cpu_SR[SR_MSR]);
+ tcg_gen_ori_i32(t1, t1, MSR_EE);
+ tcg_gen_andi_i32(t1, t1, ~MSR_EIP);
+ tcg_gen_shri_i32(t0, t1, 1);
+ tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM));
+
+ tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM));
+ tcg_gen_or_i32(t1, t1, t0);
msr_write(dc, t1);
- tcg_temp_free(t1);
- tcg_temp_free(t0);
+ tcg_temp_free_i32(t1);
+ tcg_temp_free_i32(t0);
dc->tb_flags &= ~DRTE_FLAG;
}
static void dec_rts(DisasContext *dc)
{
unsigned int b_bit, i_bit, e_bit;
- int mem_index = cpu_mmu_index(&dc->cpu->env, false);
+ TCGv_i64 tmp64;
i_bit = dc->ir & (1 << 21);
b_bit = dc->ir & (1 << 22);
e_bit = dc->ir & (1 << 23);
+ if (trap_userspace(dc, i_bit || b_bit || e_bit)) {
+ return;
+ }
+
dc->delayed_branch = 2;
dc->tb_flags |= D_FLAG;
- tcg_gen_st_tl(tcg_const_tl(dc->type_b && (dc->tb_flags & IMM_FLAG)),
+ tcg_gen_st_i32(tcg_const_i32(dc->type_b && (dc->tb_flags & IMM_FLAG)),
cpu_env, offsetof(CPUMBState, bimm));
if (i_bit) {
LOG_DIS("rtid ir=%x\n", dc->ir);
- if ((dc->tb_flags & MSR_EE_FLAG)
- && mem_index == MMU_USER_IDX) {
- tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
- t_gen_raise_exception(dc, EXCP_HW_EXCP);
- }
dc->tb_flags |= DRTI_FLAG;
} else if (b_bit) {
LOG_DIS("rtbd ir=%x\n", dc->ir);
- if ((dc->tb_flags & MSR_EE_FLAG)
- && mem_index == MMU_USER_IDX) {
- tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
- t_gen_raise_exception(dc, EXCP_HW_EXCP);
- }
dc->tb_flags |= DRTB_FLAG;
} else if (e_bit) {
LOG_DIS("rted ir=%x\n", dc->ir);
- if ((dc->tb_flags & MSR_EE_FLAG)
- && mem_index == MMU_USER_IDX) {
- tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
- t_gen_raise_exception(dc, EXCP_HW_EXCP);
- }
dc->tb_flags |= DRTE_FLAG;
} else
LOG_DIS("rts ir=%x\n", dc->ir);
dc->jmp = JMP_INDIRECT;
- tcg_gen_movi_tl(env_btaken, 1);
- tcg_gen_add_tl(env_btarget, cpu_R[dc->ra], *(dec_alu_op_b(dc)));
+ tcg_gen_movi_i32(env_btaken, 1);
+
+ tmp64 = tcg_temp_new_i64();
+ tcg_gen_extu_i32_i64(env_btarget, *(dec_alu_op_b(dc)));
+ tcg_gen_extu_i32_i64(tmp64, cpu_R[dc->ra]);
+ tcg_gen_add_i64(env_btarget, env_btarget, tmp64);
+ tcg_gen_andi_i64(env_btarget, env_btarget, UINT32_MAX);
+ tcg_temp_free_i64(tmp64);
}
static int dec_check_fpuv2(DisasContext *dc)
{
if ((dc->cpu->cfg.use_fpu != 2) && (dc->tb_flags & MSR_EE_FLAG)) {
- tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_FPU);
+ tcg_gen_movi_i64(cpu_SR[SR_ESR], ESR_EC_FPU);
t_gen_raise_exception(dc, EXCP_HW_EXCP);
}
return (dc->cpu->cfg.use_fpu == 2) ? 0 : PVR2_USE_FPU2_MASK;
@@ -1408,11 +1402,7 @@ static void dec_fpu(DisasContext *dc)
{
unsigned int fpu_insn;
- if ((dc->tb_flags & MSR_EE_FLAG)
- && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
- && !dc->cpu->cfg.use_fpu) {
- tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
- t_gen_raise_exception(dc, EXCP_HW_EXCP);
+ if (trap_illegal(dc, !dc->cpu->cfg.use_fpu)) {
return;
}
@@ -1511,10 +1501,7 @@ static void dec_fpu(DisasContext *dc)
static void dec_null(DisasContext *dc)
{
- if ((dc->tb_flags & MSR_EE_FLAG)
- && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
- tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
- t_gen_raise_exception(dc, EXCP_HW_EXCP);
+ if (trap_illegal(dc, true)) {
return;
}
qemu_log_mask(LOG_GUEST_ERROR, "unknown insn pc=%x opc=%x\n", dc->pc, dc->opcode);
@@ -1524,37 +1511,34 @@ static void dec_null(DisasContext *dc)
/* Insns connected to FSL or AXI stream attached devices. */
static void dec_stream(DisasContext *dc)
{
- int mem_index = cpu_mmu_index(&dc->cpu->env, false);
TCGv_i32 t_id, t_ctrl;
int ctrl;
LOG_DIS("%s%s imm=%x\n", dc->rd ? "get" : "put",
dc->type_b ? "" : "d", dc->imm);
- if ((dc->tb_flags & MSR_EE_FLAG) && (mem_index == MMU_USER_IDX)) {
- tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
- t_gen_raise_exception(dc, EXCP_HW_EXCP);
+ if (trap_userspace(dc, true)) {
return;
}
- t_id = tcg_temp_new();
+ t_id = tcg_temp_new_i32();
if (dc->type_b) {
- tcg_gen_movi_tl(t_id, dc->imm & 0xf);
+ tcg_gen_movi_i32(t_id, dc->imm & 0xf);
ctrl = dc->imm >> 10;
} else {
- tcg_gen_andi_tl(t_id, cpu_R[dc->rb], 0xf);
+ tcg_gen_andi_i32(t_id, cpu_R[dc->rb], 0xf);
ctrl = dc->imm >> 5;
}
- t_ctrl = tcg_const_tl(ctrl);
+ t_ctrl = tcg_const_i32(ctrl);
if (dc->rd == 0) {
gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]);
} else {
gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl);
}
- tcg_temp_free(t_id);
- tcg_temp_free(t_ctrl);
+ tcg_temp_free_i32(t_id);
+ tcg_temp_free_i32(t_ctrl);
}
static struct decoder_info {
@@ -1595,13 +1579,7 @@ static inline void decode(DisasContext *dc, uint32_t ir)
if (dc->ir)
dc->nr_nops = 0;
else {
- if ((dc->tb_flags & MSR_EE_FLAG)
- && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
- && (dc->cpu->env.pvr.regs[2] & PVR2_OPCODE_0x0_ILL_MASK)) {
- tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
- t_gen_raise_exception(dc, EXCP_HW_EXCP);
- return;
- }
+ trap_illegal(dc, dc->cpu->env.pvr.regs[2] & PVR2_OPCODE_0x0_ILL_MASK);
LOG_DIS("nr_nops=%d\t", dc->nr_nops);
dc->nr_nops++;
@@ -1636,7 +1614,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
struct DisasContext ctx;
struct DisasContext *dc = &ctx;
uint32_t page_start, org_flags;
- target_ulong npc;
+ uint32_t npc;
int num_insns;
int max_insns;
@@ -1679,7 +1657,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
#if SIM_COMPAT
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
- tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
+ tcg_gen_movi_i64(cpu_SR[SR_PC], dc->pc);
gen_helper_debug();
}
#endif
@@ -1721,7 +1699,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
dc->tb_flags &= ~D_FLAG;
/* If it is a direct jump, try direct chaining. */
if (dc->jmp == JMP_INDIRECT) {
- eval_cond_jmp(dc, env_btarget, tcg_const_tl(dc->pc));
+ eval_cond_jmp(dc, env_btarget, tcg_const_i64(dc->pc));
dc->is_jmp = DISAS_JUMP;
} else if (dc->jmp == JMP_DIRECT) {
t_sync_flags(dc);
@@ -1731,7 +1709,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
TCGLabel *l1 = gen_new_label();
t_sync_flags(dc);
/* Conditional jmp. */
- tcg_gen_brcondi_tl(TCG_COND_NE, env_btaken, 0, l1);
+ tcg_gen_brcondi_i32(TCG_COND_NE, env_btaken, 0, l1);
gen_goto_tb(dc, 1, dc->pc);
gen_set_label(l1);
gen_goto_tb(dc, 0, dc->jmp_pc);
@@ -1754,7 +1732,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {
if (dc->tb_flags & D_FLAG) {
dc->is_jmp = DISAS_UPDATE;
- tcg_gen_movi_tl(cpu_SR[SR_PC], npc);
+ tcg_gen_movi_i64(cpu_SR[SR_PC], npc);
sync_jmpstate(dc);
} else
npc = dc->jmp_pc;
@@ -1766,7 +1744,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
if (dc->is_jmp == DISAS_NEXT
&& (dc->cpustate_changed || org_flags != dc->tb_flags)) {
dc->is_jmp = DISAS_UPDATE;
- tcg_gen_movi_tl(cpu_SR[SR_PC], npc);
+ tcg_gen_movi_i64(cpu_SR[SR_PC], npc);
}
t_sync_flags(dc);
@@ -1774,7 +1752,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);
if (dc->is_jmp != DISAS_JUMP) {
- tcg_gen_movi_tl(cpu_SR[SR_PC], npc);
+ tcg_gen_movi_i64(cpu_SR[SR_PC], npc);
}
gen_helper_raise_exception(cpu_env, tmp);
tcg_temp_free_i32(tmp);
@@ -1824,17 +1802,19 @@ void mb_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
if (!env || !f)
return;
- cpu_fprintf(f, "IN: PC=%x %s\n",
+ cpu_fprintf(f, "IN: PC=%" PRIx64 " %s\n",
env->sregs[SR_PC], lookup_symbol(env->sregs[SR_PC]));
- cpu_fprintf(f, "rmsr=%x resr=%x rear=%x debug=%x imm=%x iflags=%x fsr=%x\n",
+ cpu_fprintf(f, "rmsr=%" PRIx64 " resr=%" PRIx64 " rear=%" PRIx64 " "
+ "debug=%x imm=%x iflags=%x fsr=%" PRIx64 "\n",
env->sregs[SR_MSR], env->sregs[SR_ESR], env->sregs[SR_EAR],
env->debug, env->imm, env->iflags, env->sregs[SR_FSR]);
- cpu_fprintf(f, "btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n",
+ cpu_fprintf(f, "btaken=%d btarget=%" PRIx64 " mode=%s(saved=%s) "
+ "eip=%d ie=%d\n",
env->btaken, env->btarget,
(env->sregs[SR_MSR] & MSR_UM) ? "user" : "kernel",
(env->sregs[SR_MSR] & MSR_UMS) ? "user" : "kernel",
- (env->sregs[SR_MSR] & MSR_EIP),
- (env->sregs[SR_MSR] & MSR_IE));
+ (bool)(env->sregs[SR_MSR] & MSR_EIP),
+ (bool)(env->sregs[SR_MSR] & MSR_IE));
for (i = 0; i < 32; i++) {
cpu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]);
@@ -1848,34 +1828,34 @@ void mb_tcg_init(void)
{
int i;
- env_debug = tcg_global_mem_new(cpu_env,
+ env_debug = tcg_global_mem_new_i32(cpu_env,
offsetof(CPUMBState, debug),
"debug0");
- env_iflags = tcg_global_mem_new(cpu_env,
+ env_iflags = tcg_global_mem_new_i32(cpu_env,
offsetof(CPUMBState, iflags),
"iflags");
- env_imm = tcg_global_mem_new(cpu_env,
+ env_imm = tcg_global_mem_new_i32(cpu_env,
offsetof(CPUMBState, imm),
"imm");
- env_btarget = tcg_global_mem_new(cpu_env,
+ env_btarget = tcg_global_mem_new_i64(cpu_env,
offsetof(CPUMBState, btarget),
"btarget");
- env_btaken = tcg_global_mem_new(cpu_env,
+ env_btaken = tcg_global_mem_new_i32(cpu_env,
offsetof(CPUMBState, btaken),
"btaken");
env_res_addr = tcg_global_mem_new(cpu_env,
offsetof(CPUMBState, res_addr),
"res_addr");
- env_res_val = tcg_global_mem_new(cpu_env,
+ env_res_val = tcg_global_mem_new_i32(cpu_env,
offsetof(CPUMBState, res_val),
"res_val");
for (i = 0; i < ARRAY_SIZE(cpu_R); i++) {
- cpu_R[i] = tcg_global_mem_new(cpu_env,
+ cpu_R[i] = tcg_global_mem_new_i32(cpu_env,
offsetof(CPUMBState, regs[i]),
regnames[i]);
}
for (i = 0; i < ARRAY_SIZE(cpu_SR); i++) {
- cpu_SR[i] = tcg_global_mem_new(cpu_env,
+ cpu_SR[i] = tcg_global_mem_new_i64(cpu_env,
offsetof(CPUMBState, sregs[i]),
special_regnames[i]);
}
diff --git a/target/moxie/cpu.c b/target/moxie/cpu.c
index 4170284da6..8d67eb6727 100644
--- a/target/moxie/cpu.c
+++ b/target/moxie/cpu.c
@@ -23,7 +23,6 @@
#include "qemu-common.h"
#include "migration/vmstate.h"
#include "machine.h"
-#include "exec/exec-all.h"
static void moxie_cpu_set_pc(CPUState *cs, vaddr value)
{
diff --git a/target/moxie/mmu.c b/target/moxie/mmu.c
index 9203330b3b..bd90b1eebc 100644
--- a/target/moxie/mmu.c
+++ b/target/moxie/mmu.c
@@ -21,7 +21,6 @@
#include "cpu.h"
#include "mmu.h"
-#include "exec/exec-all.h"
int moxie_mmu_translate(MoxieMMUResult *res,
CPUMoxieState *env, uint32_t vaddr,
diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
index 145796e8ce..047f3764b7 100644
--- a/target/nios2/cpu.h
+++ b/target/nios2/cpu.h
@@ -260,7 +260,6 @@ static inline int cpu_interrupts_enabled(CPUNios2State *env)
}
#include "exec/cpu-all.h"
-#include "exec/exec-all.h"
static inline void cpu_get_tb_cpu_state(CPUNios2State *env, target_ulong *pc,
target_ulong *cs_base, uint32_t *flags)
diff --git a/target/nios2/op_helper.c b/target/nios2/op_helper.c
index c853aeae02..529ec6ac0e 100644
--- a/target/nios2/op_helper.c
+++ b/target/nios2/op_helper.c
@@ -22,6 +22,7 @@
#include "cpu.h"
#include "exec/helper-proto.h"
#include "exec/cpu_ldst.h"
+#include "exec/exec-all.h"
#include "qemu/main-loop.h"
#if !defined(CONFIG_USER_ONLY)
diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c
index 20b115afae..a692a98ec0 100644
--- a/target/openrisc/cpu.c
+++ b/target/openrisc/cpu.c
@@ -21,7 +21,6 @@
#include "qapi/error.h"
#include "cpu.h"
#include "qemu-common.h"
-#include "exec/exec-all.h"
static void openrisc_cpu_set_pc(CPUState *cs, vaddr value)
{
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 7ccd2f460e..0247c1f04c 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1215,7 +1215,7 @@ struct PowerPCCPU {
uint64_t mig_insns_flags2;
uint32_t mig_nb_BATs;
bool pre_2_10_migration;
- bool pre_2_13_migration;
+ bool pre_3_0_migration;
int32_t mig_slb_nr;
};
diff --git a/target/ppc/helper_regs.h b/target/ppc/helper_regs.h
index 84fd30c2db..5efd18049e 100644
--- a/target/ppc/helper_regs.h
+++ b/target/ppc/helper_regs.h
@@ -21,6 +21,7 @@
#define HELPER_REGS_H
#include "qemu/main-loop.h"
+#include "exec/exec-all.h"
/* Swap temporary saved registers with GPRs */
static inline void hreg_swap_gpr_tgpr(CPUPPCState *env)
diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c
index 1607a7a42b..03d37da79f 100644
--- a/target/ppc/int_helper.c
+++ b/target/ppc/int_helper.c
@@ -19,7 +19,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
-#include "exec/exec-all.h"
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
#include "crypto/aes.h"
diff --git a/target/ppc/machine.c b/target/ppc/machine.c
index ba1b9e531f..b2745ec4e5 100644
--- a/target/ppc/machine.c
+++ b/target/ppc/machine.c
@@ -150,11 +150,11 @@ static bool cpu_pre_2_8_migration(void *opaque, int version_id)
}
#if defined(TARGET_PPC64)
-static bool cpu_pre_2_13_migration(void *opaque, int version_id)
+static bool cpu_pre_3_0_migration(void *opaque, int version_id)
{
PowerPCCPU *cpu = opaque;
- return cpu->pre_2_13_migration;
+ return cpu->pre_3_0_migration;
}
#endif
@@ -220,7 +220,7 @@ static int cpu_pre_save(void *opaque)
cpu->mig_insns_flags2 = env->insns_flags2 & insns_compat_mask2;
cpu->mig_nb_BATs = env->nb_BATs;
}
- if (cpu->pre_2_13_migration) {
+ if (cpu->pre_3_0_migration) {
if (cpu->hash64_opts) {
cpu->mig_slb_nr = cpu->hash64_opts->slb_size;
}
@@ -517,7 +517,7 @@ static const VMStateDescription vmstate_slb = {
.needed = slb_needed,
.post_load = slb_post_load,
.fields = (VMStateField[]) {
- VMSTATE_INT32_TEST(mig_slb_nr, PowerPCCPU, cpu_pre_2_13_migration),
+ VMSTATE_INT32_TEST(mig_slb_nr, PowerPCCPU, cpu_pre_3_0_migration),
VMSTATE_SLB_ARRAY(env.slb, PowerPCCPU, MAX_SLB_ENTRIES),
VMSTATE_END_OF_LIST()
}
diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
index a1db20e3a8..aa200cba4c 100644
--- a/target/ppc/mmu-hash64.c
+++ b/target/ppc/mmu-hash64.c
@@ -431,7 +431,8 @@ const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,
return NULL;
}
- hptes = address_space_map(CPU(cpu)->as, base + pte_offset, &plen, false);
+ hptes = address_space_map(CPU(cpu)->as, base + pte_offset, &plen, false,
+ MEMTXATTRS_UNSPECIFIED);
if (plen < (n * HASH_PTE_SIZE_64)) {
hw_error("%s: Unable to map all requested HPTEs\n", __func__);
}
diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c
index a0b3f184b2..ab782cb32a 100644
--- a/target/ppc/translate_init.inc.c
+++ b/target/ppc/translate_init.inc.c
@@ -10427,7 +10427,7 @@ static Property ppc_cpu_properties[] = {
DEFINE_PROP_BOOL("pre-2.8-migration", PowerPCCPU, pre_2_8_migration, false),
DEFINE_PROP_BOOL("pre-2.10-migration", PowerPCCPU, pre_2_10_migration,
false),
- DEFINE_PROP_BOOL("pre-2.13-migration", PowerPCCPU, pre_2_13_migration,
+ DEFINE_PROP_BOOL("pre-3.0-migration", PowerPCCPU, pre_3_0_migration,
false),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/target/riscv/helper.c b/target/riscv/helper.c
index 95889f23b9..29e1a603dc 100644
--- a/target/riscv/helper.c
+++ b/target/riscv/helper.c
@@ -210,7 +210,7 @@ restart:
MemoryRegion *mr;
hwaddr l = sizeof(target_ulong), addr1;
mr = address_space_translate(cs->as, pte_addr,
- &addr1, &l, false);
+ &addr1, &l, false, MEMTXATTRS_UNSPECIFIED);
if (memory_access_is_direct(mr, true)) {
target_ulong *pte_pa =
qemu_map_ram_ptr(mr->ram_block, addr1);
diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
index c2b775f4eb..c268065887 100644
--- a/target/s390x/cpu.c
+++ b/target/s390x/cpu.c
@@ -38,7 +38,6 @@
#include "qapi/qapi-visit-misc.h"
#include "qapi/qapi-visit-run-state.h"
#include "sysemu/hw_accel.h"
-#include "exec/exec-all.h"
#include "hw/qdev-properties.h"
#ifndef CONFIG_USER_ONLY
#include "hw/hw.h"
diff --git a/target/s390x/diag.c b/target/s390x/diag.c
index ac2c40f363..acb0f3d4af 100644
--- a/target/s390x/diag.c
+++ b/target/s390x/diag.c
@@ -16,7 +16,6 @@
#include "cpu.h"
#include "internal.h"
#include "exec/address-spaces.h"
-#include "exec/exec-all.h"
#include "hw/watchdog/wdt_diag288.h"
#include "sysemu/cpus.h"
#include "hw/s390x/ipl.h"
@@ -87,7 +86,8 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
return;
}
if (!address_space_access_valid(&address_space_memory, addr,
- sizeof(IplParameterBlock), false)) {
+ sizeof(IplParameterBlock), false,
+ MEMTXATTRS_UNSPECIFIED)) {
s390_program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO, ra);
return;
}
@@ -116,7 +116,8 @@ out:
return;
}
if (!address_space_access_valid(&address_space_memory, addr,
- sizeof(IplParameterBlock), true)) {
+ sizeof(IplParameterBlock), true,
+ MEMTXATTRS_UNSPECIFIED)) {
s390_program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO, ra);
return;
}
diff --git a/target/s390x/excp_helper.c b/target/s390x/excp_helper.c
index dfee221111..f0ce60cff2 100644
--- a/target/s390x/excp_helper.c
+++ b/target/s390x/excp_helper.c
@@ -120,7 +120,8 @@ int s390_cpu_handle_mmu_fault(CPUState *cs, vaddr orig_vaddr, int size,
/* check out of RAM access */
if (!address_space_access_valid(&address_space_memory, raddr,
- TARGET_PAGE_SIZE, rw)) {
+ TARGET_PAGE_SIZE, rw,
+ MEMTXATTRS_UNSPECIFIED)) {
DPRINTF("%s: raddr %" PRIx64 " > ram_size %" PRIx64 "\n", __func__,
(uint64_t)raddr, (uint64_t)ram_size);
trigger_pgm_exception(env, PGM_ADDRESSING, ILEN_AUTO);
diff --git a/target/s390x/helper.c b/target/s390x/helper.c
index fd5791f134..254631693d 100644
--- a/target/s390x/helper.c
+++ b/target/s390x/helper.c
@@ -23,7 +23,6 @@
#include "internal.h"
#include "exec/gdbstub.h"
#include "qemu/timer.h"
-#include "exec/exec-all.h"
#include "hw/s390x/ioinst.h"
#include "sysemu/hw_accel.h"
#ifndef CONFIG_USER_ONLY
diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
index 58e4380ae3..ac370da281 100644
--- a/target/s390x/kvm.c
+++ b/target/s390x/kvm.c
@@ -39,7 +39,6 @@
#include "hw/hw.h"
#include "sysemu/device_tree.h"
#include "exec/gdbstub.h"
-#include "exec/address-spaces.h"
#include "trace.h"
#include "hw/s390x/s390-pci-inst.h"
#include "hw/s390x/s390-pci-bus.h"
diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c
index a0e28bd124..e21a47fb4d 100644
--- a/target/s390x/mem_helper.c
+++ b/target/s390x/mem_helper.c
@@ -21,7 +21,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
-#include "exec/address-spaces.h"
#include "exec/helper-proto.h"
#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c
index 1f834f35ef..de1ced2082 100644
--- a/target/s390x/misc_helper.c
+++ b/target/s390x/misc_helper.c
@@ -26,7 +26,6 @@
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
#include "qemu/timer.h"
-#include "exec/address-spaces.h"
#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
diff --git a/target/s390x/mmu_helper.c b/target/s390x/mmu_helper.c
index a25deef5dd..145b62a7ef 100644
--- a/target/s390x/mmu_helper.c
+++ b/target/s390x/mmu_helper.c
@@ -461,7 +461,8 @@ static int translate_pages(S390CPU *cpu, vaddr addr, int nr_pages,
return ret;
}
if (!address_space_access_valid(&address_space_memory, pages[i],
- TARGET_PAGE_SIZE, is_write)) {
+ TARGET_PAGE_SIZE, is_write,
+ MEMTXATTRS_UNSPECIFIED)) {
trigger_access_exception(env, PGM_ADDRESSING, ILEN_AUTO, 0);
return -EFAULT;
}
diff --git a/target/s390x/sigp.c b/target/s390x/sigp.c
index aff1530c82..c1f9245797 100644
--- a/target/s390x/sigp.c
+++ b/target/s390x/sigp.c
@@ -280,7 +280,8 @@ static void sigp_set_prefix(CPUState *cs, run_on_cpu_data arg)
cpu_synchronize_state(cs);
if (!address_space_access_valid(&address_space_memory, addr,
- sizeof(struct LowCore), false)) {
+ sizeof(struct LowCore), false,
+ MEMTXATTRS_UNSPECIFIED)) {
set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
return;
}
diff --git a/target/sparc/mmu_helper.c b/target/sparc/mmu_helper.c
index f8886ae039..135a9c9d9b 100644
--- a/target/sparc/mmu_helper.c
+++ b/target/sparc/mmu_helper.c
@@ -21,7 +21,6 @@
#include "cpu.h"
#include "exec/exec-all.h"
#include "trace.h"
-#include "exec/address-spaces.h"
/* Sparc MMU emulation */
diff --git a/target/tilegx/cpu.c b/target/tilegx/cpu.c
index b7451bdcf2..bfe9be59b5 100644
--- a/target/tilegx/cpu.c
+++ b/target/tilegx/cpu.c
@@ -24,7 +24,6 @@
#include "qemu-common.h"
#include "hw/qdev-properties.h"
#include "linux-user/syscall_defs.h"
-#include "exec/exec-all.h"
static void tilegx_cpu_dump_state(CPUState *cs, FILE *f,
fprintf_function cpu_fprintf, int flags)
diff --git a/target/xtensa/core-dc232b.c b/target/xtensa/core-dc232b.c
index 7331eeea2f..7131337840 100644
--- a/target/xtensa/core-dc232b.c
+++ b/target/xtensa/core-dc232b.c
@@ -27,9 +27,9 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "exec/exec-all.h"
#include "exec/gdbstub.h"
#include "qemu/host-utils.h"
+#include "qemu/timer.h"
#include "core-dc232b/core-isa.h"
#include "overlay_tool.h"
diff --git a/target/xtensa/core-dc233c.c b/target/xtensa/core-dc233c.c
index 8296e6fa10..d701e3f5de 100644
--- a/target/xtensa/core-dc233c.c
+++ b/target/xtensa/core-dc233c.c
@@ -27,7 +27,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "exec/exec-all.h"
#include "exec/gdbstub.h"
#include "qemu-common.h"
#include "qemu/host-utils.h"
diff --git a/target/xtensa/core-de212.c b/target/xtensa/core-de212.c
index 53775a97fa..7322179b56 100644
--- a/target/xtensa/core-de212.c
+++ b/target/xtensa/core-de212.c
@@ -27,7 +27,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "exec/exec-all.h"
#include "exec/gdbstub.h"
#include "qemu-common.h"
#include "qemu/host-utils.h"
diff --git a/target/xtensa/core-fsf.c b/target/xtensa/core-fsf.c
index 01932bdc8b..e100e212b9 100644
--- a/target/xtensa/core-fsf.c
+++ b/target/xtensa/core-fsf.c
@@ -27,7 +27,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "exec/exec-all.h"
#include "exec/gdbstub.h"
#include "qemu-common.h"
#include "qemu/host-utils.h"
diff --git a/target/xtensa/core-sample_controller.c b/target/xtensa/core-sample_controller.c
index c622335ca5..f433ea8d66 100644
--- a/target/xtensa/core-sample_controller.c
+++ b/target/xtensa/core-sample_controller.c
@@ -27,7 +27,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "exec/exec-all.h"
#include "exec/gdbstub.h"
#include "qemu-common.h"
#include "qemu/host-utils.h"
diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c
index 2b5b537222..b50c840e09 100644
--- a/target/xtensa/cpu.c
+++ b/target/xtensa/cpu.c
@@ -33,7 +33,6 @@
#include "cpu.h"
#include "qemu-common.h"
#include "migration/vmstate.h"
-#include "exec/exec-all.h"
static void xtensa_cpu_set_pc(CPUState *cs, vaddr value)
diff --git a/target/xtensa/import_core.sh b/target/xtensa/import_core.sh
index af6c610479..039406bf28 100755
--- a/target/xtensa/import_core.sh
+++ b/target/xtensa/import_core.sh
@@ -39,7 +39,6 @@ tar -xf "$OVERLAY" -O binutils/xtensa-modules.c | \
cat <<EOF > "${TARGET}.c"
#include "qemu/osdep.h"
#include "cpu.h"
-#include "exec/exec-all.h"
#include "exec/gdbstub.h"
#include "qemu-common.h"
#include "qemu/host-utils.h"
diff --git a/target/xtensa/op_helper.c b/target/xtensa/op_helper.c
index e3bcbe10d6..8a8c763c63 100644
--- a/target/xtensa/op_helper.c
+++ b/target/xtensa/op_helper.c
@@ -105,7 +105,8 @@ static void tb_invalidate_virtual_addr(CPUXtensaState *env, uint32_t vaddr)
int ret = xtensa_get_physical_addr(env, false, vaddr, 2, 0,
&paddr, &page_size, &access);
if (ret == 0) {
- tb_invalidate_phys_addr(&address_space_memory, paddr);
+ tb_invalidate_phys_addr(&address_space_memory, paddr,
+ MEMTXATTRS_UNSPECIFIED);
}
}
diff --git a/tcg/tcg-op-vec.c b/tcg/tcg-op-vec.c
index 2ca219734d..cefba3d185 100644
--- a/tcg/tcg-op-vec.c
+++ b/tcg/tcg-op-vec.c
@@ -20,7 +20,6 @@
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "cpu.h"
-#include "exec/exec-all.h"
#include "tcg.h"
#include "tcg-op.h"
#include "tcg-mo.h"
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 3b9a5e31a2..86f90c0cb0 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -297,6 +297,7 @@ check-qtest-i386-$(CONFIG_VHOST_USER_NET_TEST_i386) += tests/vhost-user-test$(EX
ifeq ($(CONFIG_VHOST_USER_NET_TEST_i386),)
check-qtest-x86_64-$(CONFIG_VHOST_USER_NET_TEST_x86_64) += tests/vhost-user-test$(EXESUF)
endif
+check-qtest-i386-$(CONFIG_TPM) += tests/tpm-crb-swtpm-test$(EXESUF)
check-qtest-i386-$(CONFIG_TPM) += tests/tpm-crb-test$(EXESUF)
check-qtest-i386-$(CONFIG_TPM) += tests/tpm-tis-test$(EXESUF)
check-qtest-i386-$(CONFIG_SLIRP) += tests/test-netfilter$(EXESUF)
@@ -524,6 +525,7 @@ qapi-schema += missing-type.json
qapi-schema += nested-struct-data.json
qapi-schema += non-objects.json
qapi-schema += oob-test.json
+qapi-schema += allow-preconfig-test.json
qapi-schema += pragma-doc-required-crap.json
qapi-schema += pragma-extra-junk.json
qapi-schema += pragma-name-case-whitelist-crap.json
@@ -721,6 +723,8 @@ tests/test-util-sockets$(EXESUF): tests/test-util-sockets.o \
tests/test-io-task$(EXESUF): tests/test-io-task.o $(test-io-obj-y)
tests/test-io-channel-socket$(EXESUF): tests/test-io-channel-socket.o \
tests/io-channel-helpers.o tests/socket-helpers.o $(test-io-obj-y)
+tests/tpm-crb-swtpm-test$(EXESUF): tests/tpm-crb-swtpm-test.o tests/tpm-emu.o \
+ tests/tpm-util.o $(test-io-obj-y)
tests/tpm-crb-test$(EXESUF): tests/tpm-crb-test.o tests/tpm-emu.o $(test-io-obj-y)
tests/tpm-tis-test$(EXESUF): tests/tpm-tis-test.o tests/tpm-emu.o $(test-io-obj-y)
tests/test-io-channel-file$(EXESUF): tests/test-io-channel-file.o \
diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include
index ef1a3e62eb..31f21a43f5 100644
--- a/tests/docker/Makefile.include
+++ b/tests/docker/Makefile.include
@@ -4,7 +4,8 @@
DOCKER_SUFFIX := .docker
DOCKER_FILES_DIR := $(SRC_PATH)/tests/docker/dockerfiles
-DOCKER_IMAGES := $(notdir $(basename $(wildcard $(DOCKER_FILES_DIR)/*.docker)))
+DOCKER_DEPRECATED_IMAGES := debian
+DOCKER_IMAGES := $(filter-out $(DOCKER_DEPRECATED_IMAGES),$(sort $(notdir $(basename $(wildcard $(DOCKER_FILES_DIR)/*.docker)))))
DOCKER_TARGETS := $(patsubst %,docker-image-%,$(DOCKER_IMAGES))
# Use a global constant ccache directory to speed up repetitive builds
DOCKER_CCACHE_DIR := $$HOME/.cache/qemu-docker-ccache
@@ -63,7 +64,7 @@ docker-image-debian-win64-cross: docker-image-debian8-mxe
docker-image-travis: NOUSER=1
# Expand all the pre-requistes for each docker image and test combination
-$(foreach i,$(DOCKER_IMAGES), \
+$(foreach i,$(DOCKER_IMAGES) $(DOCKER_DEPRECATED_IMAGES), \
$(foreach t,$(DOCKER_TESTS) $(DOCKER_TOOLS), \
$(eval .PHONY: docker-$t@$i) \
$(eval docker-$t@$i: docker-image-$i docker-run-$t@$i) \
diff --git a/tests/docker/dockerfiles/travis.docker b/tests/docker/dockerfiles/travis.docker
index 605b6e429b..c5ad39b533 100644
--- a/tests/docker/dockerfiles/travis.docker
+++ b/tests/docker/dockerfiles/travis.docker
@@ -1,8 +1,13 @@
-FROM quay.io/travisci/travis-ruby
+FROM travisci/ci-garnet:packer-1512502276-986baf0
ENV DEBIAN_FRONTEND noninteractive
ENV LANG en_US.UTF-8
ENV LC_ALL en_US.UTF-8
+RUN cat /etc/apt/sources.list | sed "s/# deb-src/deb-src/" >> /etc/apt/sources.list
RUN apt-get update
RUN apt-get -y build-dep qemu
RUN apt-get -y install device-tree-compiler python2.7 python-yaml dh-autoreconf gdb strace lsof net-tools
-ENV FEATURES pyyaml
+# Travis tools require PhantomJS / Neo4j / Maven accessible
+# in their PATH (QEMU build won't access them).
+ENV PATH /usr/local/phantomjs/bin:/usr/local/phantomjs:/usr/local/neo4j-3.2.7/bin:/usr/local/maven-3.5.2/bin:/usr/local/cmake-3.9.2/bin:/usr/local/clang-5.0.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
+ENV FEATURES clang pyyaml
+USER travis
diff --git a/tests/libqtest.c b/tests/libqtest.c
index f869854849..098af6aec4 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -1105,3 +1105,10 @@ void qtest_qmp_device_del(const char *id)
qobject_unref(response1);
qobject_unref(response2);
}
+
+bool qmp_rsp_is_err(QDict *rsp)
+{
+ QDict *error = qdict_get_qdict(rsp, "error");
+ qobject_unref(rsp);
+ return !!error;
+}
diff --git a/tests/libqtest.h b/tests/libqtest.h
index cbe8df4473..ac52872cbe 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -972,4 +972,13 @@ void qtest_qmp_device_add(const char *driver, const char *id, const char *fmt,
*/
void qtest_qmp_device_del(const char *id);
+/**
+ * qmp_rsp_is_err:
+ * @rsp: QMP response to check for error
+ *
+ * Test @rsp for error and discard @rsp.
+ * Returns 'true' if there is error in @rsp and 'false' otherwise.
+ */
+bool qmp_rsp_is_err(QDict *rsp);
+
#endif
diff --git a/tests/numa-test.c b/tests/numa-test.c
index 169213fc1c..b7a6ef8815 100644
--- a/tests/numa-test.c
+++ b/tests/numa-test.c
@@ -260,6 +260,66 @@ static void aarch64_numa_cpu(const void *data)
g_free(cli);
}
+static void pc_dynamic_cpu_cfg(const void *data)
+{
+ QObject *e;
+ QDict *resp;
+ QList *cpus;
+ QTestState *qs;
+
+ qs = qtest_startf("%s %s", data ? (char *)data : "",
+ "-nodefaults --preconfig -smp 2");
+
+ /* create 2 numa nodes */
+ g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+ " 'arguments': { 'type': 'node', 'nodeid': 0 } }")));
+ g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+ " 'arguments': { 'type': 'node', 'nodeid': 1 } }")));
+
+ /* map 2 cpus in non default reverse order
+ * i.e socket1->node0, socket0->node1
+ */
+ g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+ " 'arguments': { 'type': 'cpu', 'node-id': 0, 'socket-id': 1 } }")));
+ g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'set-numa-node',"
+ " 'arguments': { 'type': 'cpu', 'node-id': 1, 'socket-id': 0 } }")));
+
+ /* let machine initialization to complete and run */
+ g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'exit-preconfig' }")));
+ qtest_qmp_eventwait(qs, "RESUME");
+
+ /* check that CPUs are mapped as expected */
+ resp = qtest_qmp(qs, "{ 'execute': 'query-hotpluggable-cpus'}");
+ g_assert(qdict_haskey(resp, "return"));
+ cpus = qdict_get_qlist(resp, "return");
+ g_assert(cpus);
+ while ((e = qlist_pop(cpus))) {
+ const QDict *cpu, *props;
+ int64_t socket, node;
+
+ cpu = qobject_to(QDict, e);
+ g_assert(qdict_haskey(cpu, "props"));
+ props = qdict_get_qdict(cpu, "props");
+
+ g_assert(qdict_haskey(props, "node-id"));
+ node = qdict_get_int(props, "node-id");
+ g_assert(qdict_haskey(props, "socket-id"));
+ socket = qdict_get_int(props, "socket-id");
+
+ if (socket == 0) {
+ g_assert_cmpint(node, ==, 1);
+ } else if (socket == 1) {
+ g_assert_cmpint(node, ==, 0);
+ } else {
+ g_assert(false);
+ }
+ qobject_unref(e);
+ }
+ qobject_unref(resp);
+
+ qtest_quit(qs);
+}
+
int main(int argc, char **argv)
{
const char *args = NULL;
@@ -278,6 +338,7 @@ int main(int argc, char **argv)
if (!strcmp(arch, "i386") || !strcmp(arch, "x86_64")) {
qtest_add_data_func("/numa/pc/cpu/explicit", args, pc_numa_cpu);
+ qtest_add_data_func("/numa/pc/dynamic/cpu", args, pc_dynamic_cpu_cfg);
}
if (!strcmp(arch, "ppc64")) {
diff --git a/tests/qapi-schema/allow-preconfig-test.err b/tests/qapi-schema/allow-preconfig-test.err
new file mode 100644
index 0000000000..700d583306
--- /dev/null
+++ b/tests/qapi-schema/allow-preconfig-test.err
@@ -0,0 +1 @@
+tests/qapi-schema/allow-preconfig-test.json:2: 'allow-preconfig' of command 'allow-preconfig-test' should only use true value
diff --git a/tests/qapi-schema/allow-preconfig-test.exit b/tests/qapi-schema/allow-preconfig-test.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/allow-preconfig-test.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/allow-preconfig-test.json b/tests/qapi-schema/allow-preconfig-test.json
new file mode 100644
index 0000000000..d9f0e914df
--- /dev/null
+++ b/tests/qapi-schema/allow-preconfig-test.json
@@ -0,0 +1,2 @@
+# Check against allow-preconfig illegal value
+{ 'command': 'allow-preconfig-test', 'allow-preconfig': 'some-string' }
diff --git a/tests/qapi-schema/allow-preconfig-test.out b/tests/qapi-schema/allow-preconfig-test.out
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/qapi-schema/allow-preconfig-test.out
diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out
index 63058b1590..9c8a4838e1 100644
--- a/tests/qapi-schema/doc-good.out
+++ b/tests/qapi-schema/doc-good.out
@@ -28,9 +28,9 @@ object q_obj_cmd-arg
member arg2: str optional=True
member arg3: bool optional=False
command cmd q_obj_cmd-arg -> Object
- gen=True success_response=True boxed=False oob=False
+ gen=True success_response=True boxed=False oob=False preconfig=False
command cmd-boxed Object -> None
- gen=True success_response=True boxed=True oob=False
+ gen=True success_response=True boxed=True oob=False preconfig=False
doc freeform
body=
= Section
diff --git a/tests/qapi-schema/ident-with-escape.out b/tests/qapi-schema/ident-with-escape.out
index 82213aa51d..24c976f473 100644
--- a/tests/qapi-schema/ident-with-escape.out
+++ b/tests/qapi-schema/ident-with-escape.out
@@ -5,4 +5,4 @@ module ident-with-escape.json
object q_obj_fooA-arg
member bar1: str optional=False
command fooA q_obj_fooA-arg -> None
- gen=True success_response=True boxed=False oob=False
+ gen=True success_response=True boxed=False oob=False preconfig=False
diff --git a/tests/qapi-schema/indented-expr.out b/tests/qapi-schema/indented-expr.out
index 862678f8f4..bd8a48630e 100644
--- a/tests/qapi-schema/indented-expr.out
+++ b/tests/qapi-schema/indented-expr.out
@@ -3,6 +3,6 @@ enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
prefix QTYPE
module indented-expr.json
command eins None -> None
- gen=True success_response=True boxed=False oob=False
+ gen=True success_response=True boxed=False oob=False preconfig=False
command zwei None -> None
- gen=True success_response=True boxed=False oob=False
+ gen=True success_response=True boxed=False oob=False preconfig=False
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index 06e30f452e..46c7282945 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -139,8 +139,8 @@
{ 'command': 'boxed-struct', 'boxed': true, 'data': 'UserDefZero' }
{ 'command': 'boxed-union', 'data': 'UserDefNativeListUnion', 'boxed': true }
-# Smoke test on Out-Of-Band
-{ 'command': 'an-oob-command', 'allow-oob': true }
+# Smoke test on Out-Of-Band and allow-preconfig-test
+{ 'command': 'test-flags-command', 'allow-oob': true, 'allow-preconfig': true }
# For testing integer range flattening in opts-visitor. The following schema
# corresponds to the option format:
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 467577d770..542a19c407 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -16,7 +16,7 @@ object Empty1
object Empty2
base Empty1
command user_def_cmd0 Empty2 -> Empty2
- gen=True success_response=True boxed=False oob=False
+ gen=True success_response=True boxed=False oob=False preconfig=False
enum QEnumTwo ['value1', 'value2']
prefix QENUM_TWO
object UserDefOne
@@ -143,31 +143,31 @@ object UserDefNativeListUnion
case sizes: q_obj_sizeList-wrapper
case any: q_obj_anyList-wrapper
command user_def_cmd None -> None
- gen=True success_response=True boxed=False oob=False
+ gen=True success_response=True boxed=False oob=False preconfig=False
object q_obj_user_def_cmd1-arg
member ud1a: UserDefOne optional=False
command user_def_cmd1 q_obj_user_def_cmd1-arg -> None
- gen=True success_response=True boxed=False oob=False
+ gen=True success_response=True boxed=False oob=False preconfig=False
object q_obj_user_def_cmd2-arg
member ud1a: UserDefOne optional=False
member ud1b: UserDefOne optional=True
command user_def_cmd2 q_obj_user_def_cmd2-arg -> UserDefTwo
- gen=True success_response=True boxed=False oob=False
+ gen=True success_response=True boxed=False oob=False preconfig=False
object q_obj_guest-get-time-arg
member a: int optional=False
member b: int optional=True
command guest-get-time q_obj_guest-get-time-arg -> int
- gen=True success_response=True boxed=False oob=False
+ gen=True success_response=True boxed=False oob=False preconfig=False
object q_obj_guest-sync-arg
member arg: any optional=False
command guest-sync q_obj_guest-sync-arg -> any
- gen=True success_response=True boxed=False oob=False
+ gen=True success_response=True boxed=False oob=False preconfig=False
command boxed-struct UserDefZero -> None
- gen=True success_response=True boxed=True oob=False
+ gen=True success_response=True boxed=True oob=False preconfig=False
command boxed-union UserDefNativeListUnion -> None
- gen=True success_response=True boxed=True oob=False
-command an-oob-command None -> None
- gen=True success_response=True boxed=False oob=True
+ gen=True success_response=True boxed=True oob=False preconfig=False
+command test-flags-command None -> None
+ gen=True success_response=True boxed=False oob=True preconfig=True
object UserDefOptions
member i64: intList optional=True
member u64: uint64List optional=True
@@ -231,4 +231,4 @@ object q_obj___org.qemu_x-command-arg
member c: __org.qemu_x-Union2 optional=False
member d: __org.qemu_x-Alt optional=False
command __org.qemu_x-command q_obj___org.qemu_x-command-arg -> __org.qemu_x-Union1
- gen=True success_response=True boxed=False oob=False
+ gen=True success_response=True boxed=False oob=False preconfig=False
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index c1a144ba29..4512a41504 100644
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -41,12 +41,12 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
print('alternate %s' % name)
self._print_variants(variants)
- def visit_command(self, name, info, arg_type, ret_type,
- gen, success_response, boxed, allow_oob):
+ def visit_command(self, name, info, arg_type, ret_type, gen,
+ success_response, boxed, allow_oob, allow_preconfig):
print('command %s %s -> %s' % \
(name, arg_type and arg_type.name, ret_type and ret_type.name))
- print(' gen=%s success_response=%s boxed=%s oob=%s' % \
- (gen, success_response, boxed, allow_oob))
+ print(' gen=%s success_response=%s boxed=%s oob=%s preconfig=%s' % \
+ (gen, success_response, boxed, allow_oob, allow_preconfig))
def visit_event(self, name, info, arg_type, boxed):
print('event %s %s' % (name, arg_type and arg_type.name))
diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
index 640a6dfd10..1dbc2ddc49 100755
--- a/tests/qemu-iotests/030
+++ b/tests/qemu-iotests/030
@@ -304,8 +304,7 @@ class TestParallelOps(iotests.QMPTestCase):
result = self.vm.qmp('block-stream', device='node5', base=self.imgs[3], job_id='stream-node6')
self.assert_qmp(result, 'error/class', 'GenericError')
- event = self.vm.get_qmp_event(wait=True)
- self.assertEqual(event['event'], 'BLOCK_JOB_READY')
+ event = self.vm.event_wait(name='BLOCK_JOB_READY')
self.assert_qmp(event, 'data/device', 'commit-drive0')
self.assert_qmp(event, 'data/type', 'commit')
self.assert_qmp_absent(event, 'data/error')
@@ -565,6 +564,8 @@ class TestEIO(TestErrors):
self.assert_qmp(event, 'data/offset', self.STREAM_BUFFER_SIZE)
self.assert_qmp(event, 'data/len', self.image_len)
completed = True
+ elif event['event'] == 'JOB_STATUS_CHANGE':
+ self.assert_qmp(event, 'data/id', 'drive0')
self.assert_no_active_block_jobs()
self.vm.shutdown()
@@ -596,6 +597,8 @@ class TestEIO(TestErrors):
self.assert_qmp(event, 'data/offset', self.image_len)
self.assert_qmp(event, 'data/len', self.image_len)
completed = True
+ elif event['event'] == 'JOB_STATUS_CHANGE':
+ self.assert_qmp(event, 'data/id', 'drive0')
self.assert_no_active_block_jobs()
self.vm.shutdown()
@@ -637,6 +640,8 @@ class TestEIO(TestErrors):
self.assert_qmp(event, 'data/offset', self.image_len)
self.assert_qmp(event, 'data/len', self.image_len)
completed = True
+ elif event['event'] == 'JOB_STATUS_CHANGE':
+ self.assert_qmp(event, 'data/id', 'drive0')
self.assert_no_active_block_jobs()
self.vm.shutdown()
@@ -663,6 +668,8 @@ class TestEIO(TestErrors):
self.assert_qmp(event, 'data/offset', self.STREAM_BUFFER_SIZE)
self.assert_qmp(event, 'data/len', self.image_len)
completed = True
+ elif event['event'] == 'JOB_STATUS_CHANGE':
+ self.assert_qmp(event, 'data/id', 'drive0')
self.assert_no_active_block_jobs()
self.vm.shutdown()
@@ -722,6 +729,8 @@ class TestENOSPC(TestErrors):
self.assert_qmp(event, 'data/offset', self.image_len)
self.assert_qmp(event, 'data/len', self.image_len)
completed = True
+ elif event['event'] == 'JOB_STATUS_CHANGE':
+ self.assert_qmp(event, 'data/id', 'drive0')
self.assert_no_active_block_jobs()
self.vm.shutdown()
@@ -751,7 +760,9 @@ class TestStreamStop(iotests.QMPTestCase):
time.sleep(0.1)
events = self.vm.get_qmp_events(wait=False)
- self.assertEqual(events, [], 'unexpected QMP event: %s' % events)
+ for e in events:
+ self.assert_qmp(e, 'event', 'JOB_STATUS_CHANGE')
+ self.assert_qmp(e, 'data/id', 'drive0')
self.cancel_and_wait(resume=True)
diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040
index 90b5b4f2ad..1beb5e6dab 100755
--- a/tests/qemu-iotests/040
+++ b/tests/qemu-iotests/040
@@ -162,6 +162,8 @@ class TestSingleDrive(ImageCommitTestCase):
elif event['event'] == 'BLOCK_JOB_CANCELLED':
self.assert_qmp(event, 'data/device', 'drive0')
cancelled = True
+ elif event['event'] == 'JOB_STATUS_CHANGE':
+ self.assert_qmp(event, 'data/id', 'drive0')
else:
self.fail("Unexpected event %s" % (event['event']))
diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041
index a860a31e9a..c20ac7da87 100755
--- a/tests/qemu-iotests/041
+++ b/tests/qemu-iotests/041
@@ -445,6 +445,8 @@ new_state = "1"
self.assert_qmp(event, 'data/device', 'drive0')
self.assert_qmp(event, 'data/error', 'Input/output error')
completed = True
+ elif event['event'] == 'JOB_STATUS_CHANGE':
+ self.assert_qmp(event, 'data/id', 'drive0')
self.assert_no_active_block_jobs()
self.vm.shutdown()
@@ -457,6 +459,10 @@ new_state = "1"
self.assert_qmp(result, 'return', {})
event = self.vm.get_qmp_event(wait=True)
+ while event['event'] == 'JOB_STATUS_CHANGE':
+ self.assert_qmp(event, 'data/id', 'drive0')
+ event = self.vm.get_qmp_event(wait=True)
+
self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
self.assert_qmp(event, 'data/device', 'drive0')
self.assert_qmp(event, 'data/operation', 'read')
@@ -478,6 +484,10 @@ new_state = "1"
self.assert_qmp(result, 'return', {})
event = self.vm.get_qmp_event(wait=True)
+ while event['event'] == 'JOB_STATUS_CHANGE':
+ self.assert_qmp(event, 'data/id', 'drive0')
+ event = self.vm.get_qmp_event(wait=True)
+
self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
self.assert_qmp(event, 'data/device', 'drive0')
self.assert_qmp(event, 'data/operation', 'read')
@@ -608,7 +618,7 @@ new_state = "1"
on_target_error='ignore')
self.assert_qmp(result, 'return', {})
- event = self.vm.get_qmp_event(wait=True)
+ event = self.vm.event_wait(name='BLOCK_JOB_ERROR')
self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
self.assert_qmp(event, 'data/device', 'drive0')
self.assert_qmp(event, 'data/operation', 'write')
@@ -784,7 +794,12 @@ class TestGranularity(iotests.QMPTestCase):
sync='full', target=target_img,
mode='absolute-paths', granularity=8192)
self.assert_qmp(result, 'return', {})
+
event = self.vm.get_qmp_event(wait=60.0)
+ while event['event'] == 'JOB_STATUS_CHANGE':
+ self.assert_qmp(event, 'data/id', 'drive0')
+ event = self.vm.get_qmp_event(wait=60.0)
+
# Failures will manifest as COMPLETED/ERROR.
self.assert_qmp(event, 'event', 'BLOCK_JOB_READY')
self.complete_and_wait(drive='drive0', wait_ready=False)
@@ -1015,9 +1030,9 @@ class TestOrphanedSource(iotests.QMPTestCase):
'read-only': 'on' }
self.vm = iotests.VM()
- self.vm.add_blockdev(self.qmp_to_opts(blk0))
- self.vm.add_blockdev(self.qmp_to_opts(blk1))
- self.vm.add_blockdev(self.qmp_to_opts(blk2))
+ self.vm.add_blockdev(self.vm.qmp_to_opts(blk0))
+ self.vm.add_blockdev(self.vm.qmp_to_opts(blk1))
+ self.vm.add_blockdev(self.vm.qmp_to_opts(blk2))
self.vm.launch()
def tearDown(self):
diff --git a/tests/qemu-iotests/086 b/tests/qemu-iotests/086
index cd4494a660..84e3835071 100755
--- a/tests/qemu-iotests/086
+++ b/tests/qemu-iotests/086
@@ -38,7 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.filter
_supported_fmt qcow2 raw
-_supported_proto file nfs
+_supported_proto file
_supported_os Linux
function run_qemu_img()
diff --git a/tests/qemu-iotests/094.out b/tests/qemu-iotests/094.out
index f52baffe70..665b630b08 100644
--- a/tests/qemu-iotests/094.out
+++ b/tests/qemu-iotests/094.out
@@ -2,10 +2,17 @@ QA output created by 094
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
Formatting 'TEST_DIR/source.IMGFMT', fmt=IMGFMT size=67108864
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}}
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
*** done
diff --git a/tests/qemu-iotests/095 b/tests/qemu-iotests/095
index 030adb22e1..72ecc22e1b 100755
--- a/tests/qemu-iotests/095
+++ b/tests/qemu-iotests/095
@@ -72,7 +72,7 @@ _send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" "return"
_send_qemu_cmd $h "{ 'execute': 'block-commit',
'arguments': { 'device': 'test',
- 'top': '"${TEST_IMG}.snp1"' } }" "BLOCK_JOB_COMPLETED"
+ 'top': '"${TEST_IMG}.snp1"' } }" '"status": "null"'
_cleanup_qemu
diff --git a/tests/qemu-iotests/095.out b/tests/qemu-iotests/095.out
index 73875cab40..8c093dfff3 100644
--- a/tests/qemu-iotests/095.out
+++ b/tests/qemu-iotests/095.out
@@ -11,8 +11,14 @@ virtual size: 5.0M (5242880 bytes)
=== Running QEMU Live Commit Test ===
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "test"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "test"}}
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "test"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "test"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "test", "len": 104857600, "offset": 104857600, "speed": 0, "type": "commit"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "test"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "test"}}
=== Base image info after commit and resize ===
image: TEST_DIR/t.IMGFMT.base
diff --git a/tests/qemu-iotests/109 b/tests/qemu-iotests/109
index d70b574d88..acbd079136 100755
--- a/tests/qemu-iotests/109
+++ b/tests/qemu-iotests/109
@@ -64,7 +64,7 @@ function run_qemu()
_send_qemu_cmd $QEMU_HANDLE '' "$qmp_event"
if test "$qmp_event" = BLOCK_JOB_ERROR; then
- _send_qemu_cmd $QEMU_HANDLE '' "BLOCK_JOB_COMPLETED"
+ _send_qemu_cmd $QEMU_HANDLE '' '"status": "null"'
fi
_send_qemu_cmd $QEMU_HANDLE '{"execute":"query-block-jobs"}' "return"
_send_qemu_cmd $QEMU_HANDLE '{"execute":"quit"}' "return"
diff --git a/tests/qemu-iotests/109.out b/tests/qemu-iotests/109.out
index 8a9b93672b..ad0ee6fb48 100644
--- a/tests/qemu-iotests/109.out
+++ b/tests/qemu-iotests/109.out
@@ -6,23 +6,35 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864
{"return": {}}
WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw.
-Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
-Specify the 'raw' format explicitly to remove the restrictions.
+ Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
+ Specify the 'raw' format explicitly to remove the restrictions.
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": []}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 1024, "offset": 1024, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
Warning: Image size mismatch!
Images are identical.
@@ -32,23 +44,35 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864
{"return": {}}
WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw.
-Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
-Specify the 'raw' format explicitly to remove the restrictions.
+ Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
+ Specify the 'raw' format explicitly to remove the restrictions.
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": 512, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": []}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 197120, "offset": 197120, "speed": 0, "type": "mirror"}}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 197120, "offset": 197120, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 197120, "offset": 197120, "speed": 0, "type": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
Warning: Image size mismatch!
Images are identical.
@@ -58,23 +82,35 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864
{"return": {}}
WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw.
-Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
-Specify the 'raw' format explicitly to remove the restrictions.
+ Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
+ Specify the 'raw' format explicitly to remove the restrictions.
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": 262144, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": []}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 327680, "offset": 327680, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
Warning: Image size mismatch!
Images are identical.
@@ -84,23 +120,35 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864
{"return": {}}
WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw.
-Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
-Specify the 'raw' format explicitly to remove the restrictions.
+ Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
+ Specify the 'raw' format explicitly to remove the restrictions.
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": []}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 1024, "offset": 1024, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
Warning: Image size mismatch!
Images are identical.
@@ -110,23 +158,35 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864
{"return": {}}
WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw.
-Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
-Specify the 'raw' format explicitly to remove the restrictions.
+ Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
+ Specify the 'raw' format explicitly to remove the restrictions.
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": []}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 65536, "offset": 65536, "speed": 0, "type": "mirror"}}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 65536, "offset": 65536, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": 65536, "speed": 0, "type": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
Warning: Image size mismatch!
Images are identical.
@@ -136,23 +196,35 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864
{"return": {}}
WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw.
-Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
-Specify the 'raw' format explicitly to remove the restrictions.
+ Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
+ Specify the 'raw' format explicitly to remove the restrictions.
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": []}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 2560, "offset": 2560, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
Warning: Image size mismatch!
Images are identical.
@@ -161,23 +233,35 @@ Images are identical.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
{"return": {}}
WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw.
-Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
-Specify the 'raw' format explicitly to remove the restrictions.
+ Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
+ Specify the 'raw' format explicitly to remove the restrictions.
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": []}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 2560, "offset": 2560, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
Warning: Image size mismatch!
Images are identical.
@@ -186,23 +270,35 @@ Images are identical.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
{"return": {}}
WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw.
-Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
-Specify the 'raw' format explicitly to remove the restrictions.
+ Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
+ Specify the 'raw' format explicitly to remove the restrictions.
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": []}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 31457280, "offset": 31457280, "speed": 0, "type": "mirror"}}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 31457280, "offset": 31457280, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 31457280, "offset": 31457280, "speed": 0, "type": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
Warning: Image size mismatch!
Images are identical.
@@ -211,23 +307,35 @@ Images are identical.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
{"return": {}}
WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw.
-Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
-Specify the 'raw' format explicitly to remove the restrictions.
+ Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
+ Specify the 'raw' format explicitly to remove the restrictions.
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": []}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 327680, "offset": 327680, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
Warning: Image size mismatch!
Images are identical.
@@ -236,23 +344,35 @@ Images are identical.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
{"return": {}}
WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw.
-Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
-Specify the 'raw' format explicitly to remove the restrictions.
+ Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
+ Specify the 'raw' format explicitly to remove the restrictions.
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": []}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 2048, "offset": 2048, "speed": 0, "type": "mirror"}}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 2048, "offset": 2048, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2048, "offset": 2048, "speed": 0, "type": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
Warning: Image size mismatch!
Images are identical.
@@ -261,23 +381,37 @@ Images are identical.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
{"return": {}}
WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw.
-Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
-Specify the 'raw' format explicitly to remove the restrictions.
+ Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
+ Specify the 'raw' format explicitly to remove the restrictions.
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 512, "offset": 512, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
Warning: Image size mismatch!
Images are identical.
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 512, "offset": 512, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
Warning: Image size mismatch!
Images are identical.
*** done
diff --git a/tests/qemu-iotests/124 b/tests/qemu-iotests/124
index 8e76e62f93..3ea4ac53f5 100755
--- a/tests/qemu-iotests/124
+++ b/tests/qemu-iotests/124
@@ -151,10 +151,17 @@ class TestIncrementalBackupBase(iotests.QMPTestCase):
return self.wait_qmp_backup(kwargs['device'], error)
+ def ignore_job_status_change_events(self):
+ while True:
+ e = self.vm.event_wait(name="JOB_STATUS_CHANGE")
+ if e['data']['status'] == 'null':
+ break
+
def wait_qmp_backup(self, device, error='Input/output error'):
event = self.vm.event_wait(name="BLOCK_JOB_COMPLETED",
match={'data': {'device': device}})
self.assertNotEqual(event, None)
+ self.ignore_job_status_change_events()
try:
failure = self.dictpath(event, 'data/error')
@@ -172,6 +179,7 @@ class TestIncrementalBackupBase(iotests.QMPTestCase):
event = self.vm.event_wait(name='BLOCK_JOB_CANCELLED',
match={'data': {'device': device}})
self.assertNotEqual(event, None)
+ self.ignore_job_status_change_events()
def create_anchor_backup(self, drive=None):
diff --git a/tests/qemu-iotests/126.out b/tests/qemu-iotests/126.out
index 50d73080fa..17d03d5248 100644
--- a/tests/qemu-iotests/126.out
+++ b/tests/qemu-iotests/126.out
@@ -3,7 +3,7 @@ QA output created by 126
=== Testing plain files ===
Formatting 'TEST_DIR/a:b.IMGFMT', fmt=IMGFMT size=67108864
-Formatting 'TEST_DIR/a:b.IMGFMT', fmt=IMGFMT size=67108864
+Formatting 'file:TEST_DIR/a:b.IMGFMT', fmt=IMGFMT size=67108864
=== Testing relative backing filename resolution ===
diff --git a/tests/qemu-iotests/127.out b/tests/qemu-iotests/127.out
index 543d075005..83b522d4c2 100644
--- a/tests/qemu-iotests/127.out
+++ b/tests/qemu-iotests/127.out
@@ -5,10 +5,17 @@ Formatting 'TEST_DIR/t.IMGFMT.overlay1', fmt=IMGFMT size=65536 backing_file=TEST
wrote 42/42 bytes at offset 0
42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "mirror"}}
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "mirror", "len": 65536, "offset": 65536, "speed": 0, "type": "mirror"}}
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "mirror", "len": 65536, "offset": 65536, "speed": 0, "type": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "mirror"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
*** done
diff --git a/tests/qemu-iotests/141 b/tests/qemu-iotests/141
index 2f9d7b9bc2..4246d387a1 100755
--- a/tests/qemu-iotests/141
+++ b/tests/qemu-iotests/141
@@ -107,7 +107,7 @@ test_blockjob \
'format': '$IMGFMT',
'sync': 'none'}}" \
'return' \
- 'BLOCK_JOB_CANCELLED'
+ '"status": "null"'
echo
echo '=== Testing drive-mirror ==='
@@ -124,7 +124,7 @@ test_blockjob \
'format': '$IMGFMT',
'sync': 'none'}}" \
'BLOCK_JOB_READY' \
- 'BLOCK_JOB_COMPLETED'
+ '"status": "null"'
echo
echo '=== Testing active block-commit ==='
@@ -138,7 +138,7 @@ test_blockjob \
"{'execute': 'block-commit',
'arguments': {'job-id': 'job0', 'device': 'drv0'}}" \
'BLOCK_JOB_READY' \
- 'BLOCK_JOB_COMPLETED'
+ '"status": "null"'
echo
echo '=== Testing non-active block-commit ==='
@@ -157,7 +157,7 @@ test_blockjob \
'top': '$TEST_DIR/m.$IMGFMT',
'speed': 1}}" \
'return' \
- 'BLOCK_JOB_CANCELLED'
+ '"status": "null"'
echo
echo '=== Testing block-stream ==='
@@ -170,8 +170,7 @@ echo
$QEMU_IO -c 'write 0 1M' "$TEST_DIR/b.$IMGFMT" | _filter_qemu_io
# With some data to stream (and @speed set to 1), block-stream will not complete
-# until we send the block-job-cancel command. Therefore, no event other than
-# BLOCK_JOB_CANCELLED will be emitted.
+# until we send the block-job-cancel command.
test_blockjob \
"{'execute': 'block-stream',
@@ -179,7 +178,7 @@ test_blockjob \
'device': 'drv0',
'speed': 1}}" \
'return' \
- 'BLOCK_JOB_CANCELLED'
+ '"status": "null"'
_cleanup_qemu
diff --git a/tests/qemu-iotests/141.out b/tests/qemu-iotests/141.out
index 82e763b68d..f252c86875 100644
--- a/tests/qemu-iotests/141.out
+++ b/tests/qemu-iotests/141.out
@@ -8,31 +8,50 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/m.
{"return": {}}
Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}}
{"return": {}}
{"error": {"class": "GenericError", "desc": "Node drv0 is in use"}}
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "job0", "len": 1048576, "offset": 0, "speed": 0, "type": "backup"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}}
{"return": {}}
=== Testing drive-mirror ===
{"return": {}}
Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}}
{"return": {}}
{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: node is used as backing hd of 'NODE_NAME'"}}
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}}
{"return": {}}
=== Testing active block-commit ===
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
{"return": {}}
{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: node is used as backing hd of 'NODE_NAME'"}}
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}}
{"return": {}}
=== Testing non-active block-commit ===
@@ -40,10 +59,15 @@ Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.
wrote 1048576/1048576 bytes at offset 0
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}}
{"return": {}}
{"error": {"class": "GenericError", "desc": "Node drv0 is in use"}}
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "job0", "len": 1048576, "offset": 524288, "speed": 1, "type": "commit"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}}
{"return": {}}
=== Testing block-stream ===
@@ -51,9 +75,14 @@ wrote 1048576/1048576 bytes at offset 0
wrote 1048576/1048576 bytes at offset 0
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}}
{"return": {}}
{"error": {"class": "GenericError", "desc": "Node drv0 is in use"}}
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "job0", "len": 1048576, "offset": 524288, "speed": 1, "type": "stream"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}}
{"return": {}}
*** done
diff --git a/tests/qemu-iotests/144 b/tests/qemu-iotests/144
index 00de3c33cf..4b915718cd 100755
--- a/tests/qemu-iotests/144
+++ b/tests/qemu-iotests/144
@@ -93,7 +93,7 @@ _send_qemu_cmd $h "{ 'execute': 'block-job-complete',
'arguments': {
'device': 'virtio0'
}
- }" "COMPLETED"
+ }" '"status": "null"'
echo
echo === Performing Live Snapshot 2 ===
diff --git a/tests/qemu-iotests/144.out b/tests/qemu-iotests/144.out
index 014b2817ee..55299201e4 100644
--- a/tests/qemu-iotests/144.out
+++ b/tests/qemu-iotests/144.out
@@ -12,10 +12,17 @@ Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/
=== Performing block-commit on active layer ===
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "virtio0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "virtio0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "virtio0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "virtio0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
{"return": {}}
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "virtio0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "virtio0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "virtio0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "virtio0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "virtio0"}}
=== Performing Live Snapshot 2 ===
diff --git a/tests/qemu-iotests/155 b/tests/qemu-iotests/155
index 42dae04c83..63a5b5e2c0 100755
--- a/tests/qemu-iotests/155
+++ b/tests/qemu-iotests/155
@@ -63,7 +63,7 @@ class BaseClass(iotests.QMPTestCase):
'driver': iotests.imgfmt,
'file': {'driver': 'file',
'filename': source_img}}
- self.vm.add_blockdev(self.qmp_to_opts(blockdev))
+ self.vm.add_blockdev(self.vm.qmp_to_opts(blockdev))
self.vm.add_device('virtio-blk,id=qdev0,drive=source')
self.vm.launch()
diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156
index e75dc4d743..0a9a09802e 100755
--- a/tests/qemu-iotests/156
+++ b/tests/qemu-iotests/156
@@ -119,7 +119,7 @@ _send_qemu_cmd $QEMU_HANDLE \
_send_qemu_cmd $QEMU_HANDLE \
'' \
- 'BLOCK_JOB_COMPLETED'
+ '"status": "null"'
# Remove the source images
rm -f "$TEST_IMG{,.backing,.overlay}"
diff --git a/tests/qemu-iotests/156.out b/tests/qemu-iotests/156.out
index f96a564c1d..34c057b626 100644
--- a/tests/qemu-iotests/156.out
+++ b/tests/qemu-iotests/156.out
@@ -12,13 +12,20 @@ wrote 131072/131072 bytes at offset 131072
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": ""}
Formatting 'TEST_DIR/t.IMGFMT.target.overlay', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.target
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "source"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "source"}}
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "source"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "source", "len": 131072, "offset": 131072, "speed": 0, "type": "mirror"}}
wrote 65536/65536 bytes at offset 196608
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": ""}
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "source"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "source"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "source", "len": 196608, "offset": 196608, "speed": 0, "type": "mirror"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "source"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "source"}}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
diff --git a/tests/qemu-iotests/185 b/tests/qemu-iotests/185
index 9a2d317414..7dcfdeac60 100755
--- a/tests/qemu-iotests/185
+++ b/tests/qemu-iotests/185
@@ -27,8 +27,6 @@ echo "QA output created by $seq"
here=`pwd`
status=1 # failure is the default!
-MIG_SOCKET="${TEST_DIR}/migrate"
-
_cleanup()
{
rm -f "${TEST_IMG}.mid"
@@ -118,8 +116,10 @@ _send_qemu_cmd $h \
# If we don't sleep here 'quit' command races with disk I/O
sleep 0.5
+# Ignore the JOB_STATUS_CHANGE events while shutting down the VM. Depending on
+# the timing, jobs may or may not transition through a paused state.
_send_qemu_cmd $h "{ 'execute': 'quit' }" "return"
-wait=1 _cleanup_qemu
+wait=1 _cleanup_qemu | grep -v 'JOB_STATUS_CHANGE'
echo
echo === Start active commit job and exit qemu ===
@@ -141,7 +141,7 @@ _send_qemu_cmd $h \
sleep 0.5
_send_qemu_cmd $h "{ 'execute': 'quit' }" "return"
-wait=1 _cleanup_qemu
+wait=1 _cleanup_qemu | grep -v 'JOB_STATUS_CHANGE'
echo
echo === Start mirror job and exit qemu ===
@@ -166,7 +166,7 @@ _send_qemu_cmd $h \
sleep 0.5
_send_qemu_cmd $h "{ 'execute': 'quit' }" "return"
-wait=1 _cleanup_qemu
+wait=1 _cleanup_qemu | grep -v 'JOB_STATUS_CHANGE'
echo
echo === Start backup job and exit qemu ===
@@ -190,7 +190,7 @@ _send_qemu_cmd $h \
sleep 0.5
_send_qemu_cmd $h "{ 'execute': 'quit' }" "return"
-wait=1 _cleanup_qemu
+wait=1 _cleanup_qemu | grep -v 'JOB_STATUS_CHANGE'
echo
echo === Start streaming job and exit qemu ===
@@ -211,7 +211,7 @@ _send_qemu_cmd $h \
sleep 0.5
_send_qemu_cmd $h "{ 'execute': 'quit' }" "return"
-wait=1 _cleanup_qemu
+wait=1 _cleanup_qemu | grep -v 'JOB_STATUS_CHANGE'
_check_test_img
diff --git a/tests/qemu-iotests/185.out b/tests/qemu-iotests/185.out
index 57eaf8d699..4e0ca0dffa 100644
--- a/tests/qemu-iotests/185.out
+++ b/tests/qemu-iotests/185.out
@@ -17,6 +17,8 @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.q
=== Start commit job and exit qemu ===
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "disk"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
{"return": {}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
@@ -25,6 +27,8 @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.q
=== Start active commit job and exit qemu ===
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "disk"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
{"return": {}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
@@ -34,6 +38,8 @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.q
{"return": {}}
Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 lazy_refcounts=off refcount_bits=16
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "disk"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
{"return": {}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
@@ -43,6 +49,8 @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 l
{"return": {}}
Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 lazy_refcounts=off refcount_bits=16
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "disk"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
{"return": {}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
@@ -51,6 +59,8 @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 l
=== Start streaming job and exit qemu ===
{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "disk"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
{"return": {}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
diff --git a/tests/qemu-iotests/191 b/tests/qemu-iotests/191
index dfad6555e4..d6860e72f7 100755
--- a/tests/qemu-iotests/191
+++ b/tests/qemu-iotests/191
@@ -27,8 +27,6 @@ echo "QA output created by $seq"
here=`pwd`
status=1 # failure is the default!
-MIG_SOCKET="${TEST_DIR}/migrate"
-
_cleanup()
{
rm -f "${TEST_IMG}.mid"
@@ -83,7 +81,7 @@ _send_qemu_cmd $h \
'device': 'top',
'base':'$TEST_IMG.base',
'top': '$TEST_IMG.mid' } }" \
- "BLOCK_JOB_COMPLETED"
+ '"status": "null"'
_send_qemu_cmd $h "" "^}"
echo
@@ -131,7 +129,7 @@ _send_qemu_cmd $h \
'device': 'top',
'base':'$TEST_IMG.base',
'top': '$TEST_IMG.mid' } }" \
- "BLOCK_JOB_COMPLETED"
+ '"status": "null"'
_send_qemu_cmd $h "" "^}"
echo
diff --git a/tests/qemu-iotests/191.out b/tests/qemu-iotests/191.out
index 190c5f049a..31a0c7d4c4 100644
--- a/tests/qemu-iotests/191.out
+++ b/tests/qemu-iotests/191.out
@@ -16,6 +16,28 @@ wrote 65536/65536 bytes at offset 1048576
=== Perform commit job ===
{
+ "timestamp": {
+ "seconds": TIMESTAMP,
+ "microseconds": TIMESTAMP
+ },
+ "event": "JOB_STATUS_CHANGE",
+ "data": {
+ "status": "created",
+ "id": "commit0"
+ }
+}
+{
+ "timestamp": {
+ "seconds": TIMESTAMP,
+ "microseconds": TIMESTAMP
+ },
+ "event": "JOB_STATUS_CHANGE",
+ "data": {
+ "status": "running",
+ "id": "commit0"
+ }
+}
+{
"return": {
}
}
@@ -24,6 +46,28 @@ wrote 65536/65536 bytes at offset 1048576
"seconds": TIMESTAMP,
"microseconds": TIMESTAMP
},
+ "event": "JOB_STATUS_CHANGE",
+ "data": {
+ "status": "waiting",
+ "id": "commit0"
+ }
+}
+{
+ "timestamp": {
+ "seconds": TIMESTAMP,
+ "microseconds": TIMESTAMP
+ },
+ "event": "JOB_STATUS_CHANGE",
+ "data": {
+ "status": "pending",
+ "id": "commit0"
+ }
+}
+{
+ "timestamp": {
+ "seconds": TIMESTAMP,
+ "microseconds": TIMESTAMP
+ },
"event": "BLOCK_JOB_COMPLETED",
"data": {
"device": "commit0",
@@ -33,6 +77,28 @@ wrote 65536/65536 bytes at offset 1048576
"type": "commit"
}
}
+{
+ "timestamp": {
+ "seconds": TIMESTAMP,
+ "microseconds": TIMESTAMP
+ },
+ "event": "JOB_STATUS_CHANGE",
+ "data": {
+ "status": "concluded",
+ "id": "commit0"
+ }
+}
+{
+ "timestamp": {
+ "seconds": TIMESTAMP,
+ "microseconds": TIMESTAMP
+ },
+ "event": "JOB_STATUS_CHANGE",
+ "data": {
+ "status": "null",
+ "id": "commit0"
+ }
+}
=== Check that both top and top2 point to base now ===
@@ -356,6 +422,28 @@ wrote 65536/65536 bytes at offset 1048576
=== Perform commit job ===
{
+ "timestamp": {
+ "seconds": TIMESTAMP,
+ "microseconds": TIMESTAMP
+ },
+ "event": "JOB_STATUS_CHANGE",
+ "data": {
+ "status": "created",
+ "id": "commit0"
+ }
+}
+{
+ "timestamp": {
+ "seconds": TIMESTAMP,
+ "microseconds": TIMESTAMP
+ },
+ "event": "JOB_STATUS_CHANGE",
+ "data": {
+ "status": "running",
+ "id": "commit0"
+ }
+}
+{
"return": {
}
}
@@ -364,6 +452,28 @@ wrote 65536/65536 bytes at offset 1048576
"seconds": TIMESTAMP,
"microseconds": TIMESTAMP
},
+ "event": "JOB_STATUS_CHANGE",
+ "data": {
+ "status": "waiting",
+ "id": "commit0"
+ }
+}
+{
+ "timestamp": {
+ "seconds": TIMESTAMP,
+ "microseconds": TIMESTAMP
+ },
+ "event": "JOB_STATUS_CHANGE",
+ "data": {
+ "status": "pending",
+ "id": "commit0"
+ }
+}
+{
+ "timestamp": {
+ "seconds": TIMESTAMP,
+ "microseconds": TIMESTAMP
+ },
"event": "BLOCK_JOB_COMPLETED",
"data": {
"device": "commit0",
@@ -373,6 +483,28 @@ wrote 65536/65536 bytes at offset 1048576
"type": "commit"
}
}
+{
+ "timestamp": {
+ "seconds": TIMESTAMP,
+ "microseconds": TIMESTAMP
+ },
+ "event": "JOB_STATUS_CHANGE",
+ "data": {
+ "status": "concluded",
+ "id": "commit0"
+ }
+}
+{
+ "timestamp": {
+ "seconds": TIMESTAMP,
+ "microseconds": TIMESTAMP
+ },
+ "event": "JOB_STATUS_CHANGE",
+ "data": {
+ "status": "null",
+ "id": "commit0"
+ }
+}
=== Check that both top and top2 point to base now ===
diff --git a/tests/qemu-iotests/206 b/tests/qemu-iotests/206
index 0a18b2b19a..128c334c7c 100755
--- a/tests/qemu-iotests/206
+++ b/tests/qemu-iotests/206
@@ -1,9 +1,11 @@
-#!/bin/bash
+#!/usr/bin/env python
#
# Test qcow2 and file image creation
#
# Copyright (C) 2018 Red Hat, Inc.
#
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
@@ -18,419 +20,263 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-# creator
-owner=kwolf@redhat.com
-
-seq=`basename $0`
-echo "QA output created by $seq"
-
-here=`pwd`
-status=1 # failure is the default!
-
-# get standard environment, filters and checks
-. ./common.rc
-. ./common.filter
-
-_supported_fmt qcow2
-_supported_proto file
-_supported_os Linux
-
-function do_run_qemu()
-{
- echo Testing: "$@"
- $QEMU -nographic -qmp stdio -serial none "$@"
- echo
-}
-
-function run_qemu()
-{
- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
- | _filter_qemu | _filter_imgfmt \
- | _filter_actual_image_size
-}
-
-echo
-echo "=== Successful image creation (defaults) ==="
-echo
-
-size=$((128 * 1024 * 1024))
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "file",
- "filename": "$TEST_IMG",
- "size": 0
- }
-}
-{ "execute": "blockdev-add",
- "arguments": {
- "driver": "file",
- "node-name": "imgfile",
- "filename": "$TEST_IMG"
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "imgfile",
- "size": $size
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info --format-specific
-
-echo
-echo "=== Successful image creation (inline blockdev-add, explicit defaults) ==="
-echo
-
-# Choose a different size to show that we got a new image
-size=$((64 * 1024 * 1024))
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "file",
- "filename": "$TEST_IMG",
- "size": 0,
- "preallocation": "off",
- "nocow": false
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": {
- "driver": "file",
- "filename": "$TEST_IMG"
- },
- "size": $size,
- "version": "v3",
- "cluster-size": 65536,
- "preallocation": "off",
- "lazy-refcounts": false,
- "refcount-bits": 16
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info --format-specific
-
-echo
-echo "=== Successful image creation (v3 non-default options) ==="
-echo
-
-# Choose a different size to show that we got a new image
-size=$((32 * 1024 * 1024))
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "file",
- "filename": "$TEST_IMG",
- "size": 0,
- "preallocation": "falloc",
- "nocow": true
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": {
- "driver": "file",
- "filename": "$TEST_IMG"
- },
- "size": $size,
- "version": "v3",
- "cluster-size": 2097152,
- "preallocation": "metadata",
- "lazy-refcounts": true,
- "refcount-bits": 1
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info --format-specific
-
-echo
-echo "=== Successful image creation (v2 non-default options) ==="
-echo
-
-mv $TEST_IMG $TEST_IMG.base
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "file",
- "filename": "$TEST_IMG",
- "size": 0
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": {
- "driver": "file",
- "filename": "$TEST_IMG"
- },
- "size": $size,
- "backing-file": "$TEST_IMG.base",
- "backing-fmt": "qcow2",
- "version": "v2",
- "cluster-size": 512
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info --format-specific
-
-echo
-echo "=== Successful image creation (encrypted) ==="
-echo
-
-run_qemu -object secret,id=keysec0,data="foo" <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": {
- "driver": "file",
- "filename": "$TEST_IMG"
- },
- "size": $size,
- "encrypt": {
- "format": "luks",
- "key-secret": "keysec0",
- "cipher-alg": "twofish-128",
- "cipher-mode": "ctr",
- "ivgen-alg": "plain64",
- "ivgen-hash-alg": "md5",
- "hash-alg": "sha1",
- "iter-time": 10
- }
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info --format-specific | _filter_img_info --format-specific
-
-echo
-echo "=== Invalid BlockdevRef ==="
-echo
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "this doesn't exist",
- "size": $size
- }
-}
-{ "execute": "quit" }
-EOF
-
-
-echo
-echo "=== Invalid sizes ==="
-echo
-
-# TODO Negative image sizes aren't handled correctly, but this is a problem
-# with QAPI's implementation of the 'size' type and affects other commands as
-# well. Once this is fixed, we may want to add a test case here.
-
-# 1. Misaligned image size
-# 2. 2^64 - 512
-# 3. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
-# 4. 2^63 - 512 (generally valid, but qcow2 can't handle images this size)
-
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 1234
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 18446744073709551104
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 9223372036854775808
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 9223372036854775296
- }
-}
-{ "execute": "quit" }
-EOF
-
-echo
-echo "=== Invalid version ==="
-echo
-
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 67108864,
- "version": "v1"
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 67108864,
- "version": "v2",
- "lazy-refcounts": true
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 67108864,
- "version": "v2",
- "refcount-bits": 8
- }
-}
-{ "execute": "quit" }
-EOF
-
-echo
-echo "=== Invalid backing file options ==="
-echo
-
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 67108864,
- "backing-file": "/dev/null",
- "preallocation": "full"
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 67108864,
- "backing-fmt": "$IMGFMT"
- }
-}
-{ "execute": "quit" }
-EOF
-
-echo
-echo "=== Invalid cluster size ==="
-echo
-
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 67108864,
- "cluster-size": 1234
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 67108864,
- "cluster-size": 128
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 67108864,
- "cluster-size": 4194304
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 67108864,
- "cluster-size": 0
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 281474976710656,
- "cluster-size": 512
- }
-}
-{ "execute": "quit" }
-EOF
-
-echo
-echo "=== Invalid refcount width ==="
-echo
-
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 67108864,
- "refcount-bits": 128
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 67108864,
- "refcount-bits": 0
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 67108864,
- "refcount-bits": 7
- }
-}
-{ "execute": "quit" }
-EOF
-
-# success, all done
-echo "*** done"
-rm -f $seq.full
-status=0
+import iotests
+from iotests import imgfmt
+
+iotests.verify_image_format(supported_fmts=['qcow2'])
+
+def blockdev_create(vm, options):
+ result = vm.qmp_log('blockdev-create', job_id='job0', options=options)
+
+ if 'return' in result:
+ assert result['return'] == {}
+ vm.run_job('job0')
+ iotests.log("")
+
+with iotests.FilePath('t.qcow2') as disk_path, \
+ iotests.FilePath('t.qcow2.base') as backing_path, \
+ iotests.VM() as vm:
+
+ vm.add_object('secret,id=keysec0,data=foo')
+
+ #
+ # Successful image creation (defaults)
+ #
+ iotests.log("=== Successful image creation (defaults) ===")
+ iotests.log("")
+
+ size = 128 * 1024 * 1024
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': 'file',
+ 'filename': disk_path,
+ 'size': 0 })
+
+ vm.qmp_log('blockdev-add', driver='file', filename=disk_path,
+ node_name='imgfile')
+
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'imgfile',
+ 'size': size })
+ vm.shutdown()
+
+ iotests.img_info_log(disk_path)
+
+ #
+ # Successful image creation (inline blockdev-add, explicit defaults)
+ #
+ iotests.log("=== Successful image creation (inline blockdev-add, explicit defaults) ===")
+ iotests.log("")
+
+ # Choose a different size to show that we got a new image
+ size = 64 * 1024 * 1024
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': 'file',
+ 'filename': disk_path,
+ 'size': 0,
+ 'preallocation': 'off',
+ 'nocow': False })
+
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': {
+ 'driver': 'file',
+ 'filename': disk_path,
+ },
+ 'size': size,
+ 'version': 'v3',
+ 'cluster-size': 65536,
+ 'preallocation': 'off',
+ 'lazy-refcounts': False,
+ 'refcount-bits': 16 })
+ vm.shutdown()
+
+ iotests.img_info_log(disk_path)
+
+ #
+ # Successful image creation (v3 non-default options)
+ #
+ iotests.log("=== Successful image creation (v3 non-default options) ===")
+ iotests.log("")
+
+ # Choose a different size to show that we got a new image
+ size = 32 * 1024 * 1024
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': 'file',
+ 'filename': disk_path,
+ 'size': 0,
+ 'preallocation': 'falloc',
+ 'nocow': True })
+
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': {
+ 'driver': 'file',
+ 'filename': disk_path,
+ },
+ 'size': size,
+ 'version': 'v3',
+ 'cluster-size': 2097152,
+ 'preallocation': 'metadata',
+ 'lazy-refcounts': True,
+ 'refcount-bits': 1 })
+ vm.shutdown()
+
+ iotests.img_info_log(disk_path)
+
+ #
+ # Successful image creation (v2 non-default options)
+ #
+ iotests.log("=== Successful image creation (v2 non-default options) ===")
+ iotests.log("")
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': 'file',
+ 'filename': disk_path,
+ 'size': 0 })
+
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': {
+ 'driver': 'file',
+ 'filename': disk_path,
+ },
+ 'size': size,
+ 'backing-file': backing_path,
+ 'backing-fmt': 'qcow2',
+ 'version': 'v2',
+ 'cluster-size': 512 })
+ vm.shutdown()
+
+ iotests.img_info_log(disk_path)
+
+ #
+ # Successful image creation (encrypted)
+ #
+ iotests.log("=== Successful image creation (encrypted) ===")
+ iotests.log("")
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': {
+ 'driver': 'file',
+ 'filename': disk_path,
+ },
+ 'size': size,
+ 'encrypt': {
+ 'format': 'luks',
+ 'key-secret': 'keysec0',
+ 'cipher-alg': 'twofish-128',
+ 'cipher-mode': 'ctr',
+ 'ivgen-alg': 'plain64',
+ 'ivgen-hash-alg': 'md5',
+ 'hash-alg': 'sha1',
+ 'iter-time': 10,
+ }})
+ vm.shutdown()
+
+ iotests.img_info_log(disk_path)
+
+ #
+ # Invalid BlockdevRef
+ #
+ iotests.log("=== Invalid BlockdevRef ===")
+ iotests.log("")
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': "this doesn't exist",
+ 'size': size })
+ vm.shutdown()
+
+ #
+ # Invalid sizes
+ #
+ iotests.log("=== Invalid sizes ===")
+
+ # TODO Negative image sizes aren't handled correctly, but this is a problem
+ # with QAPI's implementation of the 'size' type and affects other commands
+ # as well. Once this is fixed, we may want to add a test case here.
+ #
+ # 1. Misaligned image size
+ # 2. 2^64 - 512
+ # 3. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
+ # 4. 2^63 - 512 (generally valid, but qcow2 can't handle images this size)
+
+ vm.add_blockdev('driver=file,filename=%s,node-name=node0' % (disk_path))
+
+ vm.launch()
+ for size in [ 1234, 18446744073709551104, 9223372036854775808,
+ 9223372036854775296 ]:
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'node0',
+ 'size': size })
+ vm.shutdown()
+
+ #
+ # Invalid version
+ #
+ iotests.log("=== Invalid version ===")
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'node0',
+ 'size': 67108864,
+ 'version': 'v1' })
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'node0',
+ 'size': 67108864,
+ 'version': 'v2',
+ 'lazy-refcounts': True })
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'node0',
+ 'size': 67108864,
+ 'version': 'v2',
+ 'refcount-bits': 8 })
+ vm.shutdown()
+
+ #
+ # Invalid backing file options
+ #
+ iotests.log("=== Invalid backing file options ===")
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'node0',
+ 'size': 67108864,
+ 'backing-file': '/dev/null',
+ 'preallocation': 'full' })
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'node0',
+ 'size': 67108864,
+ 'backing-fmt': imgfmt })
+ vm.shutdown()
+
+ #
+ # Invalid cluster size
+ #
+ iotests.log("=== Invalid cluster size ===")
+
+ vm.launch()
+ for csize in [ 1234, 128, 4194304, 0 ]:
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'node0',
+ 'size': 67108864,
+ 'cluster-size': csize })
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'node0',
+ 'size': 281474976710656,
+ 'cluster-size': 512 })
+ vm.shutdown()
+
+ #
+ # Invalid refcount width
+ #
+ iotests.log("=== Invalid refcount width ===")
+
+ vm.launch()
+ for refcount_bits in [ 128, 0, 7 ]:
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'node0',
+ 'size': 67108864,
+ 'refcount-bits': refcount_bits })
+ vm.shutdown()
diff --git a/tests/qemu-iotests/206.out b/tests/qemu-iotests/206.out
index 042342ae9d..789eebe57b 100644
--- a/tests/qemu-iotests/206.out
+++ b/tests/qemu-iotests/206.out
@@ -1,17 +1,18 @@
-QA output created by 206
-
=== Successful image creation (defaults) ===
-Testing:
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-add', 'arguments': {'node_name': 'imgfile', 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}
+{u'return': {}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'imgfile', 'size': 134217728}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-image: TEST_DIR/t.IMGFMT
+image: TEST_IMG
file format: IMGFMT
virtual size: 128M (134217728 bytes)
cluster_size: 65536
@@ -23,15 +24,17 @@ Format specific information:
=== Successful image creation (inline blockdev-add, explicit defaults) ===
-Testing:
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'nocow': False, 'preallocation': 'off', 'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-image: TEST_DIR/t.IMGFMT
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 65536, 'refcount-bits': 16, 'version': 'v3', 'preallocation': 'off', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'lazy-refcounts': False, 'driver': 'qcow2', 'size': 67108864}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+image: TEST_IMG
file format: IMGFMT
virtual size: 64M (67108864 bytes)
cluster_size: 65536
@@ -43,15 +46,17 @@ Format specific information:
=== Successful image creation (v3 non-default options) ===
-Testing:
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'nocow': True, 'preallocation': 'falloc', 'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 2097152, 'refcount-bits': 1, 'version': 'v3', 'preallocation': 'metadata', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'lazy-refcounts': True, 'driver': 'qcow2', 'size': 33554432}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-image: TEST_DIR/t.IMGFMT
+image: TEST_IMG
file format: IMGFMT
virtual size: 32M (33554432 bytes)
cluster_size: 2097152
@@ -63,19 +68,21 @@ Format specific information:
=== Successful image creation (v2 non-default options) ===
-Testing:
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-image: TEST_DIR/t.IMGFMT
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 512, 'backing-fmt': 'qcow2', 'driver': 'qcow2', 'version': 'v2', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'backing-file': 'TEST_DIR/PID-t.qcow2.base', 'size': 33554432}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+image: TEST_IMG
file format: IMGFMT
virtual size: 32M (33554432 bytes)
cluster_size: 512
-backing file: TEST_DIR/t.IMGFMT.base
+backing file: TEST_IMG.base
backing file format: IMGFMT
Format specific information:
compat: 0.10
@@ -83,16 +90,16 @@ Format specific information:
=== Successful image creation (encrypted) ===
-Testing: -object secret,id=keysec0,data=foo
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'encrypt': {'key-secret': 'keysec0', 'iter-time': 10, 'cipher-mode': 'ctr', 'ivgen-hash-alg': 'md5', 'cipher-alg': 'twofish-128', 'format': 'luks', 'ivgen-alg': 'plain64', 'hash-alg': 'sha1'}, 'driver': 'qcow2', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'size': 33554432}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-image: TEST_DIR/t.IMGFMT
+image: TEST_IMG
file format: IMGFMT
virtual size: 32M (33554432 bytes)
+encrypted: yes
+cluster_size: 65536
Format specific information:
compat: 1.1
lazy refcounts: false
@@ -101,13 +108,13 @@ Format specific information:
ivgen alg: plain64
hash alg: sha1
cipher alg: twofish-128
- uuid: 00000000-0000-0000-0000-000000000000
+ uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
format: luks
cipher mode: ctr
slots:
[0]:
active: true
- iters: 1024
+ iters: XXX
key offset: 4096
stripes: 4000
[1]:
@@ -132,78 +139,118 @@ Format specific information:
active: false
key offset: 462848
payload offset: 528384
- master key iters: 1024
+ master key iters: XXX
corrupt: false
=== Invalid BlockdevRef ===
-Testing:
-QMP_VERSION
-{"return": {}}
-{"error": {"class": "GenericError", "desc": "Cannot find device=this doesn't exist nor node_name=this doesn't exist"}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
-
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': "this doesn't exist", 'size': 33554432}}}
+{u'return': {}}
+Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
=== Invalid sizes ===
-
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
-QMP_VERSION
-{"return": {}}
-{"error": {"class": "GenericError", "desc": "Image size must be a multiple of 512 bytes"}}
-{"error": {"class": "GenericError", "desc": "Could not resize image: Image size cannot be negative"}}
-{"error": {"class": "GenericError", "desc": "Could not resize image: Image size cannot be negative"}}
-{"error": {"class": "GenericError", "desc": "Could not resize image: Failed to grow the L1 table: File too large"}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
-
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 1234}}}
+{u'return': {}}
+Job failed: Image size must be a multiple of 512 bytes
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 18446744073709551104L}}}
+{u'return': {}}
+Job failed: Could not resize image: Image size cannot be negative
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 9223372036854775808L}}}
+{u'return': {}}
+Job failed: Could not resize image: Image size cannot be negative
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 9223372036854775296}}}
+{u'return': {}}
+Job failed: Could not resize image: Failed to grow the L1 table: File too large
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
=== Invalid version ===
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'version': 'v1', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
+{u'error': {u'class': u'GenericError', u'desc': u"Invalid parameter 'v1'"}}
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
-QMP_VERSION
-{"return": {}}
-{"error": {"class": "GenericError", "desc": "Invalid parameter 'v1'"}}
-{"error": {"class": "GenericError", "desc": "Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater)"}}
-{"error": {"class": "GenericError", "desc": "Different refcount widths than 16 bits require compatibility level 1.1 or above (use version=v3 or greater)"}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'lazy-refcounts': True, 'version': 'v2', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
+{u'return': {}}
+Job failed: Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater)
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 8, 'version': 'v2', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
+{u'return': {}}
+Job failed: Different refcount widths than 16 bits require compatibility level 1.1 or above (use version=v3 or greater)
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
=== Invalid backing file options ===
-
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
-QMP_VERSION
-{"return": {}}
-{"error": {"class": "GenericError", "desc": "Backing file and preallocation cannot be used at the same time"}}
-{"error": {"class": "GenericError", "desc": "Backing format cannot be used without backing file"}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
-
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'preallocation': 'full', 'driver': 'qcow2', 'backing-file': '/dev/null', 'file': 'node0', 'size': 67108864}}}
+{u'return': {}}
+Job failed: Backing file and preallocation cannot be used at the same time
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'backing-fmt': 'qcow2', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
+{u'return': {}}
+Job failed: Backing format cannot be used without backing file
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
=== Invalid cluster size ===
-
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
-QMP_VERSION
-{"return": {}}
-{"error": {"class": "GenericError", "desc": "Cluster size must be a power of two between 512 and 2048k"}}
-{"error": {"class": "GenericError", "desc": "Cluster size must be a power of two between 512 and 2048k"}}
-{"error": {"class": "GenericError", "desc": "Cluster size must be a power of two between 512 and 2048k"}}
-{"error": {"class": "GenericError", "desc": "Cluster size must be a power of two between 512 and 2048k"}}
-{"error": {"class": "GenericError", "desc": "Could not resize image: Failed to grow the L1 table: File too large"}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
-
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 1234, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
+{u'return': {}}
+Job failed: Cluster size must be a power of two between 512 and 2048k
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 128, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
+{u'return': {}}
+Job failed: Cluster size must be a power of two between 512 and 2048k
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 4194304, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
+{u'return': {}}
+Job failed: Cluster size must be a power of two between 512 and 2048k
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 0, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
+{u'return': {}}
+Job failed: Cluster size must be a power of two between 512 and 2048k
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 512, 'driver': 'qcow2', 'file': 'node0', 'size': 281474976710656}}}
+{u'return': {}}
+Job failed: Could not resize image: Failed to grow the L1 table: File too large
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
=== Invalid refcount width ===
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 128, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
+{u'return': {}}
+Job failed: Refcount width must be a power of two and may not exceed 64 bits
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 0, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
+{u'return': {}}
+Job failed: Refcount width must be a power of two and may not exceed 64 bits
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 7, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}}
+{u'return': {}}
+Job failed: Refcount width must be a power of two and may not exceed 64 bits
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
-QMP_VERSION
-{"return": {}}
-{"error": {"class": "GenericError", "desc": "Refcount width must be a power of two and may not exceed 64 bits"}}
-{"error": {"class": "GenericError", "desc": "Refcount width must be a power of two and may not exceed 64 bits"}}
-{"error": {"class": "GenericError", "desc": "Refcount width must be a power of two and may not exceed 64 bits"}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
-
-*** done
diff --git a/tests/qemu-iotests/207 b/tests/qemu-iotests/207
index f5c77852d1..444ae233ae 100755
--- a/tests/qemu-iotests/207
+++ b/tests/qemu-iotests/207
@@ -1,9 +1,11 @@
-#!/bin/bash
+#!/usr/bin/env python
#
# Test ssh image creation
#
# Copyright (C) 2018 Red Hat, Inc.
#
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
@@ -18,244 +20,198 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-# creator
-owner=kwolf@redhat.com
-
-seq=`basename $0`
-echo "QA output created by $seq"
-
-here=`pwd`
-status=1 # failure is the default!
-
-# get standard environment, filters and checks
-. ./common.rc
-. ./common.filter
-
-_supported_fmt raw
-_supported_proto ssh
-_supported_os Linux
-
-function do_run_qemu()
-{
- echo Testing: "$@"
- $QEMU -nographic -qmp stdio -serial none "$@"
- echo
-}
-
-function run_qemu()
-{
- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
- | _filter_qemu | _filter_imgfmt \
- | _filter_actual_image_size
-}
-
-echo
-echo "=== Successful image creation (defaults) ==="
-echo
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "ssh",
- "location": {
- "path": "$TEST_IMG_FILE",
- "server": {
- "host": "127.0.0.1",
- "port": "22"
- }
- },
- "size": 4194304
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info | _filter_img_info
-echo
-TEST_IMG=$TEST_IMG_FILE _img_info | _filter_img_info
-
-echo
-echo "=== Test host-key-check options ==="
-echo
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "ssh",
- "location": {
- "path": "$TEST_IMG_FILE",
- "server": {
- "host": "127.0.0.1",
- "port": "22"
- },
- "host-key-check": {
- "mode": "none"
- }
- },
- "size": 8388608
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info | _filter_img_info
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "ssh",
- "location": {
- "path": "$TEST_IMG_FILE",
- "server": {
- "host": "127.0.0.1",
- "port": "22"
- },
- "host-key-check": {
- "mode": "known_hosts"
- }
- },
- "size": 4194304
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info | _filter_img_info
-
-
-key=$(ssh-keyscan -t rsa 127.0.0.1 2>/dev/null | grep -v "\\^#" |
- cut -d" " -f3 | base64 -d | md5sum -b | cut -d" " -f1)
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "ssh",
- "location": {
- "path": "$TEST_IMG_FILE",
- "server": {
- "host": "127.0.0.1",
- "port": "22"
- },
- "host-key-check": {
- "mode": "hash",
- "type": "md5",
- "hash": "wrong"
- }
- },
- "size": 8388608
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "ssh",
- "location": {
- "path": "$TEST_IMG_FILE",
- "server": {
- "host": "127.0.0.1",
- "port": "22"
- },
- "host-key-check": {
- "mode": "hash",
- "type": "md5",
- "hash": "$key"
- }
- },
- "size": 8388608
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info | _filter_img_info
-
-
-key=$(ssh-keyscan -t rsa 127.0.0.1 2>/dev/null | grep -v "\\^#" |
- cut -d" " -f3 | base64 -d | sha1sum -b | cut -d" " -f1)
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "ssh",
- "location": {
- "path": "$TEST_IMG_FILE",
- "server": {
- "host": "127.0.0.1",
- "port": "22"
- },
- "host-key-check": {
- "mode": "hash",
- "type": "sha1",
- "hash": "wrong"
- }
- },
- "size": 4194304
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "ssh",
- "location": {
- "path": "$TEST_IMG_FILE",
- "server": {
- "host": "127.0.0.1",
- "port": "22"
- },
- "host-key-check": {
- "mode": "hash",
- "type": "sha1",
- "hash": "$key"
- }
- },
- "size": 4194304
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info | _filter_img_info
-
-echo
-echo "=== Invalid path and user ==="
-echo
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "ssh",
- "location": {
- "path": "/this/is/not/an/existing/path",
- "server": {
- "host": "127.0.0.1",
- "port": "22"
- }
- },
- "size": 4194304
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "ssh",
- "location": {
- "path": "$TEST_IMG_FILE",
- "user": "invalid user",
- "server": {
- "host": "127.0.0.1",
- "port": "22"
- }
- },
- "size": 4194304
- }
-}
-{ "execute": "quit" }
-EOF
-
-# success, all done
-echo "*** done"
-rm -f $seq.full
-status=0
+import iotests
+import subprocess
+import re
+
+iotests.verify_image_format(supported_fmts=['raw'])
+iotests.verify_protocol(supported=['ssh'])
+
+def filter_hash(msg):
+ return re.sub("'hash': '[0-9a-f]+'", "'hash': HASH", msg)
+
+def blockdev_create(vm, options):
+ result = vm.qmp_log('blockdev-create', job_id='job0', options=options,
+ filters=[iotests.filter_testfiles, filter_hash])
+
+ if 'return' in result:
+ assert result['return'] == {}
+ vm.run_job('job0')
+ iotests.log("")
+
+with iotests.FilePath('t.img') as disk_path, \
+ iotests.VM() as vm:
+
+ remote_path = iotests.remote_filename(disk_path)
+
+ #
+ # Successful image creation (defaults)
+ #
+ iotests.log("=== Successful image creation (defaults) ===")
+ iotests.log("")
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': 'ssh',
+ 'location': {
+ 'path': disk_path,
+ 'server': {
+ 'host': '127.0.0.1',
+ 'port': '22'
+ }
+ },
+ 'size': 4194304 })
+ vm.shutdown()
+
+ iotests.img_info_log(remote_path, filter_path=disk_path)
+ iotests.log("")
+ iotests.img_info_log(disk_path)
+
+ #
+ # Test host-key-check options
+ #
+ iotests.log("=== Test host-key-check options ===")
+ iotests.log("")
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': 'ssh',
+ 'location': {
+ 'path': disk_path,
+ 'server': {
+ 'host': '127.0.0.1',
+ 'port': '22'
+ },
+ 'host-key-check': {
+ 'mode': 'none'
+ }
+ },
+ 'size': 8388608 })
+ vm.shutdown()
+
+ iotests.img_info_log(remote_path, filter_path=disk_path)
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': 'ssh',
+ 'location': {
+ 'path': disk_path,
+ 'server': {
+ 'host': '127.0.0.1',
+ 'port': '22'
+ },
+ 'host-key-check': {
+ 'mode': 'known_hosts'
+ }
+ },
+ 'size': 4194304 })
+ vm.shutdown()
+
+ iotests.img_info_log(remote_path, filter_path=disk_path)
+
+ md5_key = subprocess.check_output(
+ 'ssh-keyscan -t rsa 127.0.0.1 2>/dev/null | grep -v "\\^#" | ' +
+ 'cut -d" " -f3 | base64 -d | md5sum -b | cut -d" " -f1',
+ shell=True).rstrip()
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': 'ssh',
+ 'location': {
+ 'path': disk_path,
+ 'server': {
+ 'host': '127.0.0.1',
+ 'port': '22'
+ },
+ 'host-key-check': {
+ 'mode': 'hash',
+ 'type': 'md5',
+ 'hash': 'wrong',
+ }
+ },
+ 'size': 2097152 })
+ blockdev_create(vm, { 'driver': 'ssh',
+ 'location': {
+ 'path': disk_path,
+ 'server': {
+ 'host': '127.0.0.1',
+ 'port': '22'
+ },
+ 'host-key-check': {
+ 'mode': 'hash',
+ 'type': 'md5',
+ 'hash': md5_key,
+ }
+ },
+ 'size': 8388608 })
+ vm.shutdown()
+
+ iotests.img_info_log(remote_path, filter_path=disk_path)
+
+ sha1_key = subprocess.check_output(
+ 'ssh-keyscan -t rsa 127.0.0.1 2>/dev/null | grep -v "\\^#" | ' +
+ 'cut -d" " -f3 | base64 -d | sha1sum -b | cut -d" " -f1',
+ shell=True).rstrip()
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': 'ssh',
+ 'location': {
+ 'path': disk_path,
+ 'server': {
+ 'host': '127.0.0.1',
+ 'port': '22'
+ },
+ 'host-key-check': {
+ 'mode': 'hash',
+ 'type': 'sha1',
+ 'hash': 'wrong',
+ }
+ },
+ 'size': 2097152 })
+ blockdev_create(vm, { 'driver': 'ssh',
+ 'location': {
+ 'path': disk_path,
+ 'server': {
+ 'host': '127.0.0.1',
+ 'port': '22'
+ },
+ 'host-key-check': {
+ 'mode': 'hash',
+ 'type': 'sha1',
+ 'hash': sha1_key,
+ }
+ },
+ 'size': 4194304 })
+ vm.shutdown()
+
+ iotests.img_info_log(remote_path, filter_path=disk_path)
+
+ #
+ # Invalid path and user
+ #
+ iotests.log("=== Invalid path and user ===")
+ iotests.log("")
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': 'ssh',
+ 'location': {
+ 'path': '/this/is/not/an/existing/path',
+ 'server': {
+ 'host': '127.0.0.1',
+ 'port': '22'
+ },
+ 'host-key-check': {
+ 'mode': 'none'
+ }
+ },
+ 'size': 4194304 })
+ blockdev_create(vm, { 'driver': 'ssh',
+ 'location': {
+ 'path': disk_path,
+ 'user': 'invalid user',
+ 'server': {
+ 'host': '127.0.0.1',
+ 'port': '22'
+ },
+ 'host-key-check': {
+ 'mode': 'none'
+ }
+ },
+ 'size': 4194304 })
+ vm.shutdown()
diff --git a/tests/qemu-iotests/207.out b/tests/qemu-iotests/207.out
index 417deee970..078b7e63cb 100644
--- a/tests/qemu-iotests/207.out
+++ b/tests/qemu-iotests/207.out
@@ -1,75 +1,80 @@
-QA output created by 207
-
=== Successful image creation (defaults) ===
-Testing:
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}}
+image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}}
file format: IMGFMT
virtual size: 4.0M (4194304 bytes)
-image: TEST_DIR/t.IMGFMT
+
+image: TEST_IMG
file format: IMGFMT
virtual size: 4.0M (4194304 bytes)
=== Test host-key-check options ===
-Testing:
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'mode': 'none'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 8388608}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}}
+image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}}
file format: IMGFMT
virtual size: 8.0M (8388608 bytes)
-Testing:
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
-
-image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'mode': 'known_hosts'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}}
file format: IMGFMT
virtual size: 4.0M (4194304 bytes)
-Testing:
-QMP_VERSION
-{"return": {}}
-{"error": {"class": "GenericError", "desc": "remote host key does not match host_key_check 'wrong'"}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
-
-image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': 'wrong', 'type': 'md5', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 2097152}}}
+{u'return': {}}
+Job failed: remote host key does not match host_key_check 'wrong'
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': HASH, 'type': 'md5', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 8388608}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}}
file format: IMGFMT
virtual size: 8.0M (8388608 bytes)
-Testing:
-QMP_VERSION
-{"return": {}}
-{"error": {"class": "GenericError", "desc": "remote host key does not match host_key_check 'wrong'"}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
-
-image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': 'wrong', 'type': 'sha1', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 2097152}}}
+{u'return': {}}
+Job failed: remote host key does not match host_key_check 'wrong'
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': HASH, 'type': 'sha1', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}}
file format: IMGFMT
virtual size: 4.0M (4194304 bytes)
=== Invalid path and user ===
-Testing:
-QMP_VERSION
-{"return": {}}
-{"error": {"class": "GenericError", "desc": "failed to open remote file '/this/is/not/an/existing/path': Failed opening remote file (libssh2 error code: -31)"}}
-{"error": {"class": "GenericError", "desc": "failed to authenticate using publickey authentication and the identities held by your ssh-agent"}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': '/this/is/not/an/existing/path', 'host-key-check': {'mode': 'none'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}}
+{u'return': {}}
+Job failed: failed to open remote file '/this/is/not/an/existing/path': Failed opening remote file (libssh2 error code: -31)
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'mode': 'none'}, 'user': 'invalid user', 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}}
+{u'return': {}}
+Job failed: failed to authenticate using publickey authentication and the identities held by your ssh-agent
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-*** done
diff --git a/tests/qemu-iotests/210 b/tests/qemu-iotests/210
index e607c0d296..d142841e2b 100755
--- a/tests/qemu-iotests/210
+++ b/tests/qemu-iotests/210
@@ -1,9 +1,11 @@
-#!/bin/bash
+#!/usr/bin/env python
#
# Test luks and file image creation
#
# Copyright (C) 2018 Red Hat, Inc.
#
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
@@ -18,230 +20,165 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-# creator
-owner=kwolf@redhat.com
-
-seq=`basename $0`
-echo "QA output created by $seq"
-
-here=`pwd`
-status=1 # failure is the default!
-
-# get standard environment, filters and checks
-. ./common.rc
-. ./common.filter
-
-_supported_fmt luks
-_supported_proto file
-_supported_os Linux
-
-function do_run_qemu()
-{
- echo Testing: "$@"
- $QEMU -nographic -qmp stdio -serial none "$@"
- echo
-}
-
-function run_qemu()
-{
- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
- | _filter_qemu | _filter_imgfmt \
- | _filter_actual_image_size
-}
-
-echo
-echo "=== Successful image creation (defaults) ==="
-echo
-
-size=$((128 * 1024 * 1024))
-
-run_qemu -object secret,id=keysec0,data="foo" <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "file",
- "filename": "$TEST_IMG_FILE",
- "size": 0
- }
-}
-{ "execute": "blockdev-add",
- "arguments": {
- "driver": "file",
- "node-name": "imgfile",
- "filename": "$TEST_IMG_FILE"
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "imgfile",
- "key-secret": "keysec0",
- "size": $size,
- "iter-time": 10
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info --format-specific | _filter_img_info --format-specific
-
-echo
-echo "=== Successful image creation (with non-default options) ==="
-echo
-
-# Choose a different size to show that we got a new image
-size=$((64 * 1024 * 1024))
-
-run_qemu -object secret,id=keysec0,data="foo" <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "file",
- "filename": "$TEST_IMG_FILE",
- "size": 0
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": {
- "driver": "file",
- "filename": "$TEST_IMG_FILE"
- },
- "size": $size,
- "key-secret": "keysec0",
- "cipher-alg": "twofish-128",
- "cipher-mode": "ctr",
- "ivgen-alg": "plain64",
- "ivgen-hash-alg": "md5",
- "hash-alg": "sha1",
- "iter-time": 10
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info --format-specific | _filter_img_info --format-specific
-
-echo
-echo "=== Invalid BlockdevRef ==="
-echo
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "this doesn't exist",
- "size": $size
- }
-}
-{ "execute": "quit" }
-EOF
-
-echo
-echo "=== Zero size ==="
-echo
-
-run_qemu -blockdev driver=file,filename="$TEST_IMG_FILE",node-name=node0 \
- -object secret,id=keysec0,data="foo" <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "key-secret": "keysec0",
- "size": 0,
- "iter-time": 10
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info | _filter_img_info
-
-
-echo
-echo "=== Invalid sizes ==="
-echo
-
-# TODO Negative image sizes aren't handled correctly, but this is a problem
-# with QAPI's implementation of the 'size' type and affects other commands as
-# well. Once this is fixed, we may want to add a test case here.
-
-# 1. 2^64 - 512
-# 2. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
-# 3. 2^63 - 512 (generally valid, but with the crypto header the file will
-# exceed 63 bits)
-
-run_qemu -blockdev driver=file,filename="$TEST_IMG_FILE",node-name=node0 \
- -object secret,id=keysec0,data="foo" <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "key-secret": "keysec0",
- "size": 18446744073709551104
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "key-secret": "keysec0",
- "size": 9223372036854775808
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "key-secret": "keysec0",
- "size": 9223372036854775296
- }
-}
-{ "execute": "quit" }
-EOF
-
-echo
-echo "=== Resize image with invalid sizes ==="
-echo
-
-run_qemu -blockdev driver=file,filename="$TEST_IMG_FILE",node-name=node0 \
- -blockdev driver=luks,file=node0,key-secret=keysec0,node-name=node1 \
- -object secret,id=keysec0,data="foo" <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "block_resize",
- "arguments": {
- "node-name": "node1",
- "size": 9223372036854775296
- }
-}
-{ "execute": "block_resize",
- "arguments": {
- "node-name": "node1",
- "size": 9223372036854775808
- }
-}
-{ "execute": "block_resize",
- "arguments": {
- "node-name": "node1",
- "size": 18446744073709551104
- }
-}
-{ "execute": "block_resize",
- "arguments": {
- "node-name": "node1",
- "size": -9223372036854775808
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info | _filter_img_info
-
-# success, all done
-echo "*** done"
-rm -f $seq.full
-status=0
+import iotests
+from iotests import imgfmt
+
+iotests.verify_image_format(supported_fmts=['luks'])
+iotests.verify_protocol(supported=['file'])
+
+def blockdev_create(vm, options):
+ result = vm.qmp_log('blockdev-create', job_id='job0', options=options)
+
+ if 'return' in result:
+ assert result['return'] == {}
+ vm.run_job('job0')
+ iotests.log("")
+
+with iotests.FilePath('t.luks') as disk_path, \
+ iotests.VM() as vm:
+
+ vm.add_object('secret,id=keysec0,data=foo')
+
+ #
+ # Successful image creation (defaults)
+ #
+ iotests.log("=== Successful image creation (defaults) ===")
+ iotests.log("")
+
+ size = 128 * 1024 * 1024
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': 'file',
+ 'filename': disk_path,
+ 'size': 0 })
+
+ vm.qmp_log('blockdev-add', driver='file', filename=disk_path,
+ node_name='imgfile')
+
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'imgfile',
+ 'key-secret': 'keysec0',
+ 'size': size,
+ 'iter-time': 10 })
+ vm.shutdown()
+
+ # TODO Proper support for images to be used with imgopts and/or protocols
+ iotests.img_info_log(
+ 'driver=luks,file.driver=file,file.filename=%s,key-secret=keysec0' % (disk_path),
+ filter_path=disk_path,
+ extra_args=['--object', 'secret,id=keysec0,data=foo'],
+ imgopts=True)
+
+ #
+ # Successful image creation (with non-default options)
+ #
+ iotests.log("=== Successful image creation (with non-default options) ===")
+ iotests.log("")
+
+ size = 64 * 1024 * 1024
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': 'file',
+ 'filename': disk_path,
+ 'size': 0 })
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': {
+ 'driver': 'file',
+ 'filename': disk_path,
+ },
+ 'size': size,
+ 'key-secret': 'keysec0',
+ 'cipher-alg': 'twofish-128',
+ 'cipher-mode': 'ctr',
+ 'ivgen-alg': 'plain64',
+ 'ivgen-hash-alg': 'md5',
+ 'hash-alg': 'sha1',
+ 'iter-time': 10 })
+ vm.shutdown()
+
+ # TODO Proper support for images to be used with imgopts and/or protocols
+ iotests.img_info_log(
+ 'driver=luks,file.driver=file,file.filename=%s,key-secret=keysec0' % (disk_path),
+ filter_path=disk_path,
+ extra_args=['--object', 'secret,id=keysec0,data=foo'],
+ imgopts=True)
+
+ #
+ # Invalid BlockdevRef
+ #
+ iotests.log("=== Invalid BlockdevRef ===")
+ iotests.log("")
+
+ size = 64 * 1024 * 1024
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': "this doesn't exist",
+ 'size': size })
+ vm.shutdown()
+
+ #
+ # Zero size
+ #
+ iotests.log("=== Zero size ===")
+ iotests.log("")
+
+ vm.add_blockdev('driver=file,filename=%s,node-name=node0' % (disk_path))
+ vm.launch()
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'node0',
+ 'key-secret': 'keysec0',
+ 'size': 0,
+ 'iter-time': 10 })
+ vm.shutdown()
+
+ # TODO Proper support for images to be used with imgopts and/or protocols
+ iotests.img_info_log(
+ 'driver=luks,file.driver=file,file.filename=%s,key-secret=keysec0' % (disk_path),
+ filter_path=disk_path,
+ extra_args=['--object', 'secret,id=keysec0,data=foo'],
+ imgopts=True)
+
+ #
+ # Invalid sizes
+ #
+
+ # TODO Negative image sizes aren't handled correctly, but this is a problem
+ # with QAPI's implementation of the 'size' type and affects other commands as
+ # well. Once this is fixed, we may want to add a test case here.
+
+ # 1. 2^64 - 512
+ # 2. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
+ # 3. 2^63 - 512 (generally valid, but with the crypto header the file will
+ # exceed 63 bits)
+ iotests.log("=== Invalid sizes ===")
+ iotests.log("")
+
+ vm.launch()
+ for size in [ 18446744073709551104, 9223372036854775808, 9223372036854775296 ]:
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'node0',
+ 'key-secret': 'keysec0',
+ 'size': size })
+ vm.shutdown()
+
+ #
+ # Resize image with invalid sizes
+ #
+ iotests.log("=== Resize image with invalid sizes ===")
+ iotests.log("")
+
+ vm.add_blockdev('driver=luks,file=node0,key-secret=keysec0,node-name=node1')
+ vm.launch()
+ vm.qmp_log('block_resize', node_name='node1', size=9223372036854775296)
+ vm.qmp_log('block_resize', node_name='node1', size=9223372036854775808)
+ vm.qmp_log('block_resize', node_name='node1', size=18446744073709551104)
+ vm.qmp_log('block_resize', node_name='node1', size=-9223372036854775808)
+ vm.shutdown()
+
+ # TODO Proper support for images to be used with imgopts and/or protocols
+ iotests.img_info_log(
+ 'driver=luks,file.driver=file,file.filename=%s,key-secret=keysec0' % (disk_path),
+ filter_path=disk_path,
+ extra_args=['--object', 'secret,id=keysec0,data=foo'],
+ imgopts=True)
diff --git a/tests/qemu-iotests/210.out b/tests/qemu-iotests/210.out
index 8198f8c829..078ba544a1 100644
--- a/tests/qemu-iotests/210.out
+++ b/tests/qemu-iotests/210.out
@@ -1,29 +1,31 @@
-QA output created by 210
-
=== Successful image creation (defaults) ===
-Testing: -object secret,id=keysec0,data=foo
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.luks'}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-add', 'arguments': {'node_name': 'imgfile', 'driver': 'file', 'filename': 'TEST_DIR/PID-t.luks'}}
+{u'return': {}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'iter-time': 10, 'driver': 'luks', 'file': 'imgfile', 'size': 134217728}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "key-secret": "keysec0"}
+image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_IMG"}, "key-secret": "keysec0"}
file format: IMGFMT
virtual size: 128M (134217728 bytes)
+encrypted: yes
Format specific information:
ivgen alg: plain64
hash alg: sha256
cipher alg: aes-256
- uuid: 00000000-0000-0000-0000-000000000000
+ uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
cipher mode: xts
slots:
[0]:
active: true
- iters: 1024
+ iters: XXX
key offset: 4096
stripes: 4000
[1]:
@@ -48,31 +50,34 @@ Format specific information:
active: false
key offset: 1810432
payload offset: 2068480
- master key iters: 1024
+ master key iters: XXX
=== Successful image creation (with non-default options) ===
-Testing: -object secret,id=keysec0,data=foo
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.luks'}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'hash-alg': 'sha1', 'cipher-mode': 'ctr', 'cipher-alg': 'twofish-128', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.luks'}, 'iter-time': 10, 'ivgen-alg': 'plain64', 'ivgen-hash-alg': 'md5', 'driver': 'luks', 'size': 67108864}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "key-secret": "keysec0"}
+image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_IMG"}, "key-secret": "keysec0"}
file format: IMGFMT
virtual size: 64M (67108864 bytes)
+encrypted: yes
Format specific information:
ivgen alg: plain64
hash alg: sha1
cipher alg: twofish-128
- uuid: 00000000-0000-0000-0000-000000000000
+ uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
cipher mode: ctr
slots:
[0]:
active: true
- iters: 1024
+ iters: XXX
key offset: 4096
stripes: 4000
[1]:
@@ -97,56 +102,130 @@ Format specific information:
active: false
key offset: 462848
payload offset: 528384
- master key iters: 1024
+ master key iters: XXX
=== Invalid BlockdevRef ===
-Testing:
-QMP_VERSION
-{"return": {}}
-{"error": {"class": "GenericError", "desc": "Cannot find device=this doesn't exist nor node_name=this doesn't exist"}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
-
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'luks', 'file': "this doesn't exist", 'size': 67108864}}}
+{u'return': {}}
+Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
=== Zero size ===
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0 -object secret,id=keysec0,data=foo
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'iter-time': 10, 'driver': 'luks', 'file': 'node0', 'size': 0}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "key-secret": "keysec0"}
+image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_IMG"}, "key-secret": "keysec0"}
file format: IMGFMT
virtual size: 0 (0 bytes)
+encrypted: yes
+Format specific information:
+ ivgen alg: plain64
+ hash alg: sha256
+ cipher alg: aes-256
+ uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
+ cipher mode: xts
+ slots:
+ [0]:
+ active: true
+ iters: XXX
+ key offset: 4096
+ stripes: 4000
+ [1]:
+ active: false
+ key offset: 262144
+ [2]:
+ active: false
+ key offset: 520192
+ [3]:
+ active: false
+ key offset: 778240
+ [4]:
+ active: false
+ key offset: 1036288
+ [5]:
+ active: false
+ key offset: 1294336
+ [6]:
+ active: false
+ key offset: 1552384
+ [7]:
+ active: false
+ key offset: 1810432
+ payload offset: 2068480
+ master key iters: XXX
=== Invalid sizes ===
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0 -object secret,id=keysec0,data=foo
-QMP_VERSION
-{"return": {}}
-{"error": {"class": "GenericError", "desc": "The requested file size is too large"}}
-{"error": {"class": "GenericError", "desc": "The requested file size is too large"}}
-{"error": {"class": "GenericError", "desc": "The requested file size is too large"}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'driver': 'luks', 'file': 'node0', 'size': 18446744073709551104L}}}
+{u'return': {}}
+Job failed: The requested file size is too large
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'driver': 'luks', 'file': 'node0', 'size': 9223372036854775808L}}}
+{u'return': {}}
+Job failed: The requested file size is too large
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'driver': 'luks', 'file': 'node0', 'size': 9223372036854775296}}}
+{u'return': {}}
+Job failed: The requested file size is too large
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
=== Resize image with invalid sizes ===
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0 -blockdev driver=IMGFMT,file=node0,key-secret=keysec0,node-name=node1 -object secret,id=keysec0,data=foo
-QMP_VERSION
-{"return": {}}
-{"error": {"class": "GenericError", "desc": "The requested file size is too large"}}
-{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'size', expected: integer"}}
-{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'size', expected: integer"}}
-{"error": {"class": "GenericError", "desc": "Parameter 'size' expects a >0 size"}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
-
-image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "key-secret": "keysec0"}
+{'execute': 'block_resize', 'arguments': {'size': 9223372036854775296, 'node_name': 'node1'}}
+{u'error': {u'class': u'GenericError', u'desc': u'The requested file size is too large'}}
+{'execute': 'block_resize', 'arguments': {'size': 9223372036854775808L, 'node_name': 'node1'}}
+{u'error': {u'class': u'GenericError', u'desc': u"Invalid parameter type for 'size', expected: integer"}}
+{'execute': 'block_resize', 'arguments': {'size': 18446744073709551104L, 'node_name': 'node1'}}
+{u'error': {u'class': u'GenericError', u'desc': u"Invalid parameter type for 'size', expected: integer"}}
+{'execute': 'block_resize', 'arguments': {'size': -9223372036854775808, 'node_name': 'node1'}}
+{u'error': {u'class': u'GenericError', u'desc': u"Parameter 'size' expects a >0 size"}}
+image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_IMG"}, "key-secret": "keysec0"}
file format: IMGFMT
virtual size: 0 (0 bytes)
-*** done
+encrypted: yes
+Format specific information:
+ ivgen alg: plain64
+ hash alg: sha256
+ cipher alg: aes-256
+ uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
+ cipher mode: xts
+ slots:
+ [0]:
+ active: true
+ iters: XXX
+ key offset: 4096
+ stripes: 4000
+ [1]:
+ active: false
+ key offset: 262144
+ [2]:
+ active: false
+ key offset: 520192
+ [3]:
+ active: false
+ key offset: 778240
+ [4]:
+ active: false
+ key offset: 1036288
+ [5]:
+ active: false
+ key offset: 1294336
+ [6]:
+ active: false
+ key offset: 1552384
+ [7]:
+ active: false
+ key offset: 1810432
+ payload offset: 2068480
+ master key iters: XXX
+
diff --git a/tests/qemu-iotests/211 b/tests/qemu-iotests/211
index 1edec26517..7b7985db6c 100755
--- a/tests/qemu-iotests/211
+++ b/tests/qemu-iotests/211
@@ -1,9 +1,11 @@
-#!/bin/bash
+#!/usr/bin/env python
#
# Test VDI and file image creation
#
# Copyright (C) 2018 Red Hat, Inc.
#
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
@@ -18,229 +20,154 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-# creator
-owner=kwolf@redhat.com
-
-seq=`basename $0`
-echo "QA output created by $seq"
-
-here=`pwd`
-status=1 # failure is the default!
-
-# get standard environment, filters and checks
-. ./common.rc
-. ./common.filter
-
-_supported_fmt vdi
-_supported_proto file
-_supported_os Linux
-
-function do_run_qemu()
-{
- echo Testing: "$@"
- $QEMU -nographic -qmp stdio -serial none "$@"
- echo
-}
-
-function run_qemu()
-{
- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
- | _filter_qemu | _filter_imgfmt \
- | _filter_actual_image_size
-}
-
-echo
-echo "=== Successful image creation (defaults) ==="
-echo
-
-size=$((128 * 1024 * 1024))
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "file",
- "filename": "$TEST_IMG",
- "size": 0
- }
-}
-{ "execute": "blockdev-add",
- "arguments": {
- "driver": "file",
- "node-name": "imgfile",
- "filename": "$TEST_IMG"
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "imgfile",
- "size": $size
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info --format-specific | _filter_img_info --format-specific
-$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
-
-echo
-echo "=== Successful image creation (explicit defaults) ==="
-echo
-
-# Choose a different size to show that we got a new image
-size=$((64 * 1024 * 1024))
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "file",
- "filename": "$TEST_IMG",
- "size": 0
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": {
- "driver": "file",
- "filename": "$TEST_IMG"
- },
- "size": $size,
- "preallocation": "off"
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info --format-specific | _filter_img_info --format-specific
-$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
-
-echo
-echo "=== Successful image creation (with non-default options) ==="
-echo
-
-# Choose a different size to show that we got a new image
-size=$((32 * 1024 * 1024))
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "file",
- "filename": "$TEST_IMG",
- "size": 0
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": {
- "driver": "file",
- "filename": "$TEST_IMG"
- },
- "size": $size,
- "preallocation": "metadata"
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info --format-specific | _filter_img_info --format-specific
-$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map
-
-echo
-echo "=== Invalid BlockdevRef ==="
-echo
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "this doesn't exist",
- "size": $size
- }
-}
-{ "execute": "quit" }
-EOF
-
-echo
-echo "=== Zero size ==="
-echo
-
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 0
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info | _filter_img_info
-
-echo
-echo "=== Maximum size ==="
-echo
-
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 562949819203584
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info | _filter_img_info
-
-echo
-echo "=== Invalid sizes ==="
-echo
-
-# TODO Negative image sizes aren't handled correctly, but this is a problem
-# with QAPI's implementation of the 'size' type and affects other commands as
-# well. Once this is fixed, we may want to add a test case here.
-
-# 1. 2^64 - 512
-# 2. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
-# 3. 0x1fffff8000001 (one byte more than maximum image size for VDI)
-
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 18446744073709551104
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 9223372036854775808
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 562949819203585
- }
-}
-{ "execute": "quit" }
-EOF
-
-# success, all done
-echo "*** done"
-rm -f $seq.full
-status=0
+import iotests
+from iotests import imgfmt
+
+iotests.verify_image_format(supported_fmts=['vdi'])
+iotests.verify_protocol(supported=['file'])
+
+def blockdev_create(vm, options):
+ result = vm.qmp_log('blockdev-create', job_id='job0', options=options)
+
+ if 'return' in result:
+ assert result['return'] == {}
+ vm.run_job('job0')
+ iotests.log("")
+
+with iotests.FilePath('t.vdi') as disk_path, \
+ iotests.VM() as vm:
+
+ #
+ # Successful image creation (defaults)
+ #
+ iotests.log("=== Successful image creation (defaults) ===")
+ iotests.log("")
+
+ size = 128 * 1024 * 1024
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': 'file',
+ 'filename': disk_path,
+ 'size': 0 })
+
+ vm.qmp_log('blockdev-add', driver='file', filename=disk_path,
+ node_name='imgfile')
+
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'imgfile',
+ 'size': size })
+ vm.shutdown()
+
+ iotests.img_info_log(disk_path)
+ iotests.log(iotests.qemu_img_pipe('map', '--output=json', disk_path))
+
+ #
+ # Successful image creation (explicit defaults)
+ #
+ iotests.log("=== Successful image creation (explicit defaults) ===")
+ iotests.log("")
+
+ size = 64 * 1024 * 1024
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': 'file',
+ 'filename': disk_path,
+ 'size': 0 })
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': {
+ 'driver': 'file',
+ 'filename': disk_path,
+ },
+ 'size': size,
+ 'preallocation': 'off' })
+ vm.shutdown()
+
+ iotests.img_info_log(disk_path)
+ iotests.log(iotests.qemu_img_pipe('map', '--output=json', disk_path))
+
+ #
+ # Successful image creation (with non-default options)
+ #
+ iotests.log("=== Successful image creation (with non-default options) ===")
+ iotests.log("")
+
+ size = 32 * 1024 * 1024
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': 'file',
+ 'filename': disk_path,
+ 'size': 0 })
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': {
+ 'driver': 'file',
+ 'filename': disk_path,
+ },
+ 'size': size,
+ 'preallocation': 'metadata' })
+ vm.shutdown()
+
+ iotests.img_info_log(disk_path)
+ iotests.log(iotests.qemu_img_pipe('map', '--output=json', disk_path))
+
+ #
+ # Invalid BlockdevRef
+ #
+ iotests.log("=== Invalid BlockdevRef ===")
+ iotests.log("")
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': "this doesn't exist",
+ 'size': size })
+ vm.shutdown()
+
+ #
+ # Zero size
+ #
+ iotests.log("=== Zero size ===")
+ iotests.log("")
+
+ vm.add_blockdev('driver=file,filename=%s,node-name=node0' % (disk_path))
+ vm.launch()
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'node0',
+ 'size': 0 })
+ vm.shutdown()
+
+ iotests.img_info_log(disk_path)
+
+ #
+ # Maximum size
+ #
+ iotests.log("=== Maximum size ===")
+ iotests.log("")
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'node0',
+ 'size': 562949819203584 })
+ vm.shutdown()
+
+ iotests.img_info_log(disk_path)
+
+ #
+ # Invalid sizes
+ #
+
+ # TODO Negative image sizes aren't handled correctly, but this is a problem
+ # with QAPI's implementation of the 'size' type and affects other commands
+ # as well. Once this is fixed, we may want to add a test case here.
+
+ # 1. 2^64 - 512
+ # 2. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
+ # 3. 0x1fffff8000001 (one byte more than maximum image size for VDI)
+
+ iotests.log("=== Invalid sizes ===")
+ iotests.log("")
+
+ vm.launch()
+ for size in [ 18446744073709551104, 9223372036854775808, 562949819203585 ]:
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'node0',
+ 'size': size })
+ vm.shutdown()
diff --git a/tests/qemu-iotests/211.out b/tests/qemu-iotests/211.out
index 3247bbaa64..6feaea3978 100644
--- a/tests/qemu-iotests/211.out
+++ b/tests/qemu-iotests/211.out
@@ -1,97 +1,112 @@
-QA output created by 211
-
=== Successful image creation (defaults) ===
-Testing:
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-add', 'arguments': {'node_name': 'imgfile', 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}}
+{u'return': {}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'imgfile', 'size': 134217728}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-image: TEST_DIR/t.IMGFMT
+image: TEST_IMG
file format: IMGFMT
virtual size: 128M (134217728 bytes)
+cluster_size: 1048576
+
[{ "start": 0, "length": 134217728, "depth": 0, "zero": true, "data": false}]
=== Successful image creation (explicit defaults) ===
-Testing:
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-image: TEST_DIR/t.IMGFMT
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'preallocation': 'off', 'driver': 'vdi', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}, 'size': 67108864}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+image: TEST_IMG
file format: IMGFMT
virtual size: 64M (67108864 bytes)
+cluster_size: 1048576
+
[{ "start": 0, "length": 67108864, "depth": 0, "zero": true, "data": false}]
=== Successful image creation (with non-default options) ===
-Testing:
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-image: TEST_DIR/t.IMGFMT
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'preallocation': 'metadata', 'driver': 'vdi', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}, 'size': 33554432}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+image: TEST_IMG
file format: IMGFMT
virtual size: 32M (33554432 bytes)
-[{ "start": 0, "length": 3072, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
-{ "start": 3072, "length": 33551360, "depth": 0, "zero": true, "data": true, "offset": OFFSET}]
+cluster_size: 1048576
-=== Invalid BlockdevRef ===
+[{ "start": 0, "length": 3072, "depth": 0, "zero": false, "data": true, "offset": 1024},
+{ "start": 3072, "length": 33551360, "depth": 0, "zero": true, "data": true, "offset": 4096}]
-Testing:
-QMP_VERSION
-{"return": {}}
-{"error": {"class": "GenericError", "desc": "Cannot find device=this doesn't exist nor node_name=this doesn't exist"}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+=== Invalid BlockdevRef ===
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': "this doesn't exist", 'size': 33554432}}}
+{u'return': {}}
+Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
=== Zero size ===
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 0}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-image: TEST_DIR/t.IMGFMT
+image: TEST_IMG
file format: IMGFMT
virtual size: 0 (0 bytes)
+cluster_size: 1048576
=== Maximum size ===
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 562949819203584}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-image: TEST_DIR/t.IMGFMT
+image: TEST_IMG
file format: IMGFMT
virtual size: 512T (562949819203584 bytes)
+cluster_size: 1048576
=== Invalid sizes ===
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
-QMP_VERSION
-{"return": {}}
-{"error": {"class": "GenericError", "desc": "Unsupported VDI image size (size is 0xfffffffffffffe00, max supported is 0x1fffff8000000)"}}
-{"error": {"class": "GenericError", "desc": "Unsupported VDI image size (size is 0x8000000000000000, max supported is 0x1fffff8000000)"}}
-{"error": {"class": "GenericError", "desc": "Unsupported VDI image size (size is 0x1fffff8000001, max supported is 0x1fffff8000000)"}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 18446744073709551104L}}}
+{u'return': {}}
+Job failed: Unsupported VDI image size (size is 0xfffffffffffffe00, max supported is 0x1fffff8000000)
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 9223372036854775808L}}}
+{u'return': {}}
+Job failed: Unsupported VDI image size (size is 0x8000000000000000, max supported is 0x1fffff8000000)
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 562949819203585}}}
+{u'return': {}}
+Job failed: Unsupported VDI image size (size is 0x1fffff8000001, max supported is 0x1fffff8000000)
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-*** done
diff --git a/tests/qemu-iotests/212 b/tests/qemu-iotests/212
index e5a1ba77ce..95c8810d83 100755
--- a/tests/qemu-iotests/212
+++ b/tests/qemu-iotests/212
@@ -1,9 +1,11 @@
-#!/bin/bash
+#!/usr/bin/env python
#
# Test parallels and file image creation
#
# Copyright (C) 2018 Red Hat, Inc.
#
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
@@ -18,309 +20,176 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-# creator
-owner=kwolf@redhat.com
-
-seq=`basename $0`
-echo "QA output created by $seq"
-
-here=`pwd`
-status=1 # failure is the default!
-
-# get standard environment, filters and checks
-. ./common.rc
-. ./common.filter
-
-_supported_fmt parallels
-_supported_proto file
-_supported_os Linux
-
-function do_run_qemu()
-{
- echo Testing: "$@"
- $QEMU -nographic -qmp stdio -serial none "$@"
- echo
-}
-
-function run_qemu()
-{
- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
- | _filter_qemu | _filter_imgfmt \
- | _filter_actual_image_size
-}
-
-echo
-echo "=== Successful image creation (defaults) ==="
-echo
-
-size=$((128 * 1024 * 1024))
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "file",
- "filename": "$TEST_IMG",
- "size": 0
- }
-}
-{ "execute": "blockdev-add",
- "arguments": {
- "driver": "file",
- "node-name": "imgfile",
- "filename": "$TEST_IMG"
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "imgfile",
- "size": $size
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info --format-specific | _filter_img_info --format-specific
-
-echo
-echo "=== Successful image creation (explicit defaults) ==="
-echo
-
-# Choose a different size to show that we got a new image
-size=$((64 * 1024 * 1024))
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "file",
- "filename": "$TEST_IMG",
- "size": 0
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": {
- "driver": "file",
- "filename": "$TEST_IMG"
- },
- "size": $size,
- "cluster-size": 1048576
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info --format-specific | _filter_img_info --format-specific
-
-echo
-echo "=== Successful image creation (with non-default options) ==="
-echo
-
-# Choose a different size to show that we got a new image
-size=$((32 * 1024 * 1024))
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "file",
- "filename": "$TEST_IMG",
- "size": 0
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": {
- "driver": "file",
- "filename": "$TEST_IMG"
- },
- "size": $size,
- "cluster-size": 65536
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info --format-specific | _filter_img_info --format-specific
-
-echo
-echo "=== Invalid BlockdevRef ==="
-echo
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "this doesn't exist",
- "size": $size
- }
-}
-{ "execute": "quit" }
-EOF
-
-echo
-echo "=== Zero size ==="
-echo
-
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 0
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info | _filter_img_info
-
-echo
-echo "=== Maximum size ==="
-echo
-
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 4503599627369984
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info | _filter_img_info
-
-echo
-echo "=== Invalid sizes ==="
-echo
-
-# TODO Negative image sizes aren't handled correctly, but this is a problem
-# with QAPI's implementation of the 'size' type and affects other commands as
-# well. Once this is fixed, we may want to add a test case here.
-
-# 1. Misaligned image size
-# 2. 2^64 - 512
-# 3. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
-# 4. 2^63 - 512 (generally valid, but with the image header the file will
-# exceed 63 bits)
-# 5. 2^52 (512 bytes more than maximum image size)
-
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 1234
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 18446744073709551104
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 9223372036854775808
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 9223372036854775296
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 4503599627370497
- }
-}
-{ "execute": "quit" }
-EOF
-
-echo
-echo "=== Invalid cluster size ==="
-echo
-
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 67108864,
- "cluster-size": 1234
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 67108864,
- "cluster-size": 128
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 67108864,
- "cluster-size": 4294967296
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 67108864,
- "cluster-size": 9223372036854775808
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 67108864,
- "cluster-size": 18446744073709551104
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 67108864,
- "cluster-size": 0
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 281474976710656,
- "cluster-size": 512
- }
-}
-{ "execute": "quit" }
-EOF
-
-
-# success, all done
-echo "*** done"
-rm -f $seq.full
-status=0
+import iotests
+from iotests import imgfmt
+
+iotests.verify_image_format(supported_fmts=['parallels'])
+iotests.verify_protocol(supported=['file'])
+
+def blockdev_create(vm, options):
+ result = vm.qmp_log('blockdev-create', job_id='job0', options=options)
+
+ if 'return' in result:
+ assert result['return'] == {}
+ vm.run_job('job0')
+ iotests.log("")
+
+with iotests.FilePath('t.parallels') as disk_path, \
+ iotests.VM() as vm:
+
+ #
+ # Successful image creation (defaults)
+ #
+ iotests.log("=== Successful image creation (defaults) ===")
+ iotests.log("")
+
+ size = 128 * 1024 * 1024
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': 'file',
+ 'filename': disk_path,
+ 'size': 0 })
+
+ vm.qmp_log('blockdev-add', driver='file', filename=disk_path,
+ node_name='imgfile')
+
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'imgfile',
+ 'size': size })
+ vm.shutdown()
+
+ iotests.img_info_log(disk_path)
+
+ #
+ # Successful image creation (explicit defaults)
+ #
+ iotests.log("=== Successful image creation (explicit defaults) ===")
+ iotests.log("")
+
+ # Choose a different size to show that we got a new image
+ size = 64 * 1024 * 1024
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': 'file',
+ 'filename': disk_path,
+ 'size': 0 })
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': {
+ 'driver': 'file',
+ 'filename': disk_path,
+ },
+ 'size': size,
+ 'cluster-size': 1048576 })
+ vm.shutdown()
+
+ iotests.img_info_log(disk_path)
+
+ #
+ # Successful image creation (with non-default options)
+ #
+ iotests.log("=== Successful image creation (with non-default options) ===")
+ iotests.log("")
+
+ # Choose a different size to show that we got a new image
+ size = 32 * 1024 * 1024
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': 'file',
+ 'filename': disk_path,
+ 'size': 0 })
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': {
+ 'driver': 'file',
+ 'filename': disk_path,
+ },
+ 'size': size,
+ 'cluster-size': 65536 })
+ vm.shutdown()
+
+ iotests.img_info_log(disk_path)
+
+ #
+ # Invalid BlockdevRef
+ #
+ iotests.log("=== Invalid BlockdevRef ===")
+ iotests.log("")
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': "this doesn't exist",
+ 'size': size })
+ vm.shutdown()
+
+ #
+ # Zero size
+ #
+ iotests.log("=== Zero size ===")
+ iotests.log("")
+
+ vm.add_blockdev('driver=file,filename=%s,node-name=node0' % (disk_path))
+ vm.launch()
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'node0',
+ 'size': 0 })
+ vm.shutdown()
+
+ iotests.img_info_log(disk_path)
+
+ #
+ # Maximum size
+ #
+ iotests.log("=== Maximum size ===")
+ iotests.log("")
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'node0',
+ 'size': 4503599627369984})
+ vm.shutdown()
+
+ iotests.img_info_log(disk_path)
+
+ #
+ # Invalid sizes
+ #
+
+ # TODO Negative image sizes aren't handled correctly, but this is a problem
+ # with QAPI's implementation of the 'size' type and affects other commands
+ # as well. Once this is fixed, we may want to add a test case here.
+
+ # 1. Misaligned image size
+ # 2. 2^64 - 512
+ # 3. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
+ # 4. 2^63 - 512 (generally valid, but with the image header the file will
+ # exceed 63 bits)
+ # 5. 2^52 (512 bytes more than maximum image size)
+
+ iotests.log("=== Invalid sizes ===")
+ iotests.log("")
+
+ vm.launch()
+ for size in [ 1234, 18446744073709551104, 9223372036854775808,
+ 9223372036854775296, 4503599627370497 ]:
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'node0',
+ 'size': size })
+ vm.shutdown()
+
+ #
+ # Invalid cluster size
+ #
+ iotests.log("=== Invalid cluster size ===")
+ iotests.log("")
+
+ vm.launch()
+ for csize in [ 1234, 128, 4294967296, 9223372036854775808,
+ 18446744073709551104, 0 ]:
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'node0',
+ 'size': 67108864,
+ 'cluster-size': csize })
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'node0',
+ 'size': 281474976710656,
+ 'cluster-size': 512 })
+ vm.shutdown()
diff --git a/tests/qemu-iotests/212.out b/tests/qemu-iotests/212.out
index 587de6fad0..9150da7a2c 100644
--- a/tests/qemu-iotests/212.out
+++ b/tests/qemu-iotests/212.out
@@ -1,111 +1,156 @@
-QA output created by 212
-
=== Successful image creation (defaults) ===
-Testing:
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-add', 'arguments': {'node_name': 'imgfile', 'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}}
+{u'return': {}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'imgfile', 'size': 134217728}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-image: TEST_DIR/t.IMGFMT
+image: TEST_IMG
file format: IMGFMT
virtual size: 128M (134217728 bytes)
=== Successful image creation (explicit defaults) ===
-Testing:
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-image: TEST_DIR/t.IMGFMT
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 1048576, 'driver': 'parallels', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}, 'size': 67108864}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+image: TEST_IMG
file format: IMGFMT
virtual size: 64M (67108864 bytes)
=== Successful image creation (with non-default options) ===
-Testing:
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 65536, 'driver': 'parallels', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}, 'size': 33554432}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-image: TEST_DIR/t.IMGFMT
+image: TEST_IMG
file format: IMGFMT
virtual size: 32M (33554432 bytes)
=== Invalid BlockdevRef ===
-Testing:
-QMP_VERSION
-{"return": {}}
-{"error": {"class": "GenericError", "desc": "Cannot find device=this doesn't exist nor node_name=this doesn't exist"}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
-
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': "this doesn't exist", 'size': 33554432}}}
+{u'return': {}}
+Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
=== Zero size ===
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 0}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-image: TEST_DIR/t.IMGFMT
+image: TEST_IMG
file format: IMGFMT
virtual size: 0 (0 bytes)
=== Maximum size ===
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 4503599627369984}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-image: TEST_DIR/t.IMGFMT
+image: TEST_IMG
file format: IMGFMT
virtual size: 4096T (4503599627369984 bytes)
=== Invalid sizes ===
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
-QMP_VERSION
-{"return": {}}
-{"error": {"class": "GenericError", "desc": "Image size must be a multiple of 512 bytes"}}
-{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}}
-{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}}
-{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}}
-{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
-
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 1234}}}
+{u'return': {}}
+Job failed: Image size must be a multiple of 512 bytes
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 18446744073709551104L}}}
+{u'return': {}}
+Job failed: Image size is too large for this cluster size
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 9223372036854775808L}}}
+{u'return': {}}
+Job failed: Image size is too large for this cluster size
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 9223372036854775296}}}
+{u'return': {}}
+Job failed: Image size is too large for this cluster size
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 4503599627370497}}}
+{u'return': {}}
+Job failed: Image size is too large for this cluster size
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
=== Invalid cluster size ===
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
-QMP_VERSION
-{"return": {}}
-{"error": {"class": "GenericError", "desc": "Cluster size must be a multiple of 512 bytes"}}
-{"error": {"class": "GenericError", "desc": "Cluster size must be a multiple of 512 bytes"}}
-{"error": {"class": "GenericError", "desc": "Cluster size is too large"}}
-{"error": {"class": "GenericError", "desc": "Cluster size is too large"}}
-{"error": {"class": "GenericError", "desc": "Cluster size is too large"}}
-{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}}
-{"error": {"class": "GenericError", "desc": "Image size is too large for this cluster size"}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
-
-*** done
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 1234, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}}
+{u'return': {}}
+Job failed: Cluster size must be a multiple of 512 bytes
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 128, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}}
+{u'return': {}}
+Job failed: Cluster size must be a multiple of 512 bytes
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 4294967296, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}}
+{u'return': {}}
+Job failed: Cluster size is too large
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 9223372036854775808L, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}}
+{u'return': {}}
+Job failed: Cluster size is too large
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 18446744073709551104L, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}}
+{u'return': {}}
+Job failed: Cluster size is too large
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 0, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}}
+{u'return': {}}
+Job failed: Image size is too large for this cluster size
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 512, 'driver': 'parallels', 'file': 'node0', 'size': 281474976710656}}}
+{u'return': {}}
+Job failed: Image size is too large for this cluster size
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
diff --git a/tests/qemu-iotests/213 b/tests/qemu-iotests/213
index 3a00a0f6d6..4054439e3c 100755
--- a/tests/qemu-iotests/213
+++ b/tests/qemu-iotests/213
@@ -1,9 +1,11 @@
-#!/bin/bash
+#!/usr/bin/env python
#
# Test vhdx and file image creation
#
# Copyright (C) 2018 Red Hat, Inc.
#
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
@@ -18,332 +20,190 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-# creator
-owner=kwolf@redhat.com
-
-seq=`basename $0`
-echo "QA output created by $seq"
-
-here=`pwd`
-status=1 # failure is the default!
-
-# get standard environment, filters and checks
-. ./common.rc
-. ./common.filter
-
-_supported_fmt vhdx
-_supported_proto file
-_supported_os Linux
-
-function do_run_qemu()
-{
- echo Testing: "$@"
- $QEMU -nographic -qmp stdio -serial none "$@"
- echo
-}
-
-function run_qemu()
-{
- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
- | _filter_qemu | _filter_imgfmt \
- | _filter_actual_image_size
-}
-
-echo
-echo "=== Successful image creation (defaults) ==="
-echo
-
-size=$((128 * 1024 * 1024))
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "file",
- "filename": "$TEST_IMG",
- "size": 0
- }
-}
-{ "execute": "blockdev-add",
- "arguments": {
- "driver": "file",
- "node-name": "imgfile",
- "filename": "$TEST_IMG"
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "imgfile",
- "size": $size
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info --format-specific | _filter_img_info --format-specific
-
-echo
-echo "=== Successful image creation (explicit defaults) ==="
-echo
-
-# Choose a different size to show that we got a new image
-size=$((64 * 1024 * 1024))
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "file",
- "filename": "$TEST_IMG",
- "size": 0
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": {
- "driver": "file",
- "filename": "$TEST_IMG"
- },
- "size": $size,
- "log-size": 1048576,
- "block-size": 8388608,
- "subformat": "dynamic",
- "block-state-zero": true
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info --format-specific | _filter_img_info --format-specific
-
-echo
-echo "=== Successful image creation (with non-default options) ==="
-echo
-
-# Choose a different size to show that we got a new image
-size=$((32 * 1024 * 1024))
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "file",
- "filename": "$TEST_IMG",
- "size": 0
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": {
- "driver": "file",
- "filename": "$TEST_IMG"
- },
- "size": $size,
- "log-size": 8388608,
- "block-size": 268435456,
- "subformat": "fixed",
- "block-state-zero": false
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info --format-specific | _filter_img_info --format-specific
-
-echo
-echo "=== Invalid BlockdevRef ==="
-echo
-
-run_qemu <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "this doesn't exist",
- "size": $size
- }
-}
-{ "execute": "quit" }
-EOF
-
-echo
-echo "=== Zero size ==="
-echo
-
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 0
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info | _filter_img_info
-
-echo
-echo "=== Maximum size ==="
-echo
-
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 70368744177664
- }
-}
-{ "execute": "quit" }
-EOF
-
-_img_info | _filter_img_info
-
-echo
-echo "=== Invalid sizes ==="
-echo
-
-# TODO Negative image sizes aren't handled correctly, but this is a problem
-# with QAPI's implementation of the 'size' type and affects other commands as
-# well. Once this is fixed, we may want to add a test case here.
-
-# 1. 2^64 - 512
-# 2. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
-# 3. 2^63 - 512 (generally valid, but with the image header the file will
-# exceed 63 bits)
-# 4. 2^46 + 1 (one byte more than maximum image size)
-
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 18446744073709551104
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 9223372036854775808
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 9223372036854775296
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 70368744177665
- }
-}
-{ "execute": "quit" }
-EOF
-
-echo
-echo "=== Invalid block size ==="
-echo
-
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 67108864,
- "block-size": 1234567
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 67108864,
- "block-size": 128
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 67108864,
- "block-size": 3145728
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 67108864,
- "block-size": 536870912
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 67108864,
- "block-size": 0
- }
-}
-{ "execute": "quit" }
-EOF
-
-echo
-echo "=== Invalid log size ==="
-echo
-
-run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
-{ "execute": "qmp_capabilities" }
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 67108864,
- "log-size": 1234567
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 67108864,
- "log-size": 128
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 67108864,
- "log-size": 4294967296
- }
-}
-{ "execute": "x-blockdev-create",
- "arguments": {
- "driver": "$IMGFMT",
- "file": "node0",
- "size": 67108864,
- "log-size": 0
- }
-}
-{ "execute": "quit" }
-EOF
-
-
-# success, all done
-echo "*** done"
-rm -f $seq.full
-status=0
+import iotests
+from iotests import imgfmt
+
+iotests.verify_image_format(supported_fmts=['vhdx'])
+iotests.verify_protocol(supported=['file'])
+
+def blockdev_create(vm, options):
+ result = vm.qmp_log('blockdev-create', job_id='job0', options=options)
+
+ if 'return' in result:
+ assert result['return'] == {}
+ vm.run_job('job0')
+ iotests.log("")
+
+with iotests.FilePath('t.vhdx') as disk_path, \
+ iotests.VM() as vm:
+
+ #
+ # Successful image creation (defaults)
+ #
+ iotests.log("=== Successful image creation (defaults) ===")
+ iotests.log("")
+
+ size = 128 * 1024 * 1024
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': 'file',
+ 'filename': disk_path,
+ 'size': 0 })
+
+ vm.qmp_log('blockdev-add', driver='file', filename=disk_path,
+ node_name='imgfile')
+
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'imgfile',
+ 'size': size })
+ vm.shutdown()
+
+ iotests.img_info_log(disk_path)
+
+ #
+ # Successful image creation (explicit defaults)
+ #
+ iotests.log("=== Successful image creation (explicit defaults) ===")
+ iotests.log("")
+
+ # Choose a different size to show that we got a new image
+ size = 64 * 1024 * 1024
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': 'file',
+ 'filename': disk_path,
+ 'size': 0 })
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': {
+ 'driver': 'file',
+ 'filename': disk_path,
+ },
+ 'size': size,
+ 'log-size': 1048576,
+ 'block-size': 8388608,
+ 'subformat': 'dynamic',
+ 'block-state-zero': True })
+ vm.shutdown()
+
+ iotests.img_info_log(disk_path)
+
+ #
+ # Successful image creation (with non-default options)
+ #
+ iotests.log("=== Successful image creation (with non-default options) ===")
+ iotests.log("")
+
+ # Choose a different size to show that we got a new image
+ size = 32 * 1024 * 1024
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': 'file',
+ 'filename': disk_path,
+ 'size': 0 })
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': {
+ 'driver': 'file',
+ 'filename': disk_path,
+ },
+ 'size': size,
+ 'log-size': 8388608,
+ 'block-size': 268435456,
+ 'subformat': 'fixed',
+ 'block-state-zero': False })
+ vm.shutdown()
+
+ iotests.img_info_log(disk_path)
+
+ #
+ # Invalid BlockdevRef
+ #
+ iotests.log("=== Invalid BlockdevRef ===")
+ iotests.log("")
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': "this doesn't exist",
+ 'size': size })
+ vm.shutdown()
+
+ #
+ # Zero size
+ #
+ iotests.log("=== Zero size ===")
+ iotests.log("")
+
+ vm.add_blockdev('driver=file,filename=%s,node-name=node0' % (disk_path))
+ vm.launch()
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'node0',
+ 'size': 0 })
+ vm.shutdown()
+
+ iotests.img_info_log(disk_path)
+
+ #
+ # Maximum size
+ #
+ iotests.log("=== Maximum size ===")
+ iotests.log("")
+
+ vm.launch()
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'node0',
+ 'size': 70368744177664 })
+ vm.shutdown()
+
+ iotests.img_info_log(disk_path)
+
+ #
+ # Invalid sizes
+ #
+
+ # TODO Negative image sizes aren't handled correctly, but this is a problem
+ # with QAPI's implementation of the 'size' type and affects other commands
+ # as well. Once this is fixed, we may want to add a test case here.
+
+ # 1. 2^64 - 512
+ # 2. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
+ # 3. 2^63 - 512 (generally valid, but with the image header the file will
+ # exceed 63 bits)
+ # 4. 2^46 + 1 (one byte more than maximum image size)
+
+ iotests.log("=== Invalid sizes ===")
+ iotests.log("")
+
+ vm.launch()
+ for size in [ 18446744073709551104, 9223372036854775808,
+ 9223372036854775296, 70368744177665 ]:
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'node0',
+ 'size': size })
+ vm.shutdown()
+
+ #
+ # Invalid block size
+ #
+ iotests.log("=== Invalid block size ===")
+ iotests.log("")
+
+ vm.launch()
+ for bsize in [ 1234567, 128, 3145728, 536870912, 0 ]:
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'node0',
+ 'size': 67108864,
+ 'block-size': bsize })
+ vm.shutdown()
+
+ #
+ # Invalid log size
+ #
+ iotests.log("=== Invalid log size ===")
+ iotests.log("")
+
+ vm.launch()
+ for lsize in [ 1234567, 128, 4294967296, 0 ]:
+ blockdev_create(vm, { 'driver': imgfmt,
+ 'file': 'node0',
+ 'size': 67108864,
+ 'log-size': lsize })
+ vm.shutdown()
diff --git a/tests/qemu-iotests/213.out b/tests/qemu-iotests/213.out
index 8e8fc29cbc..e1dcd47201 100644
--- a/tests/qemu-iotests/213.out
+++ b/tests/qemu-iotests/213.out
@@ -1,121 +1,169 @@
-QA output created by 213
-
=== Successful image creation (defaults) ===
-Testing:
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-add', 'arguments': {'node_name': 'imgfile', 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}}
+{u'return': {}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'imgfile', 'size': 134217728}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-image: TEST_DIR/t.IMGFMT
+image: TEST_IMG
file format: IMGFMT
virtual size: 128M (134217728 bytes)
+cluster_size: 8388608
=== Successful image creation (explicit defaults) ===
-Testing:
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-image: TEST_DIR/t.IMGFMT
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'block-size': 8388608, 'driver': 'vhdx', 'subformat': 'dynamic', 'log-size': 1048576, 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}, 'block-state-zero': True, 'size': 67108864}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+image: TEST_IMG
file format: IMGFMT
virtual size: 64M (67108864 bytes)
+cluster_size: 8388608
=== Successful image creation (with non-default options) ===
-Testing:
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'block-size': 268435456, 'driver': 'vhdx', 'subformat': 'fixed', 'log-size': 8388608, 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}, 'block-state-zero': False, 'size': 33554432}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-image: TEST_DIR/t.IMGFMT
+image: TEST_IMG
file format: IMGFMT
virtual size: 32M (33554432 bytes)
+cluster_size: 268435456
=== Invalid BlockdevRef ===
-Testing:
-QMP_VERSION
-{"return": {}}
-{"error": {"class": "GenericError", "desc": "Cannot find device=this doesn't exist nor node_name=this doesn't exist"}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
-
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': "this doesn't exist", 'size': 33554432}}}
+{u'return': {}}
+Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
=== Zero size ===
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 0}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-image: TEST_DIR/t.IMGFMT
+image: TEST_IMG
file format: IMGFMT
virtual size: 0 (0 bytes)
+cluster_size: 8388608
=== Maximum size ===
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
-QMP_VERSION
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 70368744177664}}}
+{u'return': {}}
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
-image: TEST_DIR/t.IMGFMT
+image: TEST_IMG
file format: IMGFMT
virtual size: 64T (70368744177664 bytes)
+cluster_size: 67108864
=== Invalid sizes ===
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
-QMP_VERSION
-{"return": {}}
-{"error": {"class": "GenericError", "desc": "Image size too large; max of 64TB"}}
-{"error": {"class": "GenericError", "desc": "Image size too large; max of 64TB"}}
-{"error": {"class": "GenericError", "desc": "Image size too large; max of 64TB"}}
-{"error": {"class": "GenericError", "desc": "Image size too large; max of 64TB"}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
-
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 18446744073709551104L}}}
+{u'return': {}}
+Job failed: Image size too large; max of 64TB
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 9223372036854775808L}}}
+{u'return': {}}
+Job failed: Image size too large; max of 64TB
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 9223372036854775296}}}
+{u'return': {}}
+Job failed: Image size too large; max of 64TB
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 70368744177665}}}
+{u'return': {}}
+Job failed: Image size too large; max of 64TB
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
=== Invalid block size ===
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
-QMP_VERSION
-{"return": {}}
-{"error": {"class": "GenericError", "desc": "Block size must be a multiple of 1 MB"}}
-{"error": {"class": "GenericError", "desc": "Block size must be a multiple of 1 MB"}}
-{"error": {"class": "GenericError", "desc": "Block size must be a power of two"}}
-{"error": {"class": "GenericError", "desc": "Block size must not exceed 268435456"}}
-{"error": {"class": "GenericError", "desc": "Block size must be a multiple of 1 MB"}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
-
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 1234567, 'file': 'node0', 'size': 67108864}}}
+{u'return': {}}
+Job failed: Block size must be a multiple of 1 MB
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 128, 'file': 'node0', 'size': 67108864}}}
+{u'return': {}}
+Job failed: Block size must be a multiple of 1 MB
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 3145728, 'file': 'node0', 'size': 67108864}}}
+{u'return': {}}
+Job failed: Block size must be a power of two
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 536870912, 'file': 'node0', 'size': 67108864}}}
+{u'return': {}}
+Job failed: Block size must not exceed 268435456
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 0, 'file': 'node0', 'size': 67108864}}}
+{u'return': {}}
+Job failed: Block size must be a multiple of 1 MB
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
=== Invalid log size ===
-Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
-QMP_VERSION
-{"return": {}}
-{"error": {"class": "GenericError", "desc": "Log size must be a multiple of 1 MB"}}
-{"error": {"class": "GenericError", "desc": "Log size must be a multiple of 1 MB"}}
-{"error": {"class": "GenericError", "desc": "Log size must be smaller than 4 GB"}}
-{"error": {"class": "GenericError", "desc": "Log size must be a multiple of 1 MB"}}
-{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
-
-*** done
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 1234567, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}}
+{u'return': {}}
+Job failed: Log size must be a multiple of 1 MB
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 128, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}}
+{u'return': {}}
+Job failed: Log size must be a multiple of 1 MB
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 4294967296, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}}
+{u'return': {}}
+Job failed: Log size must be smaller than 4 GB
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
+{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 0, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}}
+{u'return': {}}
+Job failed: Log size must be a multiple of 1 MB
+{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}}
+{u'return': {}}
+
diff --git a/tests/qemu-iotests/219 b/tests/qemu-iotests/219
new file mode 100755
index 0000000000..898a26eef0
--- /dev/null
+++ b/tests/qemu-iotests/219
@@ -0,0 +1,209 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2018 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
+#
+# Check using the job-* QMP commands with block jobs
+
+import iotests
+
+iotests.verify_image_format(supported_fmts=['qcow2'])
+
+def pause_wait(vm, job_id):
+ with iotests.Timeout(3, "Timeout waiting for job to pause"):
+ while True:
+ result = vm.qmp('query-jobs')
+ for job in result['return']:
+ if job['id'] == job_id and job['status'] in ['paused', 'standby']:
+ return job
+
+# Test that block-job-pause/resume and job-pause/resume can be mixed
+def test_pause_resume(vm):
+ for pause_cmd, pause_arg in [('block-job-pause', 'device'),
+ ('job-pause', 'id')]:
+ for resume_cmd, resume_arg in [('block-job-resume', 'device'),
+ ('job-resume', 'id')]:
+ iotests.log('=== Testing %s/%s ===' % (pause_cmd, resume_cmd))
+
+ iotests.log(vm.qmp(pause_cmd, **{pause_arg: 'job0'}))
+ pause_wait(vm, 'job0')
+ iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
+ iotests.log(vm.qmp('query-jobs'))
+
+ iotests.log(vm.qmp(resume_cmd, **{resume_arg: 'job0'}))
+ iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
+ iotests.log(vm.qmp('query-jobs'))
+
+def test_job_lifecycle(vm, job, job_args, has_ready=False):
+ iotests.log('')
+ iotests.log('')
+ iotests.log('Starting block job: %s (auto-finalize: %s; auto-dismiss: %s)' %
+ (job,
+ job_args.get('auto-finalize', True),
+ job_args.get('auto-dismiss', True)))
+ iotests.log(vm.qmp(job, job_id='job0', **job_args))
+
+ # Depending on the storage, the first request may or may not have completed
+ # yet, so filter out the progress. Later query-job calls don't need the
+ # filtering because the progress is made deterministic by the block job
+ # speed
+ result = vm.qmp('query-jobs')
+ for j in result['return']:
+ del j['current-progress']
+ iotests.log(result)
+
+ # undefined -> created -> running
+ iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
+ iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
+
+ # RUNNING state:
+ # pause/resume should work, complete/finalize/dismiss should error out
+ iotests.log('')
+ iotests.log('Pause/resume in RUNNING')
+ test_pause_resume(vm)
+
+ iotests.log(vm.qmp('job-complete', id='job0'))
+ iotests.log(vm.qmp('job-finalize', id='job0'))
+ iotests.log(vm.qmp('job-dismiss', id='job0'))
+
+ iotests.log(vm.qmp('block-job-complete', device='job0'))
+ iotests.log(vm.qmp('block-job-finalize', id='job0'))
+ iotests.log(vm.qmp('block-job-dismiss', id='job0'))
+
+ # Let the job complete (or transition to READY if it supports that)
+ iotests.log(vm.qmp('block-job-set-speed', device='job0', speed=0))
+ if has_ready:
+ iotests.log('')
+ iotests.log('Waiting for READY state...')
+ vm.event_wait('BLOCK_JOB_READY')
+ iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
+ iotests.log(vm.qmp('query-jobs'))
+
+ # READY state:
+ # pause/resume/complete should work, finalize/dismiss should error out
+ iotests.log('')
+ iotests.log('Pause/resume in READY')
+ test_pause_resume(vm)
+
+ iotests.log(vm.qmp('job-finalize', id='job0'))
+ iotests.log(vm.qmp('job-dismiss', id='job0'))
+
+ iotests.log(vm.qmp('block-job-finalize', id='job0'))
+ iotests.log(vm.qmp('block-job-dismiss', id='job0'))
+
+ # Transition to WAITING
+ iotests.log(vm.qmp('job-complete', id='job0'))
+
+ # Move to WAITING and PENDING state
+ iotests.log('')
+ iotests.log('Waiting for PENDING state...')
+ iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
+ iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
+
+ if not job_args.get('auto-finalize', True):
+ # PENDING state:
+ # finalize should work, pause/complete/dismiss should error out
+ iotests.log(vm.qmp('query-jobs'))
+
+ iotests.log(vm.qmp('job-pause', id='job0'))
+ iotests.log(vm.qmp('job-complete', id='job0'))
+ iotests.log(vm.qmp('job-dismiss', id='job0'))
+
+ iotests.log(vm.qmp('block-job-pause', device='job0'))
+ iotests.log(vm.qmp('block-job-complete', device='job0'))
+ iotests.log(vm.qmp('block-job-dismiss', id='job0'))
+
+ # Transition to CONCLUDED
+ iotests.log(vm.qmp('job-finalize', id='job0'))
+
+
+ # Move to CONCLUDED state
+ iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
+
+ if not job_args.get('auto-dismiss', True):
+ # CONCLUDED state:
+ # dismiss should work, pause/complete/finalize should error out
+ iotests.log(vm.qmp('query-jobs'))
+
+ iotests.log(vm.qmp('job-pause', id='job0'))
+ iotests.log(vm.qmp('job-complete', id='job0'))
+ iotests.log(vm.qmp('job-finalize', id='job0'))
+
+ iotests.log(vm.qmp('block-job-pause', device='job0'))
+ iotests.log(vm.qmp('block-job-complete', device='job0'))
+ iotests.log(vm.qmp('block-job-finalize', id='job0'))
+
+ # Transition to NULL
+ iotests.log(vm.qmp('job-dismiss', id='job0'))
+
+ # Move to NULL state
+ iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
+ iotests.log(vm.qmp('query-jobs'))
+
+
+with iotests.FilePath('disk.img') as disk_path, \
+ iotests.FilePath('copy.img') as copy_path, \
+ iotests.VM() as vm:
+
+ img_size = '4M'
+ iotests.qemu_img_create('-f', iotests.imgfmt, disk_path, img_size)
+ iotests.qemu_io('-c', 'write 0 %s' % (img_size),
+ '-f', iotests.imgfmt, disk_path)
+
+ iotests.log('Launching VM...')
+ vm.add_blockdev(vm.qmp_to_opts({
+ 'driver': iotests.imgfmt,
+ 'node-name': 'drive0-node',
+ 'file': {
+ 'driver': 'file',
+ 'filename': disk_path,
+ },
+ }))
+ vm.launch()
+
+ # In order to keep things deterministic (especially progress in query-job,
+ # but related to this also automatic state transitions like job
+ # completion), but still get pause points often enough to avoid making this
+ # test very slow, it's important to have the right ratio between speed and
+ # buf_size.
+ #
+ # For backup, buf_size is hard-coded to the source image cluster size (64k),
+ # so we'll pick the same for mirror. The slice time, i.e. the granularity
+ # of the rate limiting is 100ms. With a speed of 256k per second, we can
+ # get four pause points per second. This gives us 250ms per iteration,
+ # which should be enough to stay deterministic.
+
+ test_job_lifecycle(vm, 'drive-mirror', has_ready=True, job_args={
+ 'device': 'drive0-node',
+ 'target': copy_path,
+ 'sync': 'full',
+ 'speed': 262144,
+ 'buf_size': 65536,
+ })
+
+ for auto_finalize in [True, False]:
+ for auto_dismiss in [True, False]:
+ test_job_lifecycle(vm, 'drive-backup', job_args={
+ 'device': 'drive0-node',
+ 'target': copy_path,
+ 'sync': 'full',
+ 'speed': 262144,
+ 'auto-finalize': auto_finalize,
+ 'auto-dismiss': auto_dismiss,
+ })
+
+ vm.shutdown()
diff --git a/tests/qemu-iotests/219.out b/tests/qemu-iotests/219.out
new file mode 100644
index 0000000000..346801b655
--- /dev/null
+++ b/tests/qemu-iotests/219.out
@@ -0,0 +1,327 @@
+Launching VM...
+
+
+Starting block job: drive-mirror (auto-finalize: True; auto-dismiss: True)
+{u'return': {}}
+{u'return': [{u'status': u'running', u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'created', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+
+Pause/resume in RUNNING
+=== Testing block-job-pause/block-job-resume ===
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'paused', u'current-progress': 65536, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'running', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]}
+=== Testing block-job-pause/job-resume ===
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'paused', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'running', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]}
+=== Testing job-pause/block-job-resume ===
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'paused', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'running', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]}
+=== Testing job-pause/job-resume ===
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'paused', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'running', u'current-progress': 327680, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}}
+{u'return': {}}
+
+Waiting for READY state...
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'ready', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'ready', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]}
+
+Pause/resume in READY
+=== Testing block-job-pause/block-job-resume ===
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'standby', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'standby', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'ready', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'ready', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]}
+=== Testing block-job-pause/job-resume ===
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'standby', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'standby', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'ready', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'ready', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]}
+=== Testing job-pause/block-job-resume ===
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'standby', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'standby', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'ready', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'ready', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]}
+=== Testing job-pause/job-resume ===
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'standby', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'standby', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'ready', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'ready', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'ready' cannot accept command verb 'finalize'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'ready' cannot accept command verb 'dismiss'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'ready' cannot accept command verb 'finalize'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'ready' cannot accept command verb 'dismiss'"}}
+{u'return': {}}
+
+Waiting for PENDING state...
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'waiting', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'pending', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'concluded', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'null', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': []}
+
+
+Starting block job: drive-backup (auto-finalize: True; auto-dismiss: True)
+{u'return': {}}
+{u'return': [{u'status': u'running', u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'created', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+
+Pause/resume in RUNNING
+=== Testing block-job-pause/block-job-resume ===
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'paused', u'current-progress': 65536, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'running', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+=== Testing block-job-pause/job-resume ===
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'paused', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'running', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+=== Testing job-pause/block-job-resume ===
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'paused', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'running', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+=== Testing job-pause/job-resume ===
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'paused', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'running', u'current-progress': 327680, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}}
+{u'return': {}}
+
+Waiting for PENDING state...
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'waiting', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'pending', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'concluded', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'null', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': []}
+
+
+Starting block job: drive-backup (auto-finalize: True; auto-dismiss: False)
+{u'return': {}}
+{u'return': [{u'status': u'running', u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'created', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+
+Pause/resume in RUNNING
+=== Testing block-job-pause/block-job-resume ===
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'paused', u'current-progress': 65536, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'running', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+=== Testing block-job-pause/job-resume ===
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'paused', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'running', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+=== Testing job-pause/block-job-resume ===
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'paused', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'running', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+=== Testing job-pause/job-resume ===
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'paused', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'running', u'current-progress': 327680, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}}
+{u'return': {}}
+
+Waiting for PENDING state...
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'waiting', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'pending', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'concluded', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'concluded', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'pause'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'complete'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'finalize'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'pause'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'complete'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'finalize'"}}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'null', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': []}
+
+
+Starting block job: drive-backup (auto-finalize: False; auto-dismiss: True)
+{u'return': {}}
+{u'return': [{u'status': u'running', u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'created', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+
+Pause/resume in RUNNING
+=== Testing block-job-pause/block-job-resume ===
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'paused', u'current-progress': 65536, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'running', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+=== Testing block-job-pause/job-resume ===
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'paused', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'running', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+=== Testing job-pause/block-job-resume ===
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'paused', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'running', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+=== Testing job-pause/job-resume ===
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'paused', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'running', u'current-progress': 327680, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}}
+{u'return': {}}
+
+Waiting for PENDING state...
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'waiting', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'pending', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'pending', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'pause'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'complete'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'dismiss'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'pause'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'complete'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'dismiss'"}}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'concluded', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'null', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': []}
+
+
+Starting block job: drive-backup (auto-finalize: False; auto-dismiss: False)
+{u'return': {}}
+{u'return': [{u'status': u'running', u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'created', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+
+Pause/resume in RUNNING
+=== Testing block-job-pause/block-job-resume ===
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'paused', u'current-progress': 65536, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'running', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+=== Testing block-job-pause/job-resume ===
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'paused', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'running', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+=== Testing job-pause/block-job-resume ===
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'paused', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'running', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+=== Testing job-pause/job-resume ===
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'paused', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'running', u'current-progress': 327680, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}}
+{u'return': {}}
+
+Waiting for PENDING state...
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'waiting', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'pending', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'pending', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'pause'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'complete'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'dismiss'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'pause'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'complete'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'dismiss'"}}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'concluded', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': [{u'status': u'concluded', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'pause'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'complete'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'finalize'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'pause'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'complete'"}}
+{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'finalize'"}}
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'null', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'}
+{u'return': []}
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
index c5f4bcf578..f08ee55046 100644
--- a/tests/qemu-iotests/common.filter
+++ b/tests/qemu-iotests/common.filter
@@ -119,7 +119,8 @@ _filter_actual_image_size()
# replace driver-specific options in the "Formatting..." line
_filter_img_create()
{
- sed -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
+ sed -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \
+ -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
-e "s#$TEST_DIR#TEST_DIR#g" \
-e "s#$IMGFMT#IMGFMT#g" \
-e 's#nbd:127.0.0.1:10810#TEST_DIR/t.IMGFMT#g' \
@@ -154,7 +155,8 @@ _filter_img_info()
discard=0
regex_json_spec_start='^ *"format-specific": \{'
- sed -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
+ sed -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \
+ -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
-e "s#$TEST_DIR#TEST_DIR#g" \
-e "s#$IMGFMT#IMGFMT#g" \
-e 's#nbd://127.0.0.1:10810$#TEST_DIR/t.IMGFMT#g' \
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
index 9a65a11026..d054cb97fc 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -147,8 +147,9 @@ else
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
TEST_IMG="ssh://127.0.0.1$TEST_IMG_FILE"
elif [ "$IMGPROTO" = "nfs" ]; then
- TEST_DIR="nfs://127.0.0.1/$TEST_DIR"
- TEST_IMG=$TEST_DIR/t.$IMGFMT
+ TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
+ REMOTE_TEST_DIR="nfs://127.0.0.1$TEST_DIR"
+ TEST_IMG="nfs://127.0.0.1$TEST_IMG_FILE"
elif [ "$IMGPROTO" = "vxhs" ]; then
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
TEST_IMG="vxhs://127.0.0.1:9999/t.$IMGFMT"
@@ -173,6 +174,10 @@ if [ ! -d "$TEST_DIR" ]; then
exit 1
fi
+if [ -z "$REMOTE_TEST_DIR" ]; then
+ REMOTE_TEST_DIR="$TEST_DIR"
+fi
+
if [ ! -d "$SAMPLE_IMG_DIR" ]; then
echo "common.config: Error: \$SAMPLE_IMG_DIR ($SAMPLE_IMG_DIR) is not a directory"
exit 1
@@ -333,7 +338,8 @@ _img_info()
discard=0
regex_json_spec_start='^ *"format-specific": \{'
$QEMU_IMG info $QEMU_IMG_EXTRA_ARGS "$@" "$TEST_IMG" 2>&1 | \
- sed -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
+ sed -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \
+ -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
-e "s#$TEST_DIR#TEST_DIR#g" \
-e "s#$IMGFMT#IMGFMT#g" \
-e "/^disk size:/ D" \
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index cc8cd8cc8e..93f93d71ba 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -97,7 +97,7 @@
088 rw auto quick
089 rw auto quick
090 rw auto quick
-091 rw auto
+091 rw auto migration
092 rw auto quick
093 auto
094 rw auto quick
@@ -169,7 +169,7 @@
162 auto quick
163 rw auto
165 rw auto quick
-169 rw auto quick
+169 rw auto quick migration
170 rw auto quick
171 rw auto quick
172 auto
@@ -194,14 +194,14 @@
192 rw auto quick
194 rw auto migration quick
195 rw auto quick
-196 rw auto quick
+196 rw auto quick migration
197 rw auto quick
198 rw auto
-199 rw auto
+199 rw auto migration
200 rw auto
201 rw auto migration
202 rw auto quick
-203 rw auto
+203 rw auto migration
204 rw auto quick
205 rw auto quick
206 rw auto
@@ -216,3 +216,4 @@
215 rw auto quick
216 rw auto quick
218 rw auto quick
+219 rw auto
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index b25d48a91b..fdbdd8b300 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -109,6 +109,20 @@ def qemu_img_pipe(*args):
sys.stderr.write('qemu-img received signal %i: %s\n' % (-exitcode, ' '.join(qemu_img_args + list(args))))
return subp.communicate()[0]
+def img_info_log(filename, filter_path=None, imgopts=False, extra_args=[]):
+ args = [ 'info' ]
+ if imgopts:
+ args.append('--image-opts')
+ else:
+ args += [ '-f', imgfmt ]
+ args += extra_args
+ args.append(filename)
+
+ output = qemu_img_pipe(*args)
+ if not filter_path:
+ filter_path = filename
+ log(filter_img_info(output, filter_path))
+
def qemu_io(*args):
'''Run qemu-io and return the stdout data'''
args = qemu_io_args + list(args)
@@ -206,6 +220,22 @@ def filter_qmp_event(event):
event['timestamp']['microseconds'] = 'USECS'
return event
+def filter_testfiles(msg):
+ prefix = os.path.join(test_dir, "%s-" % (os.getpid()))
+ return msg.replace(prefix, 'TEST_DIR/PID-')
+
+def filter_img_info(output, filename):
+ lines = []
+ for line in output.split('\n'):
+ if 'disk size' in line or 'actual-size' in line:
+ continue
+ line = line.replace(filename, 'TEST_IMG') \
+ .replace(imgfmt, 'IMGFMT')
+ line = re.sub('iters: [0-9]+', 'iters: XXX', line)
+ line = re.sub('uuid: [-a-f0-9]+', 'uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', line)
+ lines.append(line)
+ return '\n'.join(lines)
+
def log(msg, filters=[]):
for flt in filters:
msg = flt(msg)
@@ -281,6 +311,13 @@ def file_path(*names):
return paths[0] if len(paths) == 1 else paths
+def remote_filename(path):
+ if imgproto == 'file':
+ return path
+ elif imgproto == 'ssh':
+ return "ssh://127.0.0.1%s" % (path)
+ else:
+ raise Exception("Protocol %s not supported" % (imgproto))
class VM(qtest.QEMUQtestMachine):
'''A QEMU VM'''
@@ -363,6 +400,58 @@ class VM(qtest.QEMUQtestMachine):
return self.qmp('human-monitor-command',
command_line='qemu-io %s "%s"' % (drive, cmd))
+ def flatten_qmp_object(self, obj, output=None, basestr=''):
+ if output is None:
+ output = dict()
+ if isinstance(obj, list):
+ for i in range(len(obj)):
+ self.flatten_qmp_object(obj[i], output, basestr + str(i) + '.')
+ elif isinstance(obj, dict):
+ for key in obj:
+ self.flatten_qmp_object(obj[key], output, basestr + key + '.')
+ else:
+ output[basestr[:-1]] = obj # Strip trailing '.'
+ return output
+
+ def qmp_to_opts(self, obj):
+ obj = self.flatten_qmp_object(obj)
+ output_list = list()
+ for key in obj:
+ output_list += [key + '=' + obj[key]]
+ return ','.join(output_list)
+
+ def get_qmp_events_filtered(self, wait=True):
+ result = []
+ for ev in self.get_qmp_events(wait=wait):
+ result.append(filter_qmp_event(ev))
+ return result
+
+ def qmp_log(self, cmd, filters=[filter_testfiles], **kwargs):
+ logmsg = "{'execute': '%s', 'arguments': %s}" % (cmd, kwargs)
+ log(logmsg, filters)
+ result = self.qmp(cmd, **kwargs)
+ log(str(result), filters)
+ return result
+
+ def run_job(self, job, auto_finalize=True, auto_dismiss=False):
+ while True:
+ for ev in self.get_qmp_events_filtered(wait=True):
+ if ev['event'] == 'JOB_STATUS_CHANGE':
+ status = ev['data']['status']
+ if status == 'aborting':
+ result = self.qmp('query-jobs')
+ for j in result['return']:
+ if j['id'] == job:
+ log('Job failed: %s' % (j['error']))
+ elif status == 'pending' and not auto_finalize:
+ self.qmp_log('job-finalize', id=job)
+ elif status == 'concluded' and not auto_dismiss:
+ self.qmp_log('job-dismiss', id=job)
+ elif status == 'null':
+ return
+ else:
+ iotests.log(ev)
+
index_re = re.compile(r'([^\[]+)\[([^\]]+)\]')
@@ -390,26 +479,6 @@ class QMPTestCase(unittest.TestCase):
self.fail('invalid index "%s" in path "%s" in "%s"' % (idx, path, str(d)))
return d
- def flatten_qmp_object(self, obj, output=None, basestr=''):
- if output is None:
- output = dict()
- if isinstance(obj, list):
- for i in range(len(obj)):
- self.flatten_qmp_object(obj[i], output, basestr + str(i) + '.')
- elif isinstance(obj, dict):
- for key in obj:
- self.flatten_qmp_object(obj[key], output, basestr + key + '.')
- else:
- output[basestr[:-1]] = obj # Strip trailing '.'
- return output
-
- def qmp_to_opts(self, obj):
- obj = self.flatten_qmp_object(obj)
- output_list = list()
- for key in obj:
- output_list += [key + '=' + obj[key]]
- return ','.join(output_list)
-
def assert_qmp_absent(self, d, path):
try:
result = self.dictpath(d, path)
@@ -444,8 +513,8 @@ class QMPTestCase(unittest.TestCase):
'''Asserts that the given filename is a json: filename and that its
content is equal to the given reference object'''
self.assertEqual(json_filename[:5], 'json:')
- self.assertEqual(self.flatten_qmp_object(json.loads(json_filename[5:])),
- self.flatten_qmp_object(reference))
+ self.assertEqual(self.vm.flatten_qmp_object(json.loads(json_filename[5:])),
+ self.vm.flatten_qmp_object(reference))
def cancel_and_wait(self, drive='drive0', force=False, resume=False):
'''Cancel a block job and wait for it to finish, returning the event'''
@@ -464,6 +533,9 @@ class QMPTestCase(unittest.TestCase):
self.assert_qmp(event, 'data/device', drive)
result = event
cancelled = True
+ elif event['event'] == 'JOB_STATUS_CHANGE':
+ self.assert_qmp(event, 'data/id', drive)
+
self.assert_no_active_block_jobs()
return result
@@ -479,6 +551,8 @@ class QMPTestCase(unittest.TestCase):
self.assert_qmp(event, 'data/offset', event['data']['len'])
self.assert_no_active_block_jobs()
return event
+ elif event['event'] == 'JOB_STATUS_CHANGE':
+ self.assert_qmp(event, 'data/id', drive)
def wait_ready(self, drive='drive0'):
'''Wait until a block job BLOCK_JOB_READY event'''
@@ -542,6 +616,16 @@ def verify_image_format(supported_fmts=[], unsupported_fmts=[]):
if not_sup or (imgfmt in unsupported_fmts):
notrun('not suitable for this image format: %s' % imgfmt)
+def verify_protocol(supported=[], unsupported=[]):
+ assert not (supported and unsupported)
+
+ if 'generic' in supported:
+ return
+
+ not_sup = supported and (imgproto not in supported)
+ if not_sup or (imgproto in unsupported):
+ notrun('not suitable for this protocol: %s' % imgproto)
+
def verify_platform(supported_oses=['linux']):
if True not in [sys.platform.startswith(x) for x in supported_oses]:
notrun('not suitable for this OS: %s' % sys.platform)
diff --git a/tests/qmp-test.c b/tests/qmp-test.c
index 88f867f8c0..a49cbc6fde 100644
--- a/tests/qmp-test.c
+++ b/tests/qmp-test.c
@@ -392,6 +392,45 @@ static void add_query_tests(QmpSchema *schema)
}
}
+static void test_qmp_preconfig(void)
+{
+ QDict *rsp, *ret;
+ QTestState *qs = qtest_startf("%s --preconfig", common_args);
+
+ /* preconfig state */
+ /* enabled commands, no error expected */
+ g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'query-commands' }")));
+
+ /* forbidden commands, expected error */
+ g_assert(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'query-cpus' }")));
+
+ /* check that query-status returns preconfig state */
+ rsp = qtest_qmp(qs, "{ 'execute': 'query-status' }");
+ ret = qdict_get_qdict(rsp, "return");
+ g_assert(ret);
+ g_assert_cmpstr(qdict_get_try_str(ret, "status"), ==, "preconfig");
+ qobject_unref(rsp);
+
+ /* exit preconfig state */
+ g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'exit-preconfig' }")));
+ qtest_qmp_eventwait(qs, "RESUME");
+
+ /* check that query-status returns running state */
+ rsp = qtest_qmp(qs, "{ 'execute': 'query-status' }");
+ ret = qdict_get_qdict(rsp, "return");
+ g_assert(ret);
+ g_assert_cmpstr(qdict_get_try_str(ret, "status"), ==, "running");
+ qobject_unref(rsp);
+
+ /* check that exit-preconfig returns error after exiting preconfig */
+ g_assert(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'exit-preconfig' }")));
+
+ /* enabled commands, no error expected */
+ g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'query-cpus' }")));
+
+ qtest_quit(qs);
+}
+
int main(int argc, char *argv[])
{
QmpSchema schema;
@@ -403,6 +442,7 @@ int main(int argc, char *argv[])
qtest_add_func("qmp/oob", test_qmp_oob);
qmp_schema_init(&schema);
add_query_tests(&schema);
+ qtest_add_func("qmp/preconfig", test_qmp_preconfig);
ret = g_test_run();
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
index 7673de1062..a11c4cfbf2 100644
--- a/tests/test-bdrv-drain.c
+++ b/tests/test-bdrv-drain.c
@@ -496,33 +496,38 @@ typedef struct TestBlockJob {
bool should_complete;
} TestBlockJob;
-static void test_job_completed(BlockJob *job, void *opaque)
+static void test_job_completed(Job *job, void *opaque)
{
- block_job_completed(job, 0);
+ job_completed(job, 0, NULL);
}
static void coroutine_fn test_job_start(void *opaque)
{
TestBlockJob *s = opaque;
- block_job_event_ready(&s->common);
+ job_transition_to_ready(&s->common.job);
while (!s->should_complete) {
- block_job_sleep_ns(&s->common, 100000);
+ job_sleep_ns(&s->common.job, 100000);
}
- block_job_defer_to_main_loop(&s->common, test_job_completed, NULL);
+ job_defer_to_main_loop(&s->common.job, test_job_completed, NULL);
}
-static void test_job_complete(BlockJob *job, Error **errp)
+static void test_job_complete(Job *job, Error **errp)
{
- TestBlockJob *s = container_of(job, TestBlockJob, common);
+ TestBlockJob *s = container_of(job, TestBlockJob, common.job);
s->should_complete = true;
}
BlockJobDriver test_job_driver = {
- .instance_size = sizeof(TestBlockJob),
- .start = test_job_start,
- .complete = test_job_complete,
+ .job_driver = {
+ .instance_size = sizeof(TestBlockJob),
+ .free = block_job_free,
+ .user_resume = block_job_user_resume,
+ .drain = block_job_drain,
+ .start = test_job_start,
+ .complete = test_job_complete,
+ },
};
static void test_blockjob_common(enum drain_type drain_type)
@@ -545,49 +550,49 @@ static void test_blockjob_common(enum drain_type drain_type)
job = block_job_create("job0", &test_job_driver, NULL, src, 0, BLK_PERM_ALL,
0, 0, NULL, NULL, &error_abort);
block_job_add_bdrv(job, "target", target, 0, BLK_PERM_ALL, &error_abort);
- block_job_start(job);
+ job_start(&job->job);
- g_assert_cmpint(job->pause_count, ==, 0);
- g_assert_false(job->paused);
- g_assert_false(job->busy); /* We're in block_job_sleep_ns() */
+ g_assert_cmpint(job->job.pause_count, ==, 0);
+ g_assert_false(job->job.paused);
+ g_assert_false(job->job.busy); /* We're in job_sleep_ns() */
do_drain_begin(drain_type, src);
if (drain_type == BDRV_DRAIN_ALL) {
/* bdrv_drain_all() drains both src and target */
- g_assert_cmpint(job->pause_count, ==, 2);
+ g_assert_cmpint(job->job.pause_count, ==, 2);
} else {
- g_assert_cmpint(job->pause_count, ==, 1);
+ g_assert_cmpint(job->job.pause_count, ==, 1);
}
/* XXX We don't wait until the job is actually paused. Is this okay? */
- /* g_assert_true(job->paused); */
- g_assert_false(job->busy); /* The job is paused */
+ /* g_assert_true(job->job.paused); */
+ g_assert_false(job->job.busy); /* The job is paused */
do_drain_end(drain_type, src);
- g_assert_cmpint(job->pause_count, ==, 0);
- g_assert_false(job->paused);
- g_assert_false(job->busy); /* We're in block_job_sleep_ns() */
+ g_assert_cmpint(job->job.pause_count, ==, 0);
+ g_assert_false(job->job.paused);
+ g_assert_false(job->job.busy); /* We're in job_sleep_ns() */
do_drain_begin(drain_type, target);
if (drain_type == BDRV_DRAIN_ALL) {
/* bdrv_drain_all() drains both src and target */
- g_assert_cmpint(job->pause_count, ==, 2);
+ g_assert_cmpint(job->job.pause_count, ==, 2);
} else {
- g_assert_cmpint(job->pause_count, ==, 1);
+ g_assert_cmpint(job->job.pause_count, ==, 1);
}
/* XXX We don't wait until the job is actually paused. Is this okay? */
- /* g_assert_true(job->paused); */
- g_assert_false(job->busy); /* The job is paused */
+ /* g_assert_true(job->job.paused); */
+ g_assert_false(job->job.busy); /* The job is paused */
do_drain_end(drain_type, target);
- g_assert_cmpint(job->pause_count, ==, 0);
- g_assert_false(job->paused);
- g_assert_false(job->busy); /* We're in block_job_sleep_ns() */
+ g_assert_cmpint(job->job.pause_count, ==, 0);
+ g_assert_false(job->job.paused);
+ g_assert_false(job->job.busy); /* We're in job_sleep_ns() */
- ret = block_job_complete_sync(job, &error_abort);
+ ret = job_complete_sync(&job->job, &error_abort);
g_assert_cmpint(ret, ==, 0);
blk_unref(blk_src);
diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c
index 5789893dda..58d9b87fb2 100644
--- a/tests/test-blockjob-txn.c
+++ b/tests/test-blockjob-txn.c
@@ -24,16 +24,17 @@ typedef struct {
int *result;
} TestBlockJob;
-static void test_block_job_complete(BlockJob *job, void *opaque)
+static void test_block_job_complete(Job *job, void *opaque)
{
- BlockDriverState *bs = blk_bs(job->blk);
+ BlockJob *bjob = container_of(job, BlockJob, job);
+ BlockDriverState *bs = blk_bs(bjob->blk);
int rc = (intptr_t)opaque;
- if (block_job_is_cancelled(job)) {
+ if (job_is_cancelled(job)) {
rc = -ECANCELED;
}
- block_job_completed(job, rc);
+ job_completed(job, rc, NULL);
bdrv_unref(bs);
}
@@ -44,18 +45,18 @@ static void coroutine_fn test_block_job_run(void *opaque)
while (s->iterations--) {
if (s->use_timer) {
- block_job_sleep_ns(job, 0);
+ job_sleep_ns(&job->job, 0);
} else {
- block_job_yield(job);
+ job_yield(&job->job);
}
- if (block_job_is_cancelled(job)) {
+ if (job_is_cancelled(&job->job)) {
break;
}
}
- block_job_defer_to_main_loop(job, test_block_job_complete,
- (void *)(intptr_t)s->rc);
+ job_defer_to_main_loop(&job->job, test_block_job_complete,
+ (void *)(intptr_t)s->rc);
}
typedef struct {
@@ -66,7 +67,7 @@ typedef struct {
static void test_block_job_cb(void *opaque, int ret)
{
TestBlockJobCBData *data = opaque;
- if (!ret && block_job_is_cancelled(&data->job->common)) {
+ if (!ret && job_is_cancelled(&data->job->common.job)) {
ret = -ECANCELED;
}
*data->result = ret;
@@ -74,8 +75,13 @@ static void test_block_job_cb(void *opaque, int ret)
}
static const BlockJobDriver test_block_job_driver = {
- .instance_size = sizeof(TestBlockJob),
- .start = test_block_job_run,
+ .job_driver = {
+ .instance_size = sizeof(TestBlockJob),
+ .free = block_job_free,
+ .user_resume = block_job_user_resume,
+ .drain = block_job_drain,
+ .start = test_block_job_run,
+ },
};
/* Create a block job that completes with a given return code after a given
@@ -87,7 +93,7 @@ static const BlockJobDriver test_block_job_driver = {
*/
static BlockJob *test_block_job_start(unsigned int iterations,
bool use_timer,
- int rc, int *result, BlockJobTxn *txn)
+ int rc, int *result, JobTxn *txn)
{
BlockDriverState *bs;
TestBlockJob *s;
@@ -102,7 +108,7 @@ static BlockJob *test_block_job_start(unsigned int iterations,
snprintf(job_id, sizeof(job_id), "job%u", counter++);
s = block_job_create(job_id, &test_block_job_driver, txn, bs,
- 0, BLK_PERM_ALL, 0, BLOCK_JOB_DEFAULT,
+ 0, BLK_PERM_ALL, 0, JOB_DEFAULT,
test_block_job_cb, data, &error_abort);
s->iterations = iterations;
s->use_timer = use_timer;
@@ -116,15 +122,15 @@ static BlockJob *test_block_job_start(unsigned int iterations,
static void test_single_job(int expected)
{
BlockJob *job;
- BlockJobTxn *txn;
+ JobTxn *txn;
int result = -EINPROGRESS;
- txn = block_job_txn_new();
+ txn = job_txn_new();
job = test_block_job_start(1, true, expected, &result, txn);
- block_job_start(job);
+ job_start(&job->job);
if (expected == -ECANCELED) {
- block_job_cancel(job, false);
+ job_cancel(&job->job, false);
}
while (result == -EINPROGRESS) {
@@ -132,7 +138,7 @@ static void test_single_job(int expected)
}
g_assert_cmpint(result, ==, expected);
- block_job_txn_unref(txn);
+ job_txn_unref(txn);
}
static void test_single_job_success(void)
@@ -154,26 +160,26 @@ static void test_pair_jobs(int expected1, int expected2)
{
BlockJob *job1;
BlockJob *job2;
- BlockJobTxn *txn;
+ JobTxn *txn;
int result1 = -EINPROGRESS;
int result2 = -EINPROGRESS;
- txn = block_job_txn_new();
+ txn = job_txn_new();
job1 = test_block_job_start(1, true, expected1, &result1, txn);
job2 = test_block_job_start(2, true, expected2, &result2, txn);
- block_job_start(job1);
- block_job_start(job2);
+ job_start(&job1->job);
+ job_start(&job2->job);
/* Release our reference now to trigger as many nice
* use-after-free bugs as possible.
*/
- block_job_txn_unref(txn);
+ job_txn_unref(txn);
if (expected1 == -ECANCELED) {
- block_job_cancel(job1, false);
+ job_cancel(&job1->job, false);
}
if (expected2 == -ECANCELED) {
- block_job_cancel(job2, false);
+ job_cancel(&job2->job, false);
}
while (result1 == -EINPROGRESS || result2 == -EINPROGRESS) {
@@ -216,23 +222,23 @@ static void test_pair_jobs_fail_cancel_race(void)
{
BlockJob *job1;
BlockJob *job2;
- BlockJobTxn *txn;
+ JobTxn *txn;
int result1 = -EINPROGRESS;
int result2 = -EINPROGRESS;
- txn = block_job_txn_new();
+ txn = job_txn_new();
job1 = test_block_job_start(1, true, -ECANCELED, &result1, txn);
job2 = test_block_job_start(2, false, 0, &result2, txn);
- block_job_start(job1);
- block_job_start(job2);
+ job_start(&job1->job);
+ job_start(&job2->job);
- block_job_cancel(job1, false);
+ job_cancel(&job1->job, false);
/* Now make job2 finish before the main loop kicks jobs. This simulates
* the race between a pending kick and another job completing.
*/
- block_job_enter(job2);
- block_job_enter(job2);
+ job_enter(&job2->job);
+ job_enter(&job2->job);
while (result1 == -EINPROGRESS || result2 == -EINPROGRESS) {
aio_poll(qemu_get_aio_context(), true);
@@ -241,7 +247,7 @@ static void test_pair_jobs_fail_cancel_race(void)
g_assert_cmpint(result1, ==, -ECANCELED);
g_assert_cmpint(result2, ==, -ECANCELED);
- block_job_txn_unref(txn);
+ job_txn_unref(txn);
}
int main(int argc, char **argv)
diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c
index 8946bfd37b..cb42f06e61 100644
--- a/tests/test-blockjob.c
+++ b/tests/test-blockjob.c
@@ -17,7 +17,12 @@
#include "sysemu/block-backend.h"
static const BlockJobDriver test_block_job_driver = {
- .instance_size = sizeof(BlockJob),
+ .job_driver = {
+ .instance_size = sizeof(BlockJob),
+ .free = block_job_free,
+ .user_resume = block_job_user_resume,
+ .drain = block_job_drain,
+ },
};
static void block_job_cb(void *opaque, int ret)
@@ -38,9 +43,9 @@ static BlockJob *mk_job(BlockBackend *blk, const char *id,
g_assert_null(errp);
g_assert_nonnull(job);
if (id) {
- g_assert_cmpstr(job->id, ==, id);
+ g_assert_cmpstr(job->job.id, ==, id);
} else {
- g_assert_cmpstr(job->id, ==, blk_name(blk));
+ g_assert_cmpstr(job->job.id, ==, blk_name(blk));
}
} else {
g_assert_nonnull(errp);
@@ -55,7 +60,7 @@ static BlockJob *do_test_id(BlockBackend *blk, const char *id,
bool should_succeed)
{
return mk_job(blk, id, &test_block_job_driver,
- should_succeed, BLOCK_JOB_DEFAULT);
+ should_succeed, JOB_DEFAULT);
}
/* This creates a BlockBackend (optionally with a name) with a
@@ -124,11 +129,11 @@ static void test_job_ids(void)
job[1] = do_test_id(blk[1], "id0", false);
/* But once job[0] finishes we can reuse its ID */
- block_job_early_fail(job[0]);
+ job_early_fail(&job[0]->job);
job[1] = do_test_id(blk[1], "id0", true);
/* No job ID specified, defaults to the backend name ('drive1') */
- block_job_early_fail(job[1]);
+ job_early_fail(&job[1]->job);
job[1] = do_test_id(blk[1], NULL, true);
/* Duplicate job ID */
@@ -141,9 +146,9 @@ static void test_job_ids(void)
/* This one is valid */
job[2] = do_test_id(blk[2], "id_2", true);
- block_job_early_fail(job[0]);
- block_job_early_fail(job[1]);
- block_job_early_fail(job[2]);
+ job_early_fail(&job[0]->job);
+ job_early_fail(&job[1]->job);
+ job_early_fail(&job[2]->job);
destroy_blk(blk[0]);
destroy_blk(blk[1]);
@@ -158,16 +163,16 @@ typedef struct CancelJob {
bool completed;
} CancelJob;
-static void cancel_job_completed(BlockJob *job, void *opaque)
+static void cancel_job_completed(Job *job, void *opaque)
{
CancelJob *s = opaque;
s->completed = true;
- block_job_completed(job, 0);
+ job_completed(job, 0, NULL);
}
-static void cancel_job_complete(BlockJob *job, Error **errp)
+static void cancel_job_complete(Job *job, Error **errp)
{
- CancelJob *s = container_of(job, CancelJob, common);
+ CancelJob *s = container_of(job, CancelJob, common.job);
s->should_complete = true;
}
@@ -176,25 +181,30 @@ static void coroutine_fn cancel_job_start(void *opaque)
CancelJob *s = opaque;
while (!s->should_complete) {
- if (block_job_is_cancelled(&s->common)) {
+ if (job_is_cancelled(&s->common.job)) {
goto defer;
}
- if (!s->common.ready && s->should_converge) {
- block_job_event_ready(&s->common);
+ if (!job_is_ready(&s->common.job) && s->should_converge) {
+ job_transition_to_ready(&s->common.job);
}
- block_job_sleep_ns(&s->common, 100000);
+ job_sleep_ns(&s->common.job, 100000);
}
defer:
- block_job_defer_to_main_loop(&s->common, cancel_job_completed, s);
+ job_defer_to_main_loop(&s->common.job, cancel_job_completed, s);
}
static const BlockJobDriver test_cancel_driver = {
- .instance_size = sizeof(CancelJob),
- .start = cancel_job_start,
- .complete = cancel_job_complete,
+ .job_driver = {
+ .instance_size = sizeof(CancelJob),
+ .free = block_job_free,
+ .user_resume = block_job_user_resume,
+ .drain = block_job_drain,
+ .start = cancel_job_start,
+ .complete = cancel_job_complete,
+ },
};
static CancelJob *create_common(BlockJob **pjob)
@@ -205,9 +215,9 @@ static CancelJob *create_common(BlockJob **pjob)
blk = create_blk(NULL);
job = mk_job(blk, "Steve", &test_cancel_driver, true,
- BLOCK_JOB_MANUAL_FINALIZE | BLOCK_JOB_MANUAL_DISMISS);
- block_job_ref(job);
- assert(job->status == BLOCK_JOB_STATUS_CREATED);
+ JOB_MANUAL_FINALIZE | JOB_MANUAL_DISMISS);
+ job_ref(&job->job);
+ assert(job->job.status == JOB_STATUS_CREATED);
s = container_of(job, CancelJob, common);
s->blk = blk;
@@ -219,16 +229,15 @@ static void cancel_common(CancelJob *s)
{
BlockJob *job = &s->common;
BlockBackend *blk = s->blk;
- BlockJobStatus sts = job->status;
+ JobStatus sts = job->job.status;
- block_job_cancel_sync(job);
- if ((sts != BLOCK_JOB_STATUS_CREATED) &&
- (sts != BLOCK_JOB_STATUS_CONCLUDED)) {
- BlockJob *dummy = job;
- block_job_dismiss(&dummy, &error_abort);
+ job_cancel_sync(&job->job);
+ if (sts != JOB_STATUS_CREATED && sts != JOB_STATUS_CONCLUDED) {
+ Job *dummy = &job->job;
+ job_dismiss(&dummy, &error_abort);
}
- assert(job->status == BLOCK_JOB_STATUS_NULL);
- block_job_unref(job);
+ assert(job->job.status == JOB_STATUS_NULL);
+ job_unref(&job->job);
destroy_blk(blk);
}
@@ -248,8 +257,8 @@ static void test_cancel_running(void)
s = create_common(&job);
- block_job_start(job);
- assert(job->status == BLOCK_JOB_STATUS_RUNNING);
+ job_start(&job->job);
+ assert(job->job.status == JOB_STATUS_RUNNING);
cancel_common(s);
}
@@ -261,12 +270,12 @@ static void test_cancel_paused(void)
s = create_common(&job);
- block_job_start(job);
- assert(job->status == BLOCK_JOB_STATUS_RUNNING);
+ job_start(&job->job);
+ assert(job->job.status == JOB_STATUS_RUNNING);
- block_job_user_pause(job, &error_abort);
- block_job_enter(job);
- assert(job->status == BLOCK_JOB_STATUS_PAUSED);
+ job_user_pause(&job->job, &error_abort);
+ job_enter(&job->job);
+ assert(job->job.status == JOB_STATUS_PAUSED);
cancel_common(s);
}
@@ -278,12 +287,12 @@ static void test_cancel_ready(void)
s = create_common(&job);
- block_job_start(job);
- assert(job->status == BLOCK_JOB_STATUS_RUNNING);
+ job_start(&job->job);
+ assert(job->job.status == JOB_STATUS_RUNNING);
s->should_converge = true;
- block_job_enter(job);
- assert(job->status == BLOCK_JOB_STATUS_READY);
+ job_enter(&job->job);
+ assert(job->job.status == JOB_STATUS_READY);
cancel_common(s);
}
@@ -295,16 +304,16 @@ static void test_cancel_standby(void)
s = create_common(&job);
- block_job_start(job);
- assert(job->status == BLOCK_JOB_STATUS_RUNNING);
+ job_start(&job->job);
+ assert(job->job.status == JOB_STATUS_RUNNING);
s->should_converge = true;
- block_job_enter(job);
- assert(job->status == BLOCK_JOB_STATUS_READY);
+ job_enter(&job->job);
+ assert(job->job.status == JOB_STATUS_READY);
- block_job_user_pause(job, &error_abort);
- block_job_enter(job);
- assert(job->status == BLOCK_JOB_STATUS_STANDBY);
+ job_user_pause(&job->job, &error_abort);
+ job_enter(&job->job);
+ assert(job->job.status == JOB_STATUS_STANDBY);
cancel_common(s);
}
@@ -316,19 +325,19 @@ static void test_cancel_pending(void)
s = create_common(&job);
- block_job_start(job);
- assert(job->status == BLOCK_JOB_STATUS_RUNNING);
+ job_start(&job->job);
+ assert(job->job.status == JOB_STATUS_RUNNING);
s->should_converge = true;
- block_job_enter(job);
- assert(job->status == BLOCK_JOB_STATUS_READY);
+ job_enter(&job->job);
+ assert(job->job.status == JOB_STATUS_READY);
- block_job_complete(job, &error_abort);
- block_job_enter(job);
+ job_complete(&job->job, &error_abort);
+ job_enter(&job->job);
while (!s->completed) {
aio_poll(qemu_get_aio_context(), true);
}
- assert(job->status == BLOCK_JOB_STATUS_PENDING);
+ assert(job->job.status == JOB_STATUS_PENDING);
cancel_common(s);
}
@@ -340,22 +349,22 @@ static void test_cancel_concluded(void)
s = create_common(&job);
- block_job_start(job);
- assert(job->status == BLOCK_JOB_STATUS_RUNNING);
+ job_start(&job->job);
+ assert(job->job.status == JOB_STATUS_RUNNING);
s->should_converge = true;
- block_job_enter(job);
- assert(job->status == BLOCK_JOB_STATUS_READY);
+ job_enter(&job->job);
+ assert(job->job.status == JOB_STATUS_READY);
- block_job_complete(job, &error_abort);
- block_job_enter(job);
+ job_complete(&job->job, &error_abort);
+ job_enter(&job->job);
while (!s->completed) {
aio_poll(qemu_get_aio_context(), true);
}
- assert(job->status == BLOCK_JOB_STATUS_PENDING);
+ assert(job->job.status == JOB_STATUS_PENDING);
- block_job_finalize(job, &error_abort);
- assert(job->status == BLOCK_JOB_STATUS_CONCLUDED);
+ job_finalize(&job->job, &error_abort);
+ assert(job->job.status == JOB_STATUS_CONCLUDED);
cancel_common(s);
}
diff --git a/tests/test-char.c b/tests/test-char.c
index 1880d36783..5905d31441 100644
--- a/tests/test-char.c
+++ b/tests/test-char.c
@@ -214,6 +214,10 @@ static void char_mux_test(void)
g_assert_cmpint(h2.last_event, ==, -1);
/* switch focus */
+ qemu_chr_be_write(base, (void *)"\1b", 2);
+ g_assert_cmpint(h1.last_event, ==, 42);
+ g_assert_cmpint(h2.last_event, ==, CHR_EVENT_BREAK);
+
qemu_chr_be_write(base, (void *)"\1c", 2);
g_assert_cmpint(h1.last_event, ==, CHR_EVENT_MUX_IN);
g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT);
@@ -227,6 +231,10 @@ static void char_mux_test(void)
g_assert_cmpstr(h1.read_buf, ==, "hello");
h1.read_count = 0;
+ qemu_chr_be_write(base, (void *)"\1b", 2);
+ g_assert_cmpint(h1.last_event, ==, CHR_EVENT_BREAK);
+ g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT);
+
/* remove first handler */
qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL,
NULL, NULL, true);
diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c
index e0ed461f58..491b0c4a44 100644
--- a/tests/test-qmp-cmds.c
+++ b/tests/test-qmp-cmds.c
@@ -16,7 +16,7 @@ void qmp_user_def_cmd(Error **errp)
{
}
-void qmp_an_oob_command(Error **errp)
+void qmp_test_flags_command(Error **errp)
{
}
diff --git a/tests/tpm-crb-swtpm-test.c b/tests/tpm-crb-swtpm-test.c
new file mode 100644
index 0000000000..c2bde0cbaa
--- /dev/null
+++ b/tests/tpm-crb-swtpm-test.c
@@ -0,0 +1,247 @@
+/*
+ * QTest testcase for TPM CRB talking to external swtpm and swtpm migration
+ *
+ * Copyright (c) 2018 IBM Corporation
+ * with parts borrowed from migration-test.c that is:
+ * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates
+ *
+ * Authors:
+ * Stefan Berger <stefanb@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include <glib/gstdio.h>
+
+#include "hw/acpi/tpm.h"
+#include "io/channel-socket.h"
+#include "libqtest.h"
+#include "tpm-util.h"
+#include "sysemu/tpm.h"
+#include "qapi/qmp/qdict.h"
+
+typedef struct TestState {
+ char *src_tpm_path;
+ char *dst_tpm_path;
+ char *uri;
+} TestState;
+
+bool got_stop;
+
+static void migrate(QTestState *who, const char *uri)
+{
+ QDict *rsp;
+ gchar *cmd;
+
+ cmd = g_strdup_printf("{ 'execute': 'migrate',"
+ "'arguments': { 'uri': '%s' } }",
+ uri);
+ rsp = qtest_qmp(who, cmd);
+ g_free(cmd);
+ g_assert(qdict_haskey(rsp, "return"));
+ qobject_unref(rsp);
+}
+
+/*
+ * Events can get in the way of responses we are actually waiting for.
+ */
+static QDict *wait_command(QTestState *who, const char *command)
+{
+ const char *event_string;
+ QDict *response;
+
+ response = qtest_qmp(who, command);
+
+ while (qdict_haskey(response, "event")) {
+ /* OK, it was an event */
+ event_string = qdict_get_str(response, "event");
+ if (!strcmp(event_string, "STOP")) {
+ got_stop = true;
+ }
+ qobject_unref(response);
+ response = qtest_qmp_receive(who);
+ }
+ return response;
+}
+
+static void wait_for_migration_complete(QTestState *who)
+{
+ while (true) {
+ QDict *rsp, *rsp_return;
+ bool completed;
+ const char *status;
+
+ rsp = wait_command(who, "{ 'execute': 'query-migrate' }");
+ rsp_return = qdict_get_qdict(rsp, "return");
+ status = qdict_get_str(rsp_return, "status");
+ completed = strcmp(status, "completed") == 0;
+ g_assert_cmpstr(status, !=, "failed");
+ qobject_unref(rsp);
+ if (completed) {
+ return;
+ }
+ usleep(1000);
+ }
+}
+
+static void migration_start_qemu(QTestState **src_qemu, QTestState **dst_qemu,
+ SocketAddress *src_tpm_addr,
+ SocketAddress *dst_tpm_addr,
+ const char *miguri)
+{
+ char *src_qemu_args, *dst_qemu_args;
+
+ src_qemu_args = g_strdup_printf(
+ "-chardev socket,id=chr,path=%s "
+ "-tpmdev emulator,id=dev,chardev=chr "
+ "-device tpm-crb,tpmdev=dev ",
+ src_tpm_addr->u.q_unix.path);
+
+ *src_qemu = qtest_init(src_qemu_args);
+
+ dst_qemu_args = g_strdup_printf(
+ "-chardev socket,id=chr,path=%s "
+ "-tpmdev emulator,id=dev,chardev=chr "
+ "-device tpm-crb,tpmdev=dev "
+ "-incoming %s",
+ dst_tpm_addr->u.q_unix.path,
+ miguri);
+
+ *dst_qemu = qtest_init(dst_qemu_args);
+
+ free(src_qemu_args);
+ free(dst_qemu_args);
+}
+
+static void tpm_crb_swtpm_test(const void *data)
+{
+ char *args = NULL;
+ QTestState *s;
+ SocketAddress *addr = NULL;
+ gboolean succ;
+ GPid swtpm_pid;
+ GError *error = NULL;
+ const TestState *ts = data;
+
+ succ = tpm_util_swtpm_start(ts->src_tpm_path, &swtpm_pid, &addr, &error);
+ /* succ may be false if swtpm is not available */
+ if (!succ) {
+ return;
+ }
+
+ args = g_strdup_printf(
+ "-chardev socket,id=chr,path=%s "
+ "-tpmdev emulator,id=dev,chardev=chr "
+ "-device tpm-crb,tpmdev=dev",
+ addr->u.q_unix.path);
+
+ s = qtest_start(args);
+ g_free(args);
+
+ tpm_util_startup(s, tpm_util_crb_transfer);
+ tpm_util_pcrextend(s, tpm_util_crb_transfer);
+
+ unsigned char tpm_pcrread_resp[] =
+ "\x80\x01\x00\x00\x00\x3e\x00\x00\x00\x00\x00\x00\x00\x16\x00\x00"
+ "\x00\x01\x00\x0b\x03\x00\x04\x00\x00\x00\x00\x01\x00\x20\xf6\x85"
+ "\x98\xe5\x86\x8d\xe6\x8b\x97\x29\x99\x60\xf2\x71\x7d\x17\x67\x89"
+ "\xa4\x2f\x9a\xae\xa8\xc7\xb7\xaa\x79\xa8\x62\x56\xc1\xde";
+ tpm_util_pcrread(s, tpm_util_crb_transfer, tpm_pcrread_resp,
+ sizeof(tpm_pcrread_resp));
+
+ qtest_end();
+ tpm_util_swtpm_kill(swtpm_pid);
+
+ if (addr) {
+ g_unlink(addr->u.q_unix.path);
+ qapi_free_SocketAddress(addr);
+ }
+}
+
+static void tpm_crb_swtpm_migration_test(const void *data)
+{
+ const TestState *ts = data;
+ gboolean succ;
+ GPid src_tpm_pid, dst_tpm_pid;
+ SocketAddress *src_tpm_addr = NULL, *dst_tpm_addr = NULL;
+ GError *error = NULL;
+ QTestState *src_qemu, *dst_qemu;
+
+ succ = tpm_util_swtpm_start(ts->src_tpm_path, &src_tpm_pid,
+ &src_tpm_addr, &error);
+ /* succ may be false if swtpm is not available */
+ if (!succ) {
+ return;
+ }
+
+ succ = tpm_util_swtpm_start(ts->dst_tpm_path, &dst_tpm_pid,
+ &dst_tpm_addr, &error);
+ /* succ may be false if swtpm is not available */
+ if (!succ) {
+ goto err_src_tpm_kill;
+ }
+
+ migration_start_qemu(&src_qemu, &dst_qemu, src_tpm_addr, dst_tpm_addr,
+ ts->uri);
+
+ tpm_util_startup(src_qemu, tpm_util_crb_transfer);
+ tpm_util_pcrextend(src_qemu, tpm_util_crb_transfer);
+
+ unsigned char tpm_pcrread_resp[] =
+ "\x80\x01\x00\x00\x00\x3e\x00\x00\x00\x00\x00\x00\x00\x16\x00\x00"
+ "\x00\x01\x00\x0b\x03\x00\x04\x00\x00\x00\x00\x01\x00\x20\xf6\x85"
+ "\x98\xe5\x86\x8d\xe6\x8b\x97\x29\x99\x60\xf2\x71\x7d\x17\x67\x89"
+ "\xa4\x2f\x9a\xae\xa8\xc7\xb7\xaa\x79\xa8\x62\x56\xc1\xde";
+ tpm_util_pcrread(src_qemu, tpm_util_crb_transfer, tpm_pcrread_resp,
+ sizeof(tpm_pcrread_resp));
+
+ migrate(src_qemu, ts->uri);
+ wait_for_migration_complete(src_qemu);
+
+ tpm_util_pcrread(dst_qemu, tpm_util_crb_transfer, tpm_pcrread_resp,
+ sizeof(tpm_pcrread_resp));
+
+ qtest_quit(dst_qemu);
+ qtest_quit(src_qemu);
+
+ tpm_util_swtpm_kill(dst_tpm_pid);
+ if (dst_tpm_addr) {
+ g_unlink(dst_tpm_addr->u.q_unix.path);
+ qapi_free_SocketAddress(dst_tpm_addr);
+ }
+
+err_src_tpm_kill:
+ tpm_util_swtpm_kill(src_tpm_pid);
+ if (src_tpm_addr) {
+ g_unlink(src_tpm_addr->u.q_unix.path);
+ qapi_free_SocketAddress(src_tpm_addr);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+ TestState ts = { 0 };
+
+ ts.src_tpm_path = g_dir_make_tmp("qemu-tpm-crb-swtpm-test.XXXXXX", NULL);
+ ts.dst_tpm_path = g_dir_make_tmp("qemu-tpm-crb-swtpm-test.XXXXXX", NULL);
+ ts.uri = g_strdup_printf("unix:%s/migsocket", ts.src_tpm_path);
+
+ module_call_init(MODULE_INIT_QOM);
+ g_test_init(&argc, &argv, NULL);
+
+ qtest_add_data_func("/tpm/crb-swtpm/test", &ts, tpm_crb_swtpm_test);
+ qtest_add_data_func("/tpm/crb-swtpm-migration/test", &ts,
+ tpm_crb_swtpm_migration_test);
+ ret = g_test_run();
+
+ g_rmdir(ts.dst_tpm_path);
+ g_free(ts.dst_tpm_path);
+ g_rmdir(ts.src_tpm_path);
+ g_free(ts.src_tpm_path);
+ g_free(ts.uri);
+
+ return ret;
+}
diff --git a/tests/tpm-util.c b/tests/tpm-util.c
new file mode 100644
index 0000000000..c9b3947c1c
--- /dev/null
+++ b/tests/tpm-util.c
@@ -0,0 +1,186 @@
+/*
+ * QTest TPM utilities
+ *
+ * Copyright (c) 2018 IBM Corporation
+ * Copyright (c) 2018 Red Hat, Inc.
+ *
+ * Authors:
+ * Stefan Berger <stefanb@linux.vnet.ibm.com>
+ * Marc-André Lureau <marcandre.lureau@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/acpi/tpm.h"
+#include "libqtest.h"
+#include "tpm-util.h"
+
+void tpm_util_crb_transfer(QTestState *s,
+ const unsigned char *req, size_t req_size,
+ unsigned char *rsp, size_t rsp_size)
+{
+ uint64_t caddr = qtest_readq(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_CMD_LADDR);
+ uint64_t raddr = qtest_readq(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_RSP_ADDR);
+
+ qtest_writeb(s, TPM_CRB_ADDR_BASE + A_CRB_LOC_CTRL, 1);
+
+ qtest_memwrite(s, caddr, req, req_size);
+
+ uint32_t sts, start = 1;
+ uint64_t end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
+ qtest_writel(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_START, start);
+ while (true) {
+ start = qtest_readl(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_START);
+ if ((start & 1) == 0) {
+ break;
+ }
+ if (g_get_monotonic_time() >= end_time) {
+ break;
+ }
+ };
+ start = qtest_readl(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_START);
+ g_assert_cmpint(start & 1, ==, 0);
+ sts = qtest_readl(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_STS);
+ g_assert_cmpint(sts & 1, ==, 0);
+
+ qtest_memread(s, raddr, rsp, rsp_size);
+}
+
+void tpm_util_startup(QTestState *s, tx_func *tx)
+{
+ unsigned char buffer[1024];
+ unsigned char tpm_startup[] =
+ "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00";
+ unsigned char tpm_startup_resp[] =
+ "\x80\x01\x00\x00\x00\x0a\x00\x00\x00\x00";
+
+ tx(s, tpm_startup, sizeof(tpm_startup), buffer, sizeof(buffer));
+
+ g_assert_cmpmem(buffer, sizeof(tpm_startup_resp),
+ tpm_startup_resp, sizeof(tpm_startup_resp));
+}
+
+void tpm_util_pcrextend(QTestState *s, tx_func *tx)
+{
+ unsigned char buffer[1024];
+ unsigned char tpm_pcrextend[] =
+ "\x80\x02\x00\x00\x00\x41\x00\x00\x01\x82\x00\x00\x00\x0a\x00\x00"
+ "\x00\x09\x40\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00"
+ "\x0b\x74\x65\x73\x74\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00";
+
+ unsigned char tpm_pcrextend_resp[] =
+ "\x80\x02\x00\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x01\x00\x00";
+
+ tx(s, tpm_pcrextend, sizeof(tpm_pcrextend), buffer, sizeof(buffer));
+
+ g_assert_cmpmem(buffer, sizeof(tpm_pcrextend_resp),
+ tpm_pcrextend_resp, sizeof(tpm_pcrextend_resp));
+}
+
+void tpm_util_pcrread(QTestState *s, tx_func *tx,
+ const unsigned char *exp_resp, size_t exp_resp_size)
+{
+ unsigned char buffer[1024];
+ unsigned char tpm_pcrread[] =
+ "\x80\x01\x00\x00\x00\x14\x00\x00\x01\x7e\x00\x00\x00\x01\x00\x0b"
+ "\x03\x00\x04\x00";
+
+ tx(s, tpm_pcrread, sizeof(tpm_pcrread), buffer, sizeof(buffer));
+
+ g_assert_cmpmem(buffer, exp_resp_size, exp_resp, exp_resp_size);
+}
+
+static gboolean tpm_util_swtpm_has_tpm2(void)
+{
+ gint mystdout;
+ gboolean succ;
+ unsigned i;
+ char buffer[10240];
+ ssize_t n;
+ gchar *swtpm_argv[] = {
+ g_strdup("swtpm"), g_strdup("socket"), g_strdup("--help"), NULL
+ };
+
+ succ = g_spawn_async_with_pipes(NULL, swtpm_argv, NULL,
+ G_SPAWN_SEARCH_PATH, NULL, NULL, NULL,
+ NULL, &mystdout, NULL, NULL);
+ if (!succ) {
+ goto cleanup;
+ }
+
+ n = read(mystdout, buffer, sizeof(buffer) - 1);
+ if (n < 0) {
+ goto cleanup;
+ }
+ buffer[n] = 0;
+ if (!strstr(buffer, "--tpm2")) {
+ succ = false;
+ }
+
+ cleanup:
+ for (i = 0; swtpm_argv[i]; i++) {
+ g_free(swtpm_argv[i]);
+ }
+
+ return succ;
+}
+
+gboolean tpm_util_swtpm_start(const char *path, GPid *pid,
+ SocketAddress **addr, GError **error)
+{
+ char *swtpm_argv_tpmstate = g_strdup_printf("dir=%s", path);
+ char *swtpm_argv_ctrl = g_strdup_printf("type=unixio,path=%s/sock",
+ path);
+ gchar *swtpm_argv[] = {
+ g_strdup("swtpm"), g_strdup("socket"),
+ g_strdup("--tpmstate"), swtpm_argv_tpmstate,
+ g_strdup("--ctrl"), swtpm_argv_ctrl,
+ g_strdup("--tpm2"),
+ NULL
+ };
+ gboolean succ;
+ unsigned i;
+
+ succ = tpm_util_swtpm_has_tpm2();
+ if (!succ) {
+ goto cleanup;
+ }
+
+ *addr = g_new0(SocketAddress, 1);
+ (*addr)->type = SOCKET_ADDRESS_TYPE_UNIX;
+ (*addr)->u.q_unix.path = g_build_filename(path, "sock", NULL);
+
+ succ = g_spawn_async(NULL, swtpm_argv, NULL, G_SPAWN_SEARCH_PATH,
+ NULL, NULL, pid, error);
+
+cleanup:
+ for (i = 0; swtpm_argv[i]; i++) {
+ g_free(swtpm_argv[i]);
+ }
+
+ return succ;
+}
+
+void tpm_util_swtpm_kill(GPid pid)
+{
+ int n;
+
+ if (!pid) {
+ return;
+ }
+
+ g_spawn_close_pid(pid);
+
+ n = kill(pid, 0);
+ if (n < 0) {
+ return;
+ }
+
+ kill(pid, SIGKILL);
+}
diff --git a/tests/tpm-util.h b/tests/tpm-util.h
new file mode 100644
index 0000000000..d155d99aea
--- /dev/null
+++ b/tests/tpm-util.h
@@ -0,0 +1,36 @@
+/*
+ * QTest TPM utilities
+ *
+ * Copyright (c) 2018 IBM Corporation
+ *
+ * Authors:
+ * Stefan Berger <stefanb@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef TESTS_TPM_UTIL_H
+#define TESTS_TPM_UTIL_H
+
+#include "qemu/osdep.h"
+#include "io/channel-socket.h"
+
+typedef void (tx_func)(QTestState *s,
+ const unsigned char *req, size_t req_size,
+ unsigned char *rsp, size_t rsp_size);
+
+void tpm_util_crb_transfer(QTestState *s,
+ const unsigned char *req, size_t req_size,
+ unsigned char *rsp, size_t rsp_size);
+
+void tpm_util_startup(QTestState *s, tx_func *tx);
+void tpm_util_pcrextend(QTestState *s, tx_func *tx);
+void tpm_util_pcrread(QTestState *s, tx_func *tx,
+ const unsigned char *exp_resp, size_t exp_resp_size);
+
+gboolean tpm_util_swtpm_start(const char *path, GPid *pid,
+ SocketAddress **addr, GError **error);
+void tpm_util_swtpm_kill(GPid pid);
+
+#endif /* TESTS_TPM_UTIL_H */
diff --git a/trace-events b/trace-events
index ed71f44649..c445f54773 100644
--- a/trace-events
+++ b/trace-events
@@ -104,6 +104,20 @@ gdbstub_err_invalid_rle(void) "got invalid RLE sequence"
gdbstub_err_checksum_invalid(uint8_t ch) "got invalid command checksum digit: 0x%02x"
gdbstub_err_checksum_incorrect(uint8_t expected, uint8_t got) "got command packet with incorrect checksum, expected=0x%02x, received=0x%02x"
+# job.c
+job_state_transition(void *job, int ret, const char *legal, const char *s0, const char *s1) "job %p (ret: %d) attempting %s transition (%s-->%s)"
+job_apply_verb(void *job, const char *state, const char *verb, const char *legal) "job %p in state %s; applying verb %s (%s)"
+job_completed(void *job, int ret, int jret) "job %p ret %d corrected ret %d"
+
+# job-qmp.c
+qmp_job_cancel(void *job) "job %p"
+qmp_job_pause(void *job) "job %p"
+qmp_job_resume(void *job) "job %p"
+qmp_job_complete(void *job) "job %p"
+qmp_job_finalize(void *job) "job %p"
+qmp_job_dismiss(void *job) "job %p"
+
+
### Guest events, keep at bottom
diff --git a/ui/cocoa.m b/ui/cocoa.m
index 110b393e4e..2991ed4f19 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -44,6 +44,9 @@
#ifndef MAC_OS_X_VERSION_10_6
#define MAC_OS_X_VERSION_10_6 1060
#endif
+#ifndef MAC_OS_X_VERSION_10_9
+#define MAC_OS_X_VERSION_10_9 1090
+#endif
#ifndef MAC_OS_X_VERSION_10_10
#define MAC_OS_X_VERSION_10_10 101000
#endif
@@ -79,6 +82,13 @@
#define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask
#define NSWindowStyleMaskTitled NSTitledWindowMask
#endif
+/* 10.13 deprecates NSFileHandlingPanelOKButton in favour of
+ * NSModalResponseOK, which was introduced in 10.9. Define
+ * it for older versions.
+ */
+#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9
+#define NSModalResponseOK NSFileHandlingPanelOKButton
+#endif
//#define DEBUG
@@ -1218,7 +1228,7 @@ QemuCocoaView *cocoaView;
[openPanel setCanChooseFiles: YES];
[openPanel setAllowsMultipleSelection: NO];
[openPanel setAllowedFileTypes: supportedImageFileTypes];
- if([openPanel runModal] == NSFileHandlingPanelOKButton) {
+ if([openPanel runModal] == NSModalResponseOK) {
NSString * file = [[[openPanel URLs] objectAtIndex: 0] path];
if(file == nil) {
NSBeep();
diff --git a/util/memfd.c b/util/memfd.c
index b3ecbac19e..d248a53c3c 100644
--- a/util/memfd.c
+++ b/util/memfd.c
@@ -66,7 +66,7 @@ int qemu_memfd_create(const char *name, size_t size, bool hugetlb,
{
int htsize = hugetlbsize ? ctz64(hugetlbsize) : 0;
- if (htsize && 1 << htsize != hugetlbsize) {
+ if (htsize && 1ULL << htsize != hugetlbsize) {
error_setg(errp, "Hugepage size must be a power of 2");
return -1;
}
diff --git a/vl.c b/vl.c
index d5836c65ae..06031715ac 100644
--- a/vl.c
+++ b/vl.c
@@ -28,11 +28,7 @@
#include "qemu/cutils.h"
#include "qemu/help_option.h"
#include "qemu/uuid.h"
-
-#ifdef CONFIG_SECCOMP
-#include <sys/prctl.h>
#include "sysemu/seccomp.h"
-#endif
#ifdef CONFIG_SDL
#if defined(__APPLE__) || defined(main)
@@ -259,35 +255,6 @@ static QemuOptsList qemu_rtc_opts = {
},
};
-static QemuOptsList qemu_sandbox_opts = {
- .name = "sandbox",
- .implied_opt_name = "enable",
- .head = QTAILQ_HEAD_INITIALIZER(qemu_sandbox_opts.head),
- .desc = {
- {
- .name = "enable",
- .type = QEMU_OPT_BOOL,
- },
- {
- .name = "obsolete",
- .type = QEMU_OPT_STRING,
- },
- {
- .name = "elevateprivileges",
- .type = QEMU_OPT_STRING,
- },
- {
- .name = "spawn",
- .type = QEMU_OPT_STRING,
- },
- {
- .name = "resourcecontrol",
- .type = QEMU_OPT_STRING,
- },
- { /* end of list */ }
- },
-};
-
static QemuOptsList qemu_option_rom_opts = {
.name = "option-rom",
.implied_opt_name = "romfile",
@@ -594,7 +561,7 @@ static int default_driver_check(void *opaque, QemuOpts *opts, Error **errp)
/***********************************************************/
/* QEMU state */
-static RunState current_run_state = RUN_STATE_PRELAUNCH;
+static RunState current_run_state = RUN_STATE_PRECONFIG;
/* We use RUN_STATE__MAX but any invalid value will do */
static RunState vmstop_requested = RUN_STATE__MAX;
@@ -607,6 +574,13 @@ typedef struct {
static const RunStateTransition runstate_transitions_def[] = {
/* from -> to */
+ { RUN_STATE_PRECONFIG, RUN_STATE_PRELAUNCH },
+ /* Early switch to inmigrate state to allow -incoming CLI option work
+ * as it used to. TODO: delay actual switching to inmigrate state to
+ * the point after machine is built and remove this hack.
+ */
+ { RUN_STATE_PRECONFIG, RUN_STATE_INMIGRATE },
+
{ RUN_STATE_DEBUG, RUN_STATE_RUNNING },
{ RUN_STATE_DEBUG, RUN_STATE_FINISH_MIGRATE },
{ RUN_STATE_DEBUG, RUN_STATE_PRELAUNCH },
@@ -1043,88 +1017,6 @@ static int bt_parse(const char *opt)
return 1;
}
-static int parse_sandbox(void *opaque, QemuOpts *opts, Error **errp)
-{
- if (qemu_opt_get_bool(opts, "enable", false)) {
-#ifdef CONFIG_SECCOMP
- uint32_t seccomp_opts = QEMU_SECCOMP_SET_DEFAULT
- | QEMU_SECCOMP_SET_OBSOLETE;
- const char *value = NULL;
-
- value = qemu_opt_get(opts, "obsolete");
- if (value) {
- if (g_str_equal(value, "allow")) {
- seccomp_opts &= ~QEMU_SECCOMP_SET_OBSOLETE;
- } else if (g_str_equal(value, "deny")) {
- /* this is the default option, this if is here
- * to provide a little bit of consistency for
- * the command line */
- } else {
- error_report("invalid argument for obsolete");
- return -1;
- }
- }
-
- value = qemu_opt_get(opts, "elevateprivileges");
- if (value) {
- if (g_str_equal(value, "deny")) {
- seccomp_opts |= QEMU_SECCOMP_SET_PRIVILEGED;
- } else if (g_str_equal(value, "children")) {
- seccomp_opts |= QEMU_SECCOMP_SET_PRIVILEGED;
-
- /* calling prctl directly because we're
- * not sure if host has CAP_SYS_ADMIN set*/
- if (prctl(PR_SET_NO_NEW_PRIVS, 1)) {
- error_report("failed to set no_new_privs "
- "aborting");
- return -1;
- }
- } else if (g_str_equal(value, "allow")) {
- /* default value */
- } else {
- error_report("invalid argument for elevateprivileges");
- return -1;
- }
- }
-
- value = qemu_opt_get(opts, "spawn");
- if (value) {
- if (g_str_equal(value, "deny")) {
- seccomp_opts |= QEMU_SECCOMP_SET_SPAWN;
- } else if (g_str_equal(value, "allow")) {
- /* default value */
- } else {
- error_report("invalid argument for spawn");
- return -1;
- }
- }
-
- value = qemu_opt_get(opts, "resourcecontrol");
- if (value) {
- if (g_str_equal(value, "deny")) {
- seccomp_opts |= QEMU_SECCOMP_SET_RESOURCECTL;
- } else if (g_str_equal(value, "allow")) {
- /* default value */
- } else {
- error_report("invalid argument for resourcecontrol");
- return -1;
- }
- }
-
- if (seccomp_start(seccomp_opts) < 0) {
- error_report("failed to install seccomp syscall filter "
- "in the kernel");
- return -1;
- }
-#else
- error_report("seccomp support is disabled");
- return -1;
-#endif
- }
-
- return 0;
-}
-
static int parse_name(void *opaque, QemuOpts *opts, Error **errp)
{
const char *proc_name;
@@ -1630,6 +1522,7 @@ static pid_t shutdown_pid;
static int powerdown_requested;
static int debug_requested;
static int suspend_requested;
+static bool preconfig_exit_requested = true;
static WakeupReason wakeup_reason;
static NotifierList powerdown_notifiers =
NOTIFIER_LIST_INITIALIZER(powerdown_notifiers);
@@ -1714,6 +1607,11 @@ static int qemu_debug_requested(void)
return r;
}
+void qemu_exit_preconfig_request(void)
+{
+ preconfig_exit_requested = true;
+}
+
/*
* Reset the VM. Issue an event unless @reason is SHUTDOWN_CAUSE_NONE.
*/
@@ -1887,6 +1785,13 @@ static bool main_loop_should_exit(void)
RunState r;
ShutdownCause request;
+ if (preconfig_exit_requested) {
+ if (runstate_check(RUN_STATE_PRECONFIG)) {
+ runstate_set(RUN_STATE_PRELAUNCH);
+ }
+ preconfig_exit_requested = false;
+ return true;
+ }
if (qemu_debug_requested()) {
vm_stop(RUN_STATE_DEBUG);
}
@@ -3059,7 +2964,6 @@ int main(int argc, char **argv, char **envp)
qemu_add_opts(&qemu_mem_opts);
qemu_add_opts(&qemu_smp_opts);
qemu_add_opts(&qemu_boot_opts);
- qemu_add_opts(&qemu_sandbox_opts);
qemu_add_opts(&qemu_add_fd_opts);
qemu_add_opts(&qemu_object_opts);
qemu_add_opts(&qemu_tpmdev_opts);
@@ -3667,6 +3571,9 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
break;
+ case QEMU_OPTION_preconfig:
+ preconfig_exit_requested = false;
+ break;
case QEMU_OPTION_enable_kvm:
olist = qemu_find_opts("machine");
qemu_opts_parse_noisily(olist, "accel=kvm", false);
@@ -3829,6 +3736,7 @@ int main(int argc, char **argv, char **envp)
/* Clock options no longer exist. Keep this option for
* backward compatibility.
*/
+ warn_report("This option is ignored and will be removed soon");
break;
case QEMU_OPTION_startdate:
warn_report("This option is deprecated, use '-rtc base=' instead.");
@@ -3957,11 +3865,17 @@ int main(int argc, char **argv, char **envp)
qtest_log = optarg;
break;
case QEMU_OPTION_sandbox:
+#ifdef CONFIG_SECCOMP
opts = qemu_opts_parse_noisily(qemu_find_opts("sandbox"),
optarg, true);
if (!opts) {
exit(1);
}
+#else
+ error_report("-sandbox support is not enabled "
+ "in this QEMU binary");
+ exit(1);
+#endif
break;
case QEMU_OPTION_add_fd:
#ifndef _WIN32
@@ -4031,6 +3945,12 @@ int main(int argc, char **argv, char **envp)
replay_configure(icount_opts);
+ if (incoming && !preconfig_exit_requested) {
+ error_report("'preconfig' and 'incoming' options are "
+ "mutually exclusive");
+ exit(EXIT_FAILURE);
+ }
+
machine_class = select_machine();
set_memory_options(&ram_slots, &maxram_size, machine_class);
@@ -4048,10 +3968,12 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
+#ifdef CONFIG_SECCOMP
if (qemu_opts_foreach(qemu_find_opts("sandbox"),
parse_sandbox, NULL, NULL)) {
exit(1);
}
+#endif
if (qemu_opts_foreach(qemu_find_opts("name"),
parse_name, NULL, NULL)) {
@@ -4548,6 +4470,10 @@ int main(int argc, char **argv, char **envp)
}
parse_numa_opts(current_machine);
+ /* do monitor/qmp handling at preconfig state if requested */
+ main_loop();
+
+ /* from here on runstate is RUN_STATE_PRELAUNCH */
machine_run_board_init(current_machine);
realtime_init();
@@ -4683,6 +4609,7 @@ int main(int argc, char **argv, char **envp)
/* No more vcpu or device emulation activity beyond this point */
vm_shutdown();
+ job_cancel_sync_all();
bdrv_close_all();
res_free();