aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.gitlab-ci.d/check-units.py29
-rw-r--r--MAINTAINERS4
-rw-r--r--accel/accel-common.c2
-rw-r--r--accel/accel-qmp.c35
-rw-r--r--accel/accel-system.c12
-rw-r--r--accel/hvf/hvf-accel-ops.c27
-rw-r--r--accel/hvf/hvf-all.c1
-rw-r--r--accel/kvm/kvm-accel-ops.c2
-rw-r--r--accel/kvm/kvm-all.c1
-rw-r--r--accel/meson.build2
-rw-r--r--accel/qtest/qtest.c3
-rw-r--r--accel/tcg/internal-common.h2
-rw-r--r--accel/tcg/meson.build1
-rw-r--r--accel/tcg/monitor.c192
-rw-r--r--accel/tcg/tcg-accel-ops-rr.c2
-rw-r--r--accel/tcg/tcg-accel-ops.c3
-rw-r--r--accel/tcg/tcg-all.c3
-rw-r--r--accel/tcg/tcg-stats.c219
-rw-r--r--accel/xen/xen-all.c3
-rw-r--r--block.c75
-rw-r--r--block/backup.c4
-rw-r--r--block/blklogwrites.c8
-rw-r--r--block/blkverify.c4
-rw-r--r--block/block-backend.c8
-rw-r--r--block/commit.c34
-rw-r--r--block/file-posix.c29
-rw-r--r--block/graph-lock.c40
-rw-r--r--block/io.c7
-rw-r--r--block/mirror.c17
-rw-r--r--block/monitor/block-hmp-cmds.c15
-rw-r--r--block/qapi.c12
-rw-r--r--block/qcow2.c4
-rw-r--r--block/quorum.c8
-rw-r--r--block/replication.c14
-rw-r--r--block/snapshot.c4
-rw-r--r--block/stream.c21
-rw-r--r--block/vmdk.c26
-rw-r--r--blockdev.c102
-rw-r--r--blockjob.c10
-rw-r--r--bsd-user/main.c1
-rw-r--r--common-user/plugin-api.c.inc1
-rw-r--r--configs/targets/alpha-linux-user.mak1
-rw-r--r--configs/targets/alpha-softmmu.mak1
-rw-r--r--configs/targets/sparc64-linux-user.mak1
-rw-r--r--configs/targets/sparc64-softmmu.mak1
-rw-r--r--contrib/plugins/execlog.c15
-rw-r--r--cpu-target.c9
-rw-r--r--docs/devel/migration/vfio.rst19
-rw-r--r--docs/devel/qapi-code-gen.rst28
-rw-r--r--docs/devel/qapi-domain.rst31
-rw-r--r--docs/devel/testing/main.rst4
-rw-r--r--docs/interop/firmware.json4
-rw-r--r--docs/interop/qemu-ga-ref.rst1
-rw-r--r--docs/interop/qemu-qmp-ref.rst1
-rw-r--r--docs/interop/qemu-storage-daemon-qmp-ref.rst1
-rw-r--r--docs/interop/vhost-user.json4
-rw-r--r--docs/sphinx/qapi_domain.py8
-rw-r--r--docs/sphinx/qapidoc.py96
-rw-r--r--docs/sphinx/qapidoc_legacy.py440
-rw-r--r--docs/system/images.rst2
-rw-r--r--docs/system/keys.rst.inc49
-rw-r--r--docs/system/linuxboot.rst2
-rw-r--r--docs/system/mux-chardev.rst.inc38
-rw-r--r--docs/system/virtio-net-failover.rst51
-rw-r--r--docs/tools/qemu-img.rst18
-rw-r--r--gdb-xml/alpha-core.xml136
-rw-r--r--gdb-xml/sparc64-core.xml99
-rw-r--r--gdbstub/system.c3
-rw-r--r--hmp-commands-info.hx12
-rw-r--r--hw/acpi/acpi-pci-hotplug-stub.c2
-rw-r--r--hw/acpi/aml-build.c27
-rw-r--r--hw/acpi/bios-linker-loader.c2
-rw-r--r--hw/acpi/generic_event_device.c77
-rw-r--r--hw/acpi/ich9.c7
-rw-r--r--hw/acpi/pci-bridge.c54
-rw-r--r--hw/acpi/pci.c50
-rw-r--r--hw/acpi/pcihp.c439
-rw-r--r--hw/acpi/piix4.c5
-rw-r--r--hw/arm/Kconfig2
-rw-r--r--hw/arm/allwinner-r40.c1
-rw-r--r--hw/arm/boot.c2
-rw-r--r--hw/arm/npcm7xx.c2
-rw-r--r--hw/arm/virt-acpi-build.c43
-rw-r--r--hw/arm/virt.c27
-rw-r--r--hw/arm/xen-pvh.c1
-rw-r--r--hw/block/hd-geometry.c1
-rw-r--r--hw/block/meson.build6
-rw-r--r--hw/block/vhost-user-blk.c9
-rw-r--r--hw/char/riscv_htif.c1
-rw-r--r--hw/core/cpu-system.c2
-rw-r--r--hw/core/machine-hmp-cmds.c5
-rw-r--r--hw/core/machine-qmp-cmds.c10
-rw-r--r--hw/core/machine.c23
-rw-r--r--hw/core/qdev-properties-system.c44
-rw-r--r--hw/core/qdev-properties.c67
-rw-r--r--hw/core/sysbus.c11
-rw-r--r--hw/cxl/cxl-events.c40
-rw-r--r--hw/cxl/cxl-mailbox-utils.c552
-rw-r--r--hw/display/artist.c1
-rw-r--r--hw/display/ati.c1
-rw-r--r--hw/display/vga.c2
-rw-r--r--hw/display/virtio-gpu-base.c27
-rw-r--r--hw/i386/acpi-build.c532
-rw-r--r--hw/i386/acpi-build.h4
-rw-r--r--hw/i386/amd_iommu.c17
-rw-r--r--hw/i386/amd_iommu.h59
-rw-r--r--hw/i386/intel_iommu.c142
-rw-r--r--hw/i386/intel_iommu_internal.h1
-rw-r--r--hw/intc/loongarch_extioi_kvm.c1
-rw-r--r--hw/loongarch/virt-acpi-build.c4
-rw-r--r--hw/mem/cxl_type3.c83
-rw-r--r--hw/microblaze/Kconfig4
-rw-r--r--hw/mips/Kconfig2
-rw-r--r--hw/mips/cps.c4
-rw-r--r--hw/misc/Kconfig1
-rw-r--r--hw/net/can/ctucan_core.c1
-rw-r--r--hw/net/lan9118.c1
-rw-r--r--hw/net/rtl8139.c1
-rw-r--r--hw/net/virtio-net.c254
-rw-r--r--hw/net/vmxnet3.c1
-rw-r--r--hw/pci-host/Kconfig1
-rw-r--r--hw/pci-host/gpex-acpi.c74
-rw-r--r--hw/pci-host/gt64120.c1
-rw-r--r--hw/pci-host/pnv_phb3.c1
-rw-r--r--hw/pci-host/pnv_phb4.c1
-rw-r--r--hw/pci-host/ppce500.c1
-rw-r--r--hw/pci-host/sh_pci.c1
-rw-r--r--hw/riscv/virt-acpi-build.c5
-rw-r--r--hw/s390x/s390-pci-inst.c1
-rw-r--r--hw/scsi/esp.c94
-rw-r--r--hw/scsi/trace-events1
-rw-r--r--hw/sensor/lsm303dlhc_mag.c1
-rw-r--r--hw/smbios/smbios.c1
-rw-r--r--hw/vfio-user/container.c6
-rw-r--r--hw/vfio-user/proxy.c10
-rw-r--r--hw/vfio/device.c6
-rw-r--r--hw/vfio/helpers.c17
-rw-r--r--hw/vfio/migration-multifd.c101
-rw-r--r--hw/vfio/migration-multifd.h3
-rw-r--r--hw/vfio/migration.c10
-rw-r--r--hw/vfio/pci.c48
-rw-r--r--hw/vfio/pci.h6
-rw-r--r--hw/vfio/trace-events1
-rw-r--r--hw/vfio/vfio-helpers.h2
-rw-r--r--hw/vfio/vfio-migration-internal.h1
-rw-r--r--hw/virtio/meson.build20
-rw-r--r--hw/virtio/vhost.c89
-rw-r--r--hw/virtio/virtio-config-io.c1
-rw-r--r--hw/virtio/virtio-pci.c1
-rw-r--r--hw/virtio/virtio.c2
-rw-r--r--hw/vmapple/virtio-blk.c1
-rw-r--r--include/accel/accel-cpu-ops.h (renamed from include/system/accel-ops.h)11
-rw-r--r--include/accel/accel-ops.h51
-rw-r--r--include/block/block-global-state.h46
-rw-r--r--include/block/block_int-common.h4
-rw-r--r--include/block/blockjob.h2
-rw-r--r--include/block/graph-lock.h11
-rw-r--r--include/block/snapshot.h6
-rw-r--r--include/exec/memattrs.h3
-rw-r--r--include/exec/tswap.h83
-rw-r--r--include/gdbstub/helpers.h48
-rw-r--r--include/hw/acpi/generic_event_device.h17
-rw-r--r--include/hw/acpi/pci.h5
-rw-r--r--include/hw/acpi/pcihp.h17
-rw-r--r--include/hw/arm/virt.h1
-rw-r--r--include/hw/arm/xen_arch_hvm.h9
-rw-r--r--include/hw/boards.h1
-rw-r--r--include/hw/cxl/cxl.h1
-rw-r--r--include/hw/cxl/cxl_device.h31
-rw-r--r--include/hw/cxl/cxl_events.h15
-rw-r--r--include/hw/cxl/cxl_mailbox.h6
-rw-r--r--include/hw/display/edid.h2
-rw-r--r--include/hw/i386/xen_arch_hvm.h11
-rw-r--r--include/hw/pci-host/gpex.h1
-rw-r--r--include/hw/pci/pci.h9
-rw-r--r--include/hw/qdev-properties-system.h5
-rw-r--r--include/hw/qdev-properties.h18
-rw-r--r--include/hw/scsi/esp.h15
-rw-r--r--include/hw/sysbus.h1
-rw-r--r--include/hw/vfio/vfio-device.h2
-rw-r--r--include/hw/virtio/vhost-user-blk.h2
-rw-r--r--include/hw/virtio/vhost.h15
-rw-r--r--include/hw/virtio/virtio-gpu.h3
-rw-r--r--include/hw/virtio/virtio-net.h6
-rw-r--r--include/hw/xen/arch_hvm.h14
-rw-r--r--include/net/net.h3
-rw-r--r--include/qemu/accel.h39
-rw-r--r--include/qemu/bswap.h73
-rw-r--r--include/qemu/job.h4
-rw-r--r--include/qemu/target-info-impl.h6
-rw-r--r--include/qemu/target-info-qapi.h29
-rw-r--r--include/qemu/target-info.h14
-rw-r--r--include/system/block-backend-global-state.h8
-rw-r--r--include/system/hvf_int.h3
-rw-r--r--include/system/kvm_int.h1
-rw-r--r--include/system/memory.h25
-rw-r--r--include/system/runstate.h41
-rw-r--r--include/tcg/tcg.h2
-rw-r--r--include/ui/console.h3
-rw-r--r--include/ui/gtk.h2
-rw-r--r--include/ui/spice-display.h5
-rw-r--r--include/ui/surface.h1
-rw-r--r--include/user/abitypes.h1
-rw-r--r--linux-user/main.c1
-rw-r--r--linux-user/meson.build5
-rw-r--r--linux-user/plugin-api.c1
-rw-r--r--net/af-xdp.c97
-rw-r--r--net/net.c9
-rw-r--r--net/vhost-vdpa.c34
-rw-r--r--[-rwxr-xr-x]pc-bios/hppa-firmware.imgbin167644 -> 167644 bytes
-rw-r--r--[-rwxr-xr-x]pc-bios/hppa-firmware64.imgbin206104 -> 206104 bytes
-rwxr-xr-xpython/tests/qapi-isort.sh2
-rw-r--r--qapi/accelerator.json54
-rw-r--r--qapi/acpi.json6
-rw-r--r--qapi/audio.json6
-rw-r--r--qapi/authz.json6
-rw-r--r--qapi/block-core.json219
-rw-r--r--qapi/block-export.json41
-rw-r--r--qapi/block.json23
-rw-r--r--qapi/char.json12
-rw-r--r--qapi/common.json4
-rw-r--r--qapi/compat.json4
-rw-r--r--qapi/control.json20
-rw-r--r--qapi/crypto.json8
-rw-r--r--qapi/cryptodev.json6
-rw-r--r--qapi/cxl.json4
-rw-r--r--qapi/dump.json19
-rw-r--r--qapi/ebpf.json6
-rw-r--r--qapi/error.json4
-rw-r--r--qapi/introspect.json34
-rw-r--r--qapi/job.json62
-rw-r--r--qapi/machine-common.json24
-rw-r--r--qapi/machine.json140
-rw-r--r--qapi/meson.build1
-rw-r--r--qapi/migration.json84
-rw-r--r--qapi/misc-arm.json4
-rw-r--r--qapi/misc-i386.json32
-rw-r--r--qapi/misc.json28
-rw-r--r--qapi/net.json41
-rw-r--r--qapi/pci.json8
-rw-r--r--qapi/qapi-schema.json5
-rw-r--r--qapi/qdev.json11
-rw-r--r--qapi/qom.json39
-rw-r--r--qapi/replay.json14
-rw-r--r--qapi/rocker.json8
-rw-r--r--qapi/run-state.json52
-rw-r--r--qapi/sockets.json10
-rw-r--r--qapi/stats.json14
-rw-r--r--qapi/tpm.json8
-rw-r--r--qapi/trace.json6
-rw-r--r--qapi/transaction.json16
-rw-r--r--qapi/uefi.json4
-rw-r--r--qapi/ui.json73
-rw-r--r--qapi/vfio.json4
-rw-r--r--qapi/virtio.json38
-rw-r--r--qapi/yank.json22
-rw-r--r--qemu-img-cmds.hx4
-rw-r--r--qemu-img.c1777
-rw-r--r--qemu-options.hx41
-rw-r--r--rust/qemu-api/src/bindings.rs3
-rw-r--r--scripts/qapi/parser.py48
-rw-r--r--scripts/qapi/schema.py3
-rw-r--r--storage-daemon/qapi/qapi-schema.json8
-rw-r--r--system/cpus.c2
-rw-r--r--system/memory.c2
-rw-r--r--system/qtest.c1
-rw-r--r--system/runstate.c40
-rw-r--r--system/tpm.c5
-rw-r--r--target-info-stub.c2
-rw-r--r--target-info.c23
-rw-r--r--target/alpha/cpu.c1
-rw-r--r--target/arm/arm-qmp-cmds.c3
-rw-r--r--target/arm/cpu.c1
-rw-r--r--target/i386/nvmm/nvmm-accel-ops.c2
-rw-r--r--target/i386/nvmm/nvmm-all.c1
-rw-r--r--target/i386/tcg/system/excp_helper.c1
-rw-r--r--target/i386/whpx/whpx-accel-ops.c2
-rw-r--r--target/i386/whpx/whpx-all.c1
-rw-r--r--target/i386/xsave_helper.c1
-rw-r--r--target/loongarch/loongarch-qmp-cmds.c3
-rw-r--r--target/mips/cpu-defs.c.inc10
-rw-r--r--target/mips/helper.h2
-rw-r--r--target/mips/meson.build1
-rw-r--r--target/mips/system/mips-qmp-cmds.c3
-rw-r--r--target/mips/tcg/micromips_translate.c.inc2
-rw-r--r--target/mips/tcg/msa_translate.c4
-rw-r--r--target/mips/tcg/nanomips_translate.c.inc7
-rw-r--r--target/mips/tcg/octeon.decode8
-rw-r--r--target/mips/tcg/octeon_translate.c12
-rw-r--r--target/mips/tcg/op_helper.c26
-rw-r--r--target/mips/tcg/rel6.decode5
-rw-r--r--target/mips/tcg/rel6_translate.c16
-rw-r--r--target/mips/tcg/translate.c102
-rw-r--r--target/mips/tcg/translate.h4
-rw-r--r--target/mips/tcg/translate_addr_const.c4
-rw-r--r--target/ppc/mmu-hash64.h2
-rw-r--r--target/riscv/vector_helper.c1
-rw-r--r--target/sparc/cpu.c1
-rw-r--r--tests/data/acpi/aarch64/virt/DSDTbin5196 -> 5293 bytes
-rw-r--r--tests/data/acpi/aarch64/virt/DSDT.acpihmatvirtbin5282 -> 5379 bytes
-rw-r--r--tests/data/acpi/aarch64/virt/DSDT.acpipcihpbin0 -> 6202 bytes
-rw-r--r--tests/data/acpi/aarch64/virt/DSDT.hpoffacpiindexbin0 -> 5347 bytes
-rw-r--r--tests/data/acpi/aarch64/virt/DSDT.memhpbin6557 -> 6654 bytes
-rw-r--r--tests/data/acpi/aarch64/virt/DSDT.pxbbin7679 -> 7768 bytes
-rw-r--r--tests/data/acpi/aarch64/virt/DSDT.topologybin5398 -> 5495 bytes
-rw-r--r--tests/data/acpi/aarch64/virt/DSDT.viotbin0 -> 5310 bytes
-rw-r--r--tests/data/acpi/aarch64/virt/PPTTbin76 -> 96 bytes
-rw-r--r--tests/data/acpi/aarch64/virt/PPTT.acpihmatvirtbin156 -> 176 bytes
-rw-r--r--tests/data/acpi/aarch64/virt/PPTT.topologybin336 -> 356 bytes
-rw-r--r--tests/data/acpi/loongarch64/virt/APICbin0 -> 108 bytes
-rw-r--r--tests/data/acpi/loongarch64/virt/APIC.topologybin0 -> 153 bytes
-rw-r--r--tests/data/acpi/loongarch64/virt/DSDTbin0 -> 4603 bytes
-rw-r--r--tests/data/acpi/loongarch64/virt/DSDT.memhpbin0 -> 5824 bytes
-rw-r--r--tests/data/acpi/loongarch64/virt/DSDT.numamembin0 -> 4609 bytes
-rw-r--r--tests/data/acpi/loongarch64/virt/DSDT.topologybin0 -> 4905 bytes
-rw-r--r--tests/data/acpi/loongarch64/virt/FACPbin0 -> 268 bytes
-rw-r--r--tests/data/acpi/loongarch64/virt/MCFGbin0 -> 60 bytes
-rw-r--r--tests/data/acpi/loongarch64/virt/PPTTbin0 -> 96 bytes
-rw-r--r--tests/data/acpi/loongarch64/virt/PPTT.topologybin0 -> 196 bytes
-rw-r--r--tests/data/acpi/loongarch64/virt/SLIT (renamed from tests/qapi-schema/doc-bad-section.out)0
-rw-r--r--tests/data/acpi/loongarch64/virt/SLIT.numamembin0 -> 48 bytes
-rw-r--r--tests/data/acpi/loongarch64/virt/SPCRbin0 -> 80 bytes
-rw-r--r--tests/data/acpi/loongarch64/virt/SRATbin0 -> 104 bytes
-rw-r--r--tests/data/acpi/loongarch64/virt/SRAT.memhpbin0 -> 144 bytes
-rw-r--r--tests/data/acpi/loongarch64/virt/SRAT.numamembin0 -> 144 bytes
-rw-r--r--tests/data/acpi/loongarch64/virt/SRAT.topologybin0 -> 152 bytes
-rwxr-xr-xtests/data/acpi/rebuild-expected-aml.sh4
-rw-r--r--tests/data/acpi/riscv64/virt/DSDTbin3576 -> 3538 bytes
-rw-r--r--tests/data/acpi/x86/microvm/DSDT.pciebin3023 -> 2985 bytes
-rw-r--r--tests/qapi-schema/doc-bad-section.err1
-rw-r--r--tests/qapi-schema/doc-bad-section.json10
-rw-r--r--tests/qapi-schema/doc-good.json10
-rw-r--r--tests/qapi-schema/doc-good.out10
-rw-r--r--tests/qapi-schema/doc-good.txt274
-rw-r--r--tests/qapi-schema/meson.build1
-rw-r--r--tests/qemu-iotests/049.out9
-rwxr-xr-xtests/qemu-iotests/1532
-rw-r--r--tests/qemu-iotests/153.out36
-rwxr-xr-xtests/qemu-iotests/1782
-rw-r--r--tests/qemu-iotests/178.out.qcow23
-rw-r--r--tests/qemu-iotests/178.out.raw3
-rw-r--r--tests/qemu-iotests/184.out8
-rw-r--r--tests/qemu-iotests/common.filter6
-rwxr-xr-xtests/qemu-iotests/tests/qom-set-drive75
-rw-r--r--tests/qemu-iotests/tests/qom-set-drive.out11
-rw-r--r--tests/qtest/bios-tables-test.c174
-rw-r--r--tests/qtest/meson.build1
-rw-r--r--tests/tcg/mips/include/wrappers_mips64r6.h32
-rw-r--r--tests/tcg/mips/user/isa/mips64r6/crc/Makefile40
-rw-r--r--tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32b.c142
-rw-r--r--tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32cb.c142
-rw-r--r--tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32cd.c142
-rw-r--r--tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32ch.c142
-rw-r--r--tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32cw.c142
-rw-r--r--tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32d.c142
-rw-r--r--tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32h.c142
-rw-r--r--tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32w.c142
-rw-r--r--tests/tcg/plugins/mem.c1
-rw-r--r--tests/unit/test-bdrv-drain.c46
-rw-r--r--tests/unit/test-bdrv-graph-mod.c20
-rw-r--r--ui/console-gl.c54
-rw-r--r--ui/egl-helpers.c6
-rw-r--r--ui/gtk.c58
-rw-r--r--ui/spice-core.c32
-rw-r--r--ui/spice-display.c226
-rw-r--r--ui/vnc-enc-tight.c456
-rw-r--r--ui/vnc-enc-zlib.c47
-rw-r--r--ui/vnc-enc-zrle.c122
-rw-r--r--ui/vnc-enc-zrle.c.inc20
-rw-r--r--ui/vnc-jobs.c13
-rw-r--r--ui/vnc.c83
-rw-r--r--ui/vnc.h49
372 files changed, 8260 insertions, 4336 deletions
diff --git a/.gitlab-ci.d/check-units.py b/.gitlab-ci.d/check-units.py
index 268a411..cebef0e 100755
--- a/.gitlab-ci.d/check-units.py
+++ b/.gitlab-ci.d/check-units.py
@@ -8,8 +8,10 @@
# SPDX-License-Identifier: GPL-2.0-or-later
from os import access, R_OK, path
-from sys import argv, exit
+from sys import exit
import json
+import argparse
+from pathlib import Path
from collections import Counter
@@ -28,7 +30,7 @@ def extract_build_units(cc_path):
return build_units
-def analyse_units(build_units):
+def analyse_units(build_units, top_n):
"""
Analyse the build units and report stats and the top 10 rebuilds
"""
@@ -42,7 +44,7 @@ def analyse_units(build_units):
reverse=True)
print("Most rebuilt units:")
- for unit, count in sorted_build_units[:20]:
+ for unit, count in sorted_build_units[:top_n]:
print(f" {unit} built {count} times")
print("Least rebuilt units:")
@@ -51,16 +53,19 @@ def analyse_units(build_units):
if __name__ == "__main__":
- if len(argv) != 2:
- script_name = path.basename(argv[0])
- print(f"Usage: {script_name} <path_to_compile_commands.json>")
- exit(1)
+ parser = argparse.ArgumentParser(
+ description="analyse number of build units in compile_commands.json")
+ parser.add_argument("cc_path", type=Path, default=None,
+ help="Path to compile_commands.json")
+ parser.add_argument("-n", type=int, default=20,
+ help="Dump the top <n> entries")
+
+ args = parser.parse_args()
- cc_path = argv[1]
- if path.isfile(cc_path) and access(cc_path, R_OK):
- units = extract_build_units(cc_path)
- analyse_units(units)
+ if path.isfile(args.cc_path) and access(args.cc_path, R_OK):
+ units = extract_build_units(args.cc_path)
+ analyse_units(units, args.n)
exit(0)
else:
- print(f"{cc_path} doesn't exist or isn't readable")
+ print(f"{args.cc_path} doesn't exist or isn't readable")
exit(1)
diff --git a/MAINTAINERS b/MAINTAINERS
index e88ed2c..bc0af3e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -502,13 +502,14 @@ F: include/exec/target_long.h
F: include/qemu/accel.h
F: include/system/accel-*.h
F: include/system/cpus.h
-F: include/accel/accel-cpu*.h
+F: include/accel/accel-*.h
F: accel/accel-*.?
F: accel/dummy-cpus.?
F: accel/Makefile.objs
F: accel/stubs/Makefile.objs
F: cpu-common.c
F: cpu-target.c
+F: qapi/accelerator.json
F: system/cpus.c
Apple Silicon HVF CPUs
@@ -4287,6 +4288,7 @@ F: tests/functional/test_multiprocess.py
VFIO-USER:
M: John Levon <john.levon@nutanix.com>
M: Thanos Makatos <thanos.makatos@nutanix.com>
+M: Cédric Le Goater <clg@redhat.com>
S: Supported
F: docs/interop/vfio-user.rst
F: docs/system/devices/vfio-user.rst
diff --git a/accel/accel-common.c b/accel/accel-common.c
index 591ff4c..850c5ab 100644
--- a/accel/accel-common.c
+++ b/accel/accel-common.c
@@ -10,7 +10,9 @@
#include "qemu/osdep.h"
#include "qemu/accel.h"
#include "qemu/target-info.h"
+#include "accel/accel-ops.h"
#include "accel/accel-cpu.h"
+#include "accel/accel-cpu-ops.h"
#include "accel-internal.h"
/* Lookup AccelClass from opt_name. Returns NULL if not found */
diff --git a/accel/accel-qmp.c b/accel/accel-qmp.c
new file mode 100644
index 0000000..5fb70c6
--- /dev/null
+++ b/accel/accel-qmp.c
@@ -0,0 +1,35 @@
+/*
+ * QMP commands related to accelerators
+ *
+ * Copyright (c) Linaro
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/accel.h"
+#include "qapi/type-helpers.h"
+#include "qapi/qapi-commands-accelerator.h"
+#include "accel/accel-ops.h"
+#include "accel/accel-cpu-ops.h"
+#include "hw/core/cpu.h"
+
+HumanReadableText *qmp_x_accel_stats(Error **errp)
+{
+ AccelState *accel = current_accel();
+ AccelClass *acc = ACCEL_GET_CLASS(accel);
+ g_autoptr(GString) buf = g_string_new("");
+
+ if (acc->get_stats) {
+ acc->get_stats(accel, buf);
+ }
+ if (acc->ops->get_vcpu_stats) {
+ CPUState *cpu;
+
+ CPU_FOREACH(cpu) {
+ acc->ops->get_vcpu_stats(cpu, buf);
+ }
+ }
+
+ return human_readable_text_from_str(buf);
+}
diff --git a/accel/accel-system.c b/accel/accel-system.c
index c54c30f..1e97c64 100644
--- a/accel/accel-system.c
+++ b/accel/accel-system.c
@@ -25,8 +25,12 @@
#include "qemu/osdep.h"
#include "qemu/accel.h"
+#include "qapi/qapi-commands-accelerator.h"
+#include "monitor/monitor.h"
#include "hw/boards.h"
-#include "system/accel-ops.h"
+#include "hw/core/cpu.h"
+#include "accel/accel-ops.h"
+#include "accel/accel-cpu-ops.h"
#include "system/cpus.h"
#include "qemu/error-report.h"
#include "accel-internal.h"
@@ -101,11 +105,17 @@ void accel_init_ops_interfaces(AccelClass *ac)
cpus_register_accel(ops);
}
+static void accel_ops_class_init(ObjectClass *oc, const void *data)
+{
+ monitor_register_hmp_info_hrt("accel", qmp_x_accel_stats);
+}
+
static const TypeInfo accel_ops_type_info = {
.name = TYPE_ACCEL_OPS,
.parent = TYPE_OBJECT,
.abstract = true,
.class_size = sizeof(AccelOpsClass),
+ .class_init = accel_ops_class_init,
};
static void accel_system_register_types(void)
diff --git a/accel/hvf/hvf-accel-ops.c b/accel/hvf/hvf-accel-ops.c
index be8724a..d488d6a 100644
--- a/accel/hvf/hvf-accel-ops.c
+++ b/accel/hvf/hvf-accel-ops.c
@@ -54,10 +54,11 @@
#include "gdbstub/enums.h"
#include "exec/cpu-common.h"
#include "hw/core/cpu.h"
-#include "system/accel-ops.h"
+#include "accel/accel-cpu-ops.h"
#include "system/cpus.h"
#include "system/hvf.h"
#include "system/hvf_int.h"
+#include <mach/mach_time.h>
HVFState *hvf_state;
@@ -118,6 +119,12 @@ static void dummy_signal(int sig)
{
}
+static void do_hvf_get_vcpu_exec_time(CPUState *cpu, run_on_cpu_data arg)
+{
+ int r = hv_vcpu_get_exec_time(cpu->accel->fd, arg.host_ptr);
+ assert_hvf_ok(r);
+}
+
static void hvf_vcpu_destroy(CPUState *cpu)
{
hv_return_t ret = hv_vcpu_destroy(cpu->accel->fd);
@@ -347,6 +354,21 @@ static void hvf_remove_all_breakpoints(CPUState *cpu)
}
}
+static void hvf_get_vcpu_stats(CPUState *cpu, GString *buf)
+{
+ uint64_t time_mach; /* units of mach_absolute_time() */
+
+ run_on_cpu(cpu, do_hvf_get_vcpu_exec_time, RUN_ON_CPU_HOST_PTR(&time_mach));
+
+ mach_timebase_info_data_t timebase;
+ mach_timebase_info(&timebase);
+ uint64_t time_ns = time_mach * timebase.numer / timebase.denom;
+
+ g_string_append_printf(buf, "HVF cumulative execution time: %llu.%.3llus\n",
+ time_ns / 1000000000,
+ (time_ns % 1000000000) / 1000000);
+}
+
static void hvf_accel_ops_class_init(ObjectClass *oc, const void *data)
{
AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
@@ -365,7 +387,10 @@ static void hvf_accel_ops_class_init(ObjectClass *oc, const void *data)
ops->remove_all_breakpoints = hvf_remove_all_breakpoints;
ops->update_guest_debug = hvf_update_guest_debug;
ops->supports_guest_debug = hvf_arch_supports_guest_debug;
+
+ ops->get_vcpu_stats = hvf_get_vcpu_stats;
};
+
static const TypeInfo hvf_accel_ops_type = {
.name = ACCEL_OPS_NAME("hvf"),
diff --git a/accel/hvf/hvf-all.c b/accel/hvf/hvf-all.c
index 1fa07c8..e67a810 100644
--- a/accel/hvf/hvf-all.c
+++ b/accel/hvf/hvf-all.c
@@ -10,6 +10,7 @@
#include "qemu/osdep.h"
#include "qemu/error-report.h"
+#include "accel/accel-ops.h"
#include "system/address-spaces.h"
#include "system/memory.h"
#include "system/hvf.h"
diff --git a/accel/kvm/kvm-accel-ops.c b/accel/kvm/kvm-accel-ops.c
index 0eafc90..b709187 100644
--- a/accel/kvm/kvm-accel-ops.c
+++ b/accel/kvm/kvm-accel-ops.c
@@ -16,7 +16,7 @@
#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
-#include "system/accel-ops.h"
+#include "accel/accel-cpu-ops.h"
#include "system/kvm.h"
#include "system/kvm_int.h"
#include "system/runstate.h"
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 78fc2d2..890d5ea 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -32,6 +32,7 @@
#include "system/runstate.h"
#include "system/cpus.h"
#include "system/accel-blocker.h"
+#include "accel/accel-ops.h"
#include "qemu/bswap.h"
#include "exec/tswap.h"
#include "system/memory.h"
diff --git a/accel/meson.build b/accel/meson.build
index 5290931..25b0f10 100644
--- a/accel/meson.build
+++ b/accel/meson.build
@@ -1,6 +1,6 @@
common_ss.add(files('accel-common.c'))
specific_ss.add(files('accel-target.c'))
-system_ss.add(files('accel-system.c', 'accel-blocker.c'))
+system_ss.add(files('accel-system.c', 'accel-blocker.c', 'accel-qmp.c'))
user_ss.add(files('accel-user.c'))
subdir('tcg')
diff --git a/accel/qtest/qtest.c b/accel/qtest/qtest.c
index 2b83126..1d4337d 100644
--- a/accel/qtest/qtest.c
+++ b/accel/qtest/qtest.c
@@ -18,7 +18,8 @@
#include "qemu/option.h"
#include "qemu/config-file.h"
#include "qemu/accel.h"
-#include "system/accel-ops.h"
+#include "accel/accel-ops.h"
+#include "accel/accel-cpu-ops.h"
#include "system/qtest.h"
#include "system/cpus.h"
#include "qemu/guest-random.h"
diff --git a/accel/tcg/internal-common.h b/accel/tcg/internal-common.h
index 77a3a06..6adfeef 100644
--- a/accel/tcg/internal-common.h
+++ b/accel/tcg/internal-common.h
@@ -139,6 +139,6 @@ G_NORETURN void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr);
void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr);
void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr);
-void tcg_dump_stats(GString *buf);
+void tcg_get_stats(AccelState *accel, GString *buf);
#endif
diff --git a/accel/tcg/meson.build b/accel/tcg/meson.build
index 575e92b..002aa8f 100644
--- a/accel/tcg/meson.build
+++ b/accel/tcg/meson.build
@@ -11,6 +11,7 @@ tcg_ss.add(files(
'tcg-runtime-gvec.c',
'tb-maint.c',
'tcg-all.c',
+ 'tcg-stats.c',
'translate-all.c',
'translator.c',
))
diff --git a/accel/tcg/monitor.c b/accel/tcg/monitor.c
index e7ed728..be5c195 100644
--- a/accel/tcg/monitor.c
+++ b/accel/tcg/monitor.c
@@ -7,205 +7,13 @@
*/
#include "qemu/osdep.h"
-#include "qemu/accel.h"
-#include "qemu/qht.h"
#include "qapi/error.h"
#include "qapi/type-helpers.h"
#include "qapi/qapi-commands-machine.h"
#include "monitor/monitor.h"
-#include "system/cpu-timers.h"
-#include "exec/icount.h"
#include "system/tcg.h"
#include "tcg/tcg.h"
#include "internal-common.h"
-#include "tb-context.h"
-
-
-static void dump_drift_info(GString *buf)
-{
- if (!icount_enabled()) {
- return;
- }
-
- g_string_append_printf(buf, "Host - Guest clock %"PRIi64" ms\n",
- (cpu_get_clock() - icount_get()) / SCALE_MS);
- if (icount_align_option) {
- g_string_append_printf(buf, "Max guest delay %"PRIi64" ms\n",
- -max_delay / SCALE_MS);
- g_string_append_printf(buf, "Max guest advance %"PRIi64" ms\n",
- max_advance / SCALE_MS);
- } else {
- g_string_append_printf(buf, "Max guest delay NA\n");
- g_string_append_printf(buf, "Max guest advance NA\n");
- }
-}
-
-static void dump_accel_info(GString *buf)
-{
- AccelState *accel = current_accel();
- bool one_insn_per_tb = object_property_get_bool(OBJECT(accel),
- "one-insn-per-tb",
- &error_fatal);
-
- g_string_append_printf(buf, "Accelerator settings:\n");
- g_string_append_printf(buf, "one-insn-per-tb: %s\n\n",
- one_insn_per_tb ? "on" : "off");
-}
-
-static void print_qht_statistics(struct qht_stats hst, GString *buf)
-{
- uint32_t hgram_opts;
- size_t hgram_bins;
- char *hgram;
-
- if (!hst.head_buckets) {
- return;
- }
- g_string_append_printf(buf, "TB hash buckets %zu/%zu "
- "(%0.2f%% head buckets used)\n",
- hst.used_head_buckets, hst.head_buckets,
- (double)hst.used_head_buckets /
- hst.head_buckets * 100);
-
- hgram_opts = QDIST_PR_BORDER | QDIST_PR_LABELS;
- hgram_opts |= QDIST_PR_100X | QDIST_PR_PERCENT;
- if (qdist_xmax(&hst.occupancy) - qdist_xmin(&hst.occupancy) == 1) {
- hgram_opts |= QDIST_PR_NODECIMAL;
- }
- hgram = qdist_pr(&hst.occupancy, 10, hgram_opts);
- g_string_append_printf(buf, "TB hash occupancy %0.2f%% avg chain occ. "
- "Histogram: %s\n",
- qdist_avg(&hst.occupancy) * 100, hgram);
- g_free(hgram);
-
- hgram_opts = QDIST_PR_BORDER | QDIST_PR_LABELS;
- hgram_bins = qdist_xmax(&hst.chain) - qdist_xmin(&hst.chain);
- if (hgram_bins > 10) {
- hgram_bins = 10;
- } else {
- hgram_bins = 0;
- hgram_opts |= QDIST_PR_NODECIMAL | QDIST_PR_NOBINRANGE;
- }
- hgram = qdist_pr(&hst.chain, hgram_bins, hgram_opts);
- g_string_append_printf(buf, "TB hash avg chain %0.3f buckets. "
- "Histogram: %s\n",
- qdist_avg(&hst.chain), hgram);
- g_free(hgram);
-}
-
-struct tb_tree_stats {
- size_t nb_tbs;
- size_t host_size;
- size_t target_size;
- size_t max_target_size;
- size_t direct_jmp_count;
- size_t direct_jmp2_count;
- size_t cross_page;
-};
-
-static gboolean tb_tree_stats_iter(gpointer key, gpointer value, gpointer data)
-{
- const TranslationBlock *tb = value;
- struct tb_tree_stats *tst = data;
-
- tst->nb_tbs++;
- tst->host_size += tb->tc.size;
- tst->target_size += tb->size;
- if (tb->size > tst->max_target_size) {
- tst->max_target_size = tb->size;
- }
- if (tb->page_addr[1] != -1) {
- tst->cross_page++;
- }
- if (tb->jmp_reset_offset[0] != TB_JMP_OFFSET_INVALID) {
- tst->direct_jmp_count++;
- if (tb->jmp_reset_offset[1] != TB_JMP_OFFSET_INVALID) {
- tst->direct_jmp2_count++;
- }
- }
- return false;
-}
-
-static void tlb_flush_counts(size_t *pfull, size_t *ppart, size_t *pelide)
-{
- CPUState *cpu;
- size_t full = 0, part = 0, elide = 0;
-
- CPU_FOREACH(cpu) {
- full += qatomic_read(&cpu->neg.tlb.c.full_flush_count);
- part += qatomic_read(&cpu->neg.tlb.c.part_flush_count);
- elide += qatomic_read(&cpu->neg.tlb.c.elide_flush_count);
- }
- *pfull = full;
- *ppart = part;
- *pelide = elide;
-}
-
-static void tcg_dump_flush_info(GString *buf)
-{
- size_t flush_full, flush_part, flush_elide;
-
- g_string_append_printf(buf, "TB flush count %u\n",
- qatomic_read(&tb_ctx.tb_flush_count));
- g_string_append_printf(buf, "TB invalidate count %u\n",
- qatomic_read(&tb_ctx.tb_phys_invalidate_count));
-
- tlb_flush_counts(&flush_full, &flush_part, &flush_elide);
- g_string_append_printf(buf, "TLB full flushes %zu\n", flush_full);
- g_string_append_printf(buf, "TLB partial flushes %zu\n", flush_part);
- g_string_append_printf(buf, "TLB elided flushes %zu\n", flush_elide);
-}
-
-static void dump_exec_info(GString *buf)
-{
- struct tb_tree_stats tst = {};
- struct qht_stats hst;
- size_t nb_tbs;
-
- tcg_tb_foreach(tb_tree_stats_iter, &tst);
- nb_tbs = tst.nb_tbs;
- /* XXX: avoid using doubles ? */
- g_string_append_printf(buf, "Translation buffer state:\n");
- /*
- * Report total code size including the padding and TB structs;
- * otherwise users might think "-accel tcg,tb-size" is not honoured.
- * For avg host size we use the precise numbers from tb_tree_stats though.
- */
- g_string_append_printf(buf, "gen code size %zu/%zu\n",
- tcg_code_size(), tcg_code_capacity());
- g_string_append_printf(buf, "TB count %zu\n", nb_tbs);
- g_string_append_printf(buf, "TB avg target size %zu max=%zu bytes\n",
- nb_tbs ? tst.target_size / nb_tbs : 0,
- tst.max_target_size);
- g_string_append_printf(buf, "TB avg host size %zu bytes "
- "(expansion ratio: %0.1f)\n",
- nb_tbs ? tst.host_size / nb_tbs : 0,
- tst.target_size ?
- (double)tst.host_size / tst.target_size : 0);
- g_string_append_printf(buf, "cross page TB count %zu (%zu%%)\n",
- tst.cross_page,
- nb_tbs ? (tst.cross_page * 100) / nb_tbs : 0);
- g_string_append_printf(buf, "direct jump count %zu (%zu%%) "
- "(2 jumps=%zu %zu%%)\n",
- tst.direct_jmp_count,
- nb_tbs ? (tst.direct_jmp_count * 100) / nb_tbs : 0,
- tst.direct_jmp2_count,
- nb_tbs ? (tst.direct_jmp2_count * 100) / nb_tbs : 0);
-
- qht_statistics_init(&tb_ctx.htable, &hst);
- print_qht_statistics(hst, buf);
- qht_statistics_destroy(&hst);
-
- g_string_append_printf(buf, "\nStatistics:\n");
- tcg_dump_flush_info(buf);
-}
-
-void tcg_dump_stats(GString *buf)
-{
- dump_accel_info(buf);
- dump_exec_info(buf);
- dump_drift_info(buf);
-}
HumanReadableText *qmp_x_query_jit(Error **errp)
{
diff --git a/accel/tcg/tcg-accel-ops-rr.c b/accel/tcg/tcg-accel-ops-rr.c
index a578698..6eec5c9 100644
--- a/accel/tcg/tcg-accel-ops-rr.c
+++ b/accel/tcg/tcg-accel-ops-rr.c
@@ -302,8 +302,6 @@ static void *rr_cpu_thread_fn(void *arg)
rr_deal_with_unplugged_cpus();
}
- rcu_unregister_thread();
-
g_assert_not_reached();
}
diff --git a/accel/tcg/tcg-accel-ops.c b/accel/tcg/tcg-accel-ops.c
index 279dbfa..3b0d7d2 100644
--- a/accel/tcg/tcg-accel-ops.c
+++ b/accel/tcg/tcg-accel-ops.c
@@ -26,7 +26,8 @@
*/
#include "qemu/osdep.h"
-#include "system/accel-ops.h"
+#include "accel/accel-ops.h"
+#include "accel/accel-cpu-ops.h"
#include "system/tcg.h"
#include "system/replay.h"
#include "exec/icount.h"
diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c
index 5904582..5125e1a 100644
--- a/accel/tcg/tcg-all.c
+++ b/accel/tcg/tcg-all.c
@@ -39,6 +39,8 @@
#ifndef CONFIG_USER_ONLY
#include "hw/boards.h"
#endif
+#include "accel/accel-ops.h"
+#include "accel/accel-cpu-ops.h"
#include "accel/tcg/cpu-ops.h"
#include "internal-common.h"
@@ -241,6 +243,7 @@ static void tcg_accel_class_init(ObjectClass *oc, const void *data)
ac->init_machine = tcg_init_machine;
ac->cpu_common_realize = tcg_exec_realizefn;
ac->cpu_common_unrealize = tcg_exec_unrealizefn;
+ ac->get_stats = tcg_get_stats;
ac->allowed = &tcg_allowed;
ac->gdbstub_supported_sstep_flags = tcg_gdbstub_supported_sstep_flags;
diff --git a/accel/tcg/tcg-stats.c b/accel/tcg/tcg-stats.c
new file mode 100644
index 0000000..ced5dec
--- /dev/null
+++ b/accel/tcg/tcg-stats.c
@@ -0,0 +1,219 @@
+/*
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * QEMU TCG statistics
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/accel.h"
+#include "qemu/qht.h"
+#include "qapi/error.h"
+#include "system/cpu-timers.h"
+#include "exec/icount.h"
+#include "hw/core/cpu.h"
+#include "tcg/tcg.h"
+#include "internal-common.h"
+#include "tb-context.h"
+#include <math.h>
+
+static void dump_drift_info(GString *buf)
+{
+ if (!icount_enabled()) {
+ return;
+ }
+
+ g_string_append_printf(buf, "Host - Guest clock %"PRIi64" ms\n",
+ (cpu_get_clock() - icount_get()) / SCALE_MS);
+ if (icount_align_option) {
+ g_string_append_printf(buf, "Max guest delay %"PRIi64" ms\n",
+ -max_delay / SCALE_MS);
+ g_string_append_printf(buf, "Max guest advance %"PRIi64" ms\n",
+ max_advance / SCALE_MS);
+ } else {
+ g_string_append_printf(buf, "Max guest delay NA\n");
+ g_string_append_printf(buf, "Max guest advance NA\n");
+ }
+}
+
+static void dump_accel_info(AccelState *accel, GString *buf)
+{
+ bool one_insn_per_tb = object_property_get_bool(OBJECT(accel),
+ "one-insn-per-tb",
+ &error_fatal);
+
+ g_string_append_printf(buf, "Accelerator settings:\n");
+ g_string_append_printf(buf, "one-insn-per-tb: %s\n\n",
+ one_insn_per_tb ? "on" : "off");
+}
+
+static void print_qht_statistics(struct qht_stats hst, GString *buf)
+{
+ uint32_t hgram_opts;
+ size_t hgram_bins;
+ char *hgram;
+ double avg;
+
+ if (!hst.head_buckets) {
+ return;
+ }
+ g_string_append_printf(buf, "TB hash buckets %zu/%zu "
+ "(%0.2f%% head buckets used)\n",
+ hst.used_head_buckets, hst.head_buckets,
+ (double)hst.used_head_buckets /
+ hst.head_buckets * 100);
+
+ hgram_opts = QDIST_PR_BORDER | QDIST_PR_LABELS;
+ hgram_opts |= QDIST_PR_100X | QDIST_PR_PERCENT;
+ if (qdist_xmax(&hst.occupancy) - qdist_xmin(&hst.occupancy) == 1) {
+ hgram_opts |= QDIST_PR_NODECIMAL;
+ }
+ hgram = qdist_pr(&hst.occupancy, 10, hgram_opts);
+ avg = qdist_avg(&hst.occupancy);
+ if (!isnan(avg)) {
+ g_string_append_printf(buf, "TB hash occupancy "
+ "%0.2f%% avg chain occ. "
+ "Histogram: %s\n",
+ avg * 100, hgram);
+ }
+ g_free(hgram);
+
+ hgram_opts = QDIST_PR_BORDER | QDIST_PR_LABELS;
+ hgram_bins = qdist_xmax(&hst.chain) - qdist_xmin(&hst.chain);
+ if (hgram_bins > 10) {
+ hgram_bins = 10;
+ } else {
+ hgram_bins = 0;
+ hgram_opts |= QDIST_PR_NODECIMAL | QDIST_PR_NOBINRANGE;
+ }
+ hgram = qdist_pr(&hst.chain, hgram_bins, hgram_opts);
+ avg = qdist_avg(&hst.chain);
+ if (!isnan(avg)) {
+ g_string_append_printf(buf, "TB hash avg chain %0.3f buckets. "
+ "Histogram: %s\n",
+ avg, hgram);
+ }
+ g_free(hgram);
+}
+
+struct tb_tree_stats {
+ size_t nb_tbs;
+ size_t host_size;
+ size_t target_size;
+ size_t max_target_size;
+ size_t direct_jmp_count;
+ size_t direct_jmp2_count;
+ size_t cross_page;
+};
+
+static gboolean tb_tree_stats_iter(gpointer key, gpointer value, gpointer data)
+{
+ const TranslationBlock *tb = value;
+ struct tb_tree_stats *tst = data;
+
+ tst->nb_tbs++;
+ tst->host_size += tb->tc.size;
+ tst->target_size += tb->size;
+ if (tb->size > tst->max_target_size) {
+ tst->max_target_size = tb->size;
+ }
+#ifndef CONFIG_USER_ONLY
+ if (tb->page_addr[1] != -1) {
+ tst->cross_page++;
+ }
+#endif
+ if (tb->jmp_reset_offset[0] != TB_JMP_OFFSET_INVALID) {
+ tst->direct_jmp_count++;
+ if (tb->jmp_reset_offset[1] != TB_JMP_OFFSET_INVALID) {
+ tst->direct_jmp2_count++;
+ }
+ }
+ return false;
+}
+
+static void tlb_flush_counts(size_t *pfull, size_t *ppart, size_t *pelide)
+{
+ CPUState *cpu;
+ size_t full = 0, part = 0, elide = 0;
+
+ CPU_FOREACH(cpu) {
+ full += qatomic_read(&cpu->neg.tlb.c.full_flush_count);
+ part += qatomic_read(&cpu->neg.tlb.c.part_flush_count);
+ elide += qatomic_read(&cpu->neg.tlb.c.elide_flush_count);
+ }
+ *pfull = full;
+ *ppart = part;
+ *pelide = elide;
+}
+
+static void tcg_dump_flush_info(GString *buf)
+{
+ size_t flush_full, flush_part, flush_elide;
+
+ g_string_append_printf(buf, "TB flush count %u\n",
+ qatomic_read(&tb_ctx.tb_flush_count));
+ g_string_append_printf(buf, "TB invalidate count %u\n",
+ qatomic_read(&tb_ctx.tb_phys_invalidate_count));
+
+ tlb_flush_counts(&flush_full, &flush_part, &flush_elide);
+ g_string_append_printf(buf, "TLB full flushes %zu\n", flush_full);
+ g_string_append_printf(buf, "TLB partial flushes %zu\n", flush_part);
+ g_string_append_printf(buf, "TLB elided flushes %zu\n", flush_elide);
+}
+
+static void dump_exec_info(GString *buf)
+{
+ struct tb_tree_stats tst = {};
+ struct qht_stats hst;
+ size_t nb_tbs;
+
+ tcg_tb_foreach(tb_tree_stats_iter, &tst);
+ nb_tbs = tst.nb_tbs;
+ /* XXX: avoid using doubles ? */
+ g_string_append_printf(buf, "Translation buffer state:\n");
+ /*
+ * Report total code size including the padding and TB structs;
+ * otherwise users might think "-accel tcg,tb-size" is not honoured.
+ * For avg host size we use the precise numbers from tb_tree_stats though.
+ */
+ g_string_append_printf(buf, "gen code size %zu/%zu\n",
+ tcg_code_size(), tcg_code_capacity());
+ g_string_append_printf(buf, "TB count %zu\n", nb_tbs);
+ g_string_append_printf(buf, "TB avg target size %zu max=%zu bytes\n",
+ nb_tbs ? tst.target_size / nb_tbs : 0,
+ tst.max_target_size);
+ g_string_append_printf(buf, "TB avg host size %zu bytes "
+ "(expansion ratio: %0.1f)\n",
+ nb_tbs ? tst.host_size / nb_tbs : 0,
+ tst.target_size ?
+ (double)tst.host_size / tst.target_size : 0);
+ g_string_append_printf(buf, "cross page TB count %zu (%zu%%)\n",
+ tst.cross_page,
+ nb_tbs ? (tst.cross_page * 100) / nb_tbs : 0);
+ g_string_append_printf(buf, "direct jump count %zu (%zu%%) "
+ "(2 jumps=%zu %zu%%)\n",
+ tst.direct_jmp_count,
+ nb_tbs ? (tst.direct_jmp_count * 100) / nb_tbs : 0,
+ tst.direct_jmp2_count,
+ nb_tbs ? (tst.direct_jmp2_count * 100) / nb_tbs : 0);
+
+ qht_statistics_init(&tb_ctx.htable, &hst);
+ print_qht_statistics(hst, buf);
+ qht_statistics_destroy(&hst);
+
+ g_string_append_printf(buf, "\nStatistics:\n");
+ tcg_dump_flush_info(buf);
+}
+
+void tcg_get_stats(AccelState *accel, GString *buf)
+{
+ dump_accel_info(accel, buf);
+ dump_exec_info(buf);
+ dump_drift_info(buf);
+}
+
+void tcg_dump_stats(GString *buf)
+{
+ tcg_get_stats(current_accel(), buf);
+}
diff --git a/accel/xen/xen-all.c b/accel/xen/xen-all.c
index bd0ff64..97377d6 100644
--- a/accel/xen/xen-all.c
+++ b/accel/xen/xen-all.c
@@ -19,7 +19,8 @@
#include "chardev/char.h"
#include "qemu/accel.h"
#include "accel/dummy-cpus.h"
-#include "system/accel-ops.h"
+#include "accel/accel-ops.h"
+#include "accel/accel-cpu-ops.h"
#include "system/cpus.h"
#include "system/xen.h"
#include "system/runstate.h"
diff --git a/block.c b/block.c
index bfd4340..8848e9a 100644
--- a/block.c
+++ b/block.c
@@ -431,7 +431,7 @@ BlockDriverState *bdrv_new(void)
bs->block_status_cache = g_new0(BdrvBlockStatusCache, 1);
for (i = 0; i < bdrv_drain_all_count; i++) {
- bdrv_drained_begin(bs);
+ bdrv_do_drained_begin_quiesce(bs, NULL);
}
QTAILQ_INSERT_TAIL(&all_bdrv_states, bs, bs_list);
@@ -1721,14 +1721,12 @@ bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv, const char *node_name,
open_failed:
bs->drv = NULL;
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
if (bs->file != NULL) {
bdrv_unref_child(bs, bs->file);
assert(!bs->file);
}
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
g_free(bs->opaque);
bs->opaque = NULL;
@@ -3572,9 +3570,8 @@ out:
*
* All block nodes must be drained.
*/
-int bdrv_set_backing_hd_drained(BlockDriverState *bs,
- BlockDriverState *backing_hd,
- Error **errp)
+int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
+ Error **errp)
{
int ret;
Transaction *tran = tran_new();
@@ -3596,21 +3593,6 @@ out:
return ret;
}
-int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
- Error **errp)
-{
- int ret;
- GLOBAL_STATE_CODE();
-
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
- ret = bdrv_set_backing_hd_drained(bs, backing_hd, errp);
- bdrv_graph_wrunlock();
- bdrv_drain_all_end();
-
- return ret;
-}
-
/*
* Opens the backing file for a BlockDriverState if not yet open
*
@@ -3636,7 +3618,8 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
Error *local_err = NULL;
GLOBAL_STATE_CODE();
- GRAPH_RDLOCK_GUARD_MAINLOOP();
+
+ bdrv_graph_rdlock_main_loop();
if (bs->backing != NULL) {
goto free_exit;
@@ -3717,7 +3700,11 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
/* Hook up the backing file link; drop our reference, bs owns the
* backing_hd reference now */
+ bdrv_graph_rdunlock_main_loop();
+ bdrv_graph_wrlock_drained();
ret = bdrv_set_backing_hd(bs, backing_hd, errp);
+ bdrv_graph_wrunlock();
+ bdrv_graph_rdlock_main_loop();
bdrv_unref(backing_hd);
if (ret < 0) {
@@ -3729,6 +3716,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
free_exit:
g_free(backing_filename);
qobject_unref(tmp_parent_options);
+ bdrv_graph_rdunlock_main_loop();
return ret;
}
@@ -3778,13 +3766,12 @@ done:
return bs;
}
-static BdrvChild *bdrv_open_child_common(const char *filename,
- QDict *options, const char *bdref_key,
- BlockDriverState *parent,
- const BdrvChildClass *child_class,
- BdrvChildRole child_role,
- bool allow_none, bool parse_filename,
- Error **errp)
+static BdrvChild * GRAPH_UNLOCKED
+bdrv_open_child_common(const char *filename, QDict *options,
+ const char *bdref_key, BlockDriverState *parent,
+ const BdrvChildClass *child_class,
+ BdrvChildRole child_role, bool allow_none,
+ bool parse_filename, Error **errp)
{
BlockDriverState *bs;
BdrvChild *child;
@@ -3797,12 +3784,10 @@ static BdrvChild *bdrv_open_child_common(const char *filename,
return NULL;
}
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
child = bdrv_attach_child(parent, bs, bdref_key, child_class, child_role,
errp);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
return child;
}
@@ -5160,7 +5145,7 @@ static void GRAPH_UNLOCKED bdrv_reopen_abort(BDRVReopenState *reopen_state)
}
-static void bdrv_close(BlockDriverState *bs)
+static void GRAPH_UNLOCKED bdrv_close(BlockDriverState *bs)
{
BdrvAioNotifier *ban, *ban_next;
BdrvChild *child, *next;
@@ -5180,8 +5165,7 @@ static void bdrv_close(BlockDriverState *bs)
bs->drv = NULL;
}
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
bdrv_unref_child(bs, child);
}
@@ -5189,7 +5173,6 @@ static void bdrv_close(BlockDriverState *bs)
assert(!bs->backing);
assert(!bs->file);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
g_free(bs->opaque);
bs->opaque = NULL;
@@ -5515,8 +5498,7 @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
assert(!bs_new->backing);
bdrv_graph_rdunlock_main_loop();
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
child = bdrv_attach_child_noperm(bs_new, bs_top, "backing",
&child_of_bds, bdrv_backing_role(bs_new),
@@ -5537,7 +5519,6 @@ out:
bdrv_refresh_limits(bs_top, NULL, NULL);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
return ret;
}
@@ -7076,31 +7057,25 @@ bdrv_inactivate_recurse(BlockDriverState *bs, bool top_level)
return 0;
}
+/* All block nodes must be drained. */
int bdrv_inactivate(BlockDriverState *bs, Error **errp)
{
int ret;
GLOBAL_STATE_CODE();
- bdrv_drain_all_begin();
- bdrv_graph_rdlock_main_loop();
-
if (bdrv_has_bds_parent(bs, true)) {
error_setg(errp, "Node has active parent node");
- ret = -EPERM;
- goto out;
+ return -EPERM;
}
ret = bdrv_inactivate_recurse(bs, true);
if (ret < 0) {
error_setg_errno(errp, -ret, "Failed to inactivate node");
- goto out;
+ return ret;
}
-out:
- bdrv_graph_rdunlock_main_loop();
- bdrv_drain_all_end();
- return ret;
+ return 0;
}
int bdrv_inactivate_all(void)
diff --git a/block/backup.c b/block/backup.c
index 909027c..d4713fa 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -498,12 +498,10 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
block_copy_set_speed(bcs, speed);
/* Required permissions are taken by copy-before-write filter target */
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
&error_abort);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
return &job->common;
diff --git a/block/blklogwrites.c b/block/blklogwrites.c
index 70ac76f..aa1f888 100644
--- a/block/blklogwrites.c
+++ b/block/blklogwrites.c
@@ -281,11 +281,9 @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags,
ret = 0;
fail_log:
if (ret < 0) {
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
bdrv_unref_child(bs, s->log_file);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
s->log_file = NULL;
qemu_mutex_destroy(&s->mutex);
}
@@ -298,12 +296,10 @@ static void blk_log_writes_close(BlockDriverState *bs)
{
BDRVBlkLogWritesState *s = bs->opaque;
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
bdrv_unref_child(bs, s->log_file);
s->log_file = NULL;
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
qemu_mutex_destroy(&s->mutex);
}
diff --git a/block/blkverify.c b/block/blkverify.c
index 3a71f74..72efcbe 100644
--- a/block/blkverify.c
+++ b/block/blkverify.c
@@ -151,12 +151,10 @@ static void blkverify_close(BlockDriverState *bs)
{
BDRVBlkverifyState *s = bs->opaque;
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
bdrv_unref_child(bs, s->test_file);
s->test_file = NULL;
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
}
static int64_t coroutine_fn GRAPH_RDLOCK
diff --git a/block/block-backend.c b/block/block-backend.c
index 68209bb..f8d6ba6 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -889,11 +889,9 @@ void blk_remove_bs(BlockBackend *blk)
root = blk->root;
blk->root = NULL;
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
bdrv_root_unref_child(root);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
}
/*
@@ -906,8 +904,7 @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
GLOBAL_STATE_CODE();
bdrv_ref(bs);
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
if ((bs->open_flags & BDRV_O_INACTIVE) && blk_can_inactivate(blk)) {
blk->disable_perm = true;
@@ -922,7 +919,6 @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
perm, shared_perm, blk, errp);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
if (blk->root == NULL) {
return -EPERM;
}
diff --git a/block/commit.c b/block/commit.c
index 6c4b736..0d9e1a1 100644
--- a/block/commit.c
+++ b/block/commit.c
@@ -68,7 +68,7 @@ static int commit_prepare(Job *job)
s->backing_mask_protocol);
}
-static void commit_abort(Job *job)
+static void GRAPH_UNLOCKED commit_abort(Job *job)
{
CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
BlockDriverState *top_bs = blk_bs(s->top);
@@ -392,8 +392,7 @@ void commit_start(const char *job_id, BlockDriverState *bs,
* this is the responsibility of the interface (i.e. whoever calls
* commit_start()).
*/
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
s->base_overlay = bdrv_find_overlay(top, base);
assert(s->base_overlay);
@@ -425,21 +424,18 @@ void commit_start(const char *job_id, BlockDriverState *bs,
iter_shared_perms, errp);
if (ret < 0) {
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
goto fail;
}
}
if (bdrv_freeze_backing_chain(commit_top_bs, base, errp) < 0) {
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
goto fail;
}
s->chain_frozen = true;
ret = block_job_add_bdrv(&s->common, "base", base, 0, BLK_PERM_ALL, errp);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
if (ret < 0) {
goto fail;
@@ -518,28 +514,32 @@ int bdrv_commit(BlockDriverState *bs)
Error *local_err = NULL;
GLOBAL_STATE_CODE();
- GRAPH_RDLOCK_GUARD_MAINLOOP();
if (!drv)
return -ENOMEDIUM;
+ bdrv_graph_rdlock_main_loop();
+
backing_file_bs = bdrv_cow_bs(bs);
if (!backing_file_bs) {
- return -ENOTSUP;
+ ret = -ENOTSUP;
+ goto out;
}
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT_SOURCE, NULL) ||
bdrv_op_is_blocked(backing_file_bs, BLOCK_OP_TYPE_COMMIT_TARGET, NULL))
{
- return -EBUSY;
+ ret = -EBUSY;
+ goto out;
}
ro = bdrv_is_read_only(backing_file_bs);
if (ro) {
if (bdrv_reopen_set_read_only(backing_file_bs, false, NULL)) {
- return -EACCES;
+ ret = -EACCES;
+ goto out;
}
}
@@ -563,8 +563,14 @@ int bdrv_commit(BlockDriverState *bs)
goto ro_cleanup;
}
+ bdrv_graph_rdunlock_main_loop();
+
+ bdrv_graph_wrlock_drained();
bdrv_set_backing_hd(commit_top_bs, backing_file_bs, &error_abort);
bdrv_set_backing_hd(bs, commit_top_bs, &error_abort);
+ bdrv_graph_wrunlock();
+
+ bdrv_graph_rdlock_main_loop();
ret = blk_insert_bs(backing, backing_file_bs, &local_err);
if (ret < 0) {
@@ -639,9 +645,14 @@ int bdrv_commit(BlockDriverState *bs)
ret = 0;
ro_cleanup:
blk_unref(backing);
+
+ bdrv_graph_rdunlock_main_loop();
+ bdrv_graph_wrlock_drained();
if (bdrv_cow_bs(bs) != backing_file_bs) {
bdrv_set_backing_hd(bs, backing_file_bs, &error_abort);
}
+ bdrv_graph_wrunlock();
+ bdrv_graph_rdlock_main_loop();
bdrv_unref(commit_top_bs);
blk_unref(src);
@@ -650,5 +661,8 @@ ro_cleanup:
bdrv_reopen_set_read_only(backing_file_bs, true, NULL);
}
+out:
+ bdrv_graph_rdunlock_main_loop();
+
return ret;
}
diff --git a/block/file-posix.c b/block/file-posix.c
index 9b5f08c..8c73867 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -2564,9 +2564,9 @@ static inline bool raw_check_linux_aio(BDRVRawState *s)
}
#endif
-static int coroutine_fn raw_co_prw(BlockDriverState *bs, int64_t *offset_ptr,
- uint64_t bytes, QEMUIOVector *qiov, int type,
- int flags)
+static int coroutine_fn GRAPH_RDLOCK
+raw_co_prw(BlockDriverState *bs, int64_t *offset_ptr, uint64_t bytes,
+ QEMUIOVector *qiov, int type, int flags)
{
BDRVRawState *s = bs->opaque;
RawPosixAIOData acb;
@@ -2625,7 +2625,7 @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, int64_t *offset_ptr,
ret = raw_thread_pool_submit(handle_aiocb_rw, &acb);
if (ret == 0 && (flags & BDRV_REQ_FUA)) {
/* TODO Use pwritev2() instead if it's available */
- ret = raw_co_flush_to_disk(bs);
+ ret = bdrv_co_flush(bs);
}
goto out; /* Avoid the compiler err of unused label */
@@ -2660,16 +2660,16 @@ out:
return ret;
}
-static int coroutine_fn raw_co_preadv(BlockDriverState *bs, int64_t offset,
- int64_t bytes, QEMUIOVector *qiov,
- BdrvRequestFlags flags)
+static int coroutine_fn GRAPH_RDLOCK
+raw_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
+ QEMUIOVector *qiov, BdrvRequestFlags flags)
{
return raw_co_prw(bs, &offset, bytes, qiov, QEMU_AIO_READ, flags);
}
-static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, int64_t offset,
- int64_t bytes, QEMUIOVector *qiov,
- BdrvRequestFlags flags)
+static int coroutine_fn GRAPH_RDLOCK
+raw_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
+ QEMUIOVector *qiov, BdrvRequestFlags flags)
{
return raw_co_prw(bs, &offset, bytes, qiov, QEMU_AIO_WRITE, flags);
}
@@ -3606,10 +3606,11 @@ static int coroutine_fn raw_co_zone_mgmt(BlockDriverState *bs, BlockZoneOp op,
#endif
#if defined(CONFIG_BLKZONED)
-static int coroutine_fn raw_co_zone_append(BlockDriverState *bs,
- int64_t *offset,
- QEMUIOVector *qiov,
- BdrvRequestFlags flags) {
+static int coroutine_fn GRAPH_RDLOCK
+raw_co_zone_append(BlockDriverState *bs,
+ int64_t *offset,
+ QEMUIOVector *qiov,
+ BdrvRequestFlags flags) {
assert(flags == 0);
int64_t zone_size_mask = bs->bl.zone_size - 1;
int64_t iov_len = 0;
diff --git a/block/graph-lock.c b/block/graph-lock.c
index c81162b..b731947 100644
--- a/block/graph-lock.c
+++ b/block/graph-lock.c
@@ -34,6 +34,17 @@ static QemuMutex aio_context_list_lock;
static int has_writer;
/*
+ * Many write-locked sections are also drained sections. There is a convenience
+ * wrapper bdrv_graph_wrlock_drained() which begins a drained section before
+ * acquiring the lock. This variable here is used so bdrv_graph_wrunlock() knows
+ * if it also needs to end such a drained section. It needs to be a counter,
+ * because the aio_poll() call in bdrv_graph_wrlock() might re-enter
+ * bdrv_graph_wrlock_drained(). And note that aio_bh_poll() in
+ * bdrv_graph_wrunlock() might also re-enter a write-locked section.
+ */
+static int wrlock_quiesced_counter;
+
+/*
* A reader coroutine could move from an AioContext to another.
* If this happens, there is no problem from the point of view of
* counters. The problem is that the total count becomes
@@ -112,8 +123,14 @@ void no_coroutine_fn bdrv_graph_wrlock(void)
assert(!qatomic_read(&has_writer));
assert(!qemu_in_coroutine());
- /* Make sure that constantly arriving new I/O doesn't cause starvation */
- bdrv_drain_all_begin_nopoll();
+ bool need_drain = wrlock_quiesced_counter == 0;
+
+ if (need_drain) {
+ /*
+ * Make sure that constantly arriving new I/O doesn't cause starvation
+ */
+ bdrv_drain_all_begin_nopoll();
+ }
/*
* reader_count == 0: this means writer will read has_reader as 1
@@ -139,7 +156,18 @@ void no_coroutine_fn bdrv_graph_wrlock(void)
smp_mb();
} while (reader_count() >= 1);
- bdrv_drain_all_end();
+ if (need_drain) {
+ bdrv_drain_all_end();
+ }
+}
+
+void no_coroutine_fn bdrv_graph_wrlock_drained(void)
+{
+ GLOBAL_STATE_CODE();
+
+ bdrv_drain_all_begin();
+ wrlock_quiesced_counter++;
+ bdrv_graph_wrlock();
}
void no_coroutine_fn bdrv_graph_wrunlock(void)
@@ -168,6 +196,12 @@ void no_coroutine_fn bdrv_graph_wrunlock(void)
* progress.
*/
aio_bh_poll(qemu_get_aio_context());
+
+ if (wrlock_quiesced_counter > 0) {
+ bdrv_drain_all_end();
+ wrlock_quiesced_counter--;
+ }
+
}
void coroutine_fn bdrv_graph_co_rdlock(void)
diff --git a/block/io.c b/block/io.c
index ac5c717..9bd8ba8 100644
--- a/block/io.c
+++ b/block/io.c
@@ -361,7 +361,7 @@ static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent,
GLOBAL_STATE_CODE();
/* Stop things in parent-to-child order */
- if (qatomic_fetch_inc(&bs->quiesce_counter) == 0) {
+ if (bs->quiesce_counter++ == 0) {
GRAPH_RDLOCK_GUARD_MAINLOOP();
bdrv_parent_drained_begin(bs, parent);
if (bs->drv && bs->drv->bdrv_drain_begin) {
@@ -401,8 +401,6 @@ bdrv_drained_begin(BlockDriverState *bs)
*/
static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
{
- int old_quiesce_counter;
-
IO_OR_GS_CODE();
if (qemu_in_coroutine()) {
@@ -415,8 +413,7 @@ static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
assert(bs->quiesce_counter > 0);
/* Re-enable things in child-to-parent order */
- old_quiesce_counter = qatomic_fetch_dec(&bs->quiesce_counter);
- if (old_quiesce_counter == 1) {
+ if (--bs->quiesce_counter == 0) {
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (bs->drv && bs->drv->bdrv_drain_end) {
bs->drv->bdrv_drain_end(bs);
diff --git a/block/mirror.c b/block/mirror.c
index 6e8caf4..b344182 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -761,10 +761,14 @@ static int mirror_exit_common(Job *job)
bdrv_graph_rdlock_main_loop();
bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing,
&error_abort);
+ bdrv_graph_rdunlock_main_loop();
if (!abort && s->backing_mode == MIRROR_SOURCE_BACKING_CHAIN) {
BlockDriverState *backing;
- BlockDriverState *unfiltered_target = bdrv_skip_filters(target_bs);
+ BlockDriverState *unfiltered_target;
+
+ bdrv_graph_wrlock_drained();
+ unfiltered_target = bdrv_skip_filters(target_bs);
backing = s->sync_mode == MIRROR_SYNC_MODE_NONE ? src : s->base;
if (bdrv_cow_bs(unfiltered_target) != backing) {
@@ -775,16 +779,18 @@ static int mirror_exit_common(Job *job)
ret = -EPERM;
}
}
+ bdrv_graph_wrunlock();
} else if (!abort && s->backing_mode == MIRROR_OPEN_BACKING_CHAIN) {
+ bdrv_graph_rdlock_main_loop();
assert(!bdrv_backing_chain_next(target_bs));
ret = bdrv_open_backing_file(bdrv_skip_filters(target_bs), NULL,
"backing", &local_err);
+ bdrv_graph_rdunlock_main_loop();
if (ret < 0) {
error_report_err(local_err);
local_err = NULL;
}
}
- bdrv_graph_rdunlock_main_loop();
if (s->should_complete && !abort) {
BlockDriverState *to_replace = s->to_replace ?: src;
@@ -2014,15 +2020,13 @@ static BlockJob *mirror_start_job(
*/
bdrv_disable_dirty_bitmap(s->dirty_bitmap);
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
ret = block_job_add_bdrv(&s->common, "source", bs, 0,
BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE |
BLK_PERM_CONSISTENT_READ,
errp);
if (ret < 0) {
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
goto fail;
}
@@ -2068,19 +2072,16 @@ static BlockJob *mirror_start_job(
iter_shared_perms, errp);
if (ret < 0) {
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
goto fail;
}
}
if (bdrv_freeze_backing_chain(mirror_top_bs, target, errp) < 0) {
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
goto fail;
}
}
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
QTAILQ_INIT(&s->ops_in_flight);
diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
index 6919a49..282d1c3 100644
--- a/block/monitor/block-hmp-cmds.c
+++ b/block/monitor/block-hmp-cmds.c
@@ -144,7 +144,7 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict)
Error *local_err = NULL;
GLOBAL_STATE_CODE();
- GRAPH_RDLOCK_GUARD_MAINLOOP();
+ bdrv_graph_rdlock_main_loop();
bs = bdrv_find_node(id);
if (bs) {
@@ -152,29 +152,31 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict)
if (local_err) {
error_report_err(local_err);
}
- return;
+ goto unlock;
}
blk = blk_by_name(id);
if (!blk) {
error_report("Device '%s' not found", id);
- return;
+ goto unlock;
}
if (!blk_legacy_dinfo(blk)) {
error_report("Deleting device added with blockdev-add"
" is not supported");
- return;
+ goto unlock;
}
bs = blk_bs(blk);
if (bs) {
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_DRIVE_DEL, &local_err)) {
error_report_err(local_err);
- return;
+ goto unlock;
}
+ bdrv_graph_rdunlock_main_loop();
blk_remove_bs(blk);
+ bdrv_graph_rdlock_main_loop();
}
/* Make the BlockBackend and the attached BlockDriverState anonymous */
@@ -191,6 +193,9 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict)
} else {
blk_unref(blk);
}
+
+unlock:
+ bdrv_graph_rdunlock_main_loop();
}
void hmp_commit(Monitor *mon, const QDict *qdict)
diff --git a/block/qapi.c b/block/qapi.c
index 2c50a6b..12fbf8d 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -51,6 +51,8 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
ImageInfo *backing_info;
BlockDriverState *backing;
BlockDeviceInfo *info;
+ BlockdevChildList **children_list_tail;
+ BdrvChild *child;
if (!bs->drv) {
error_setg(errp, "Block device %s is ejected", bs->node_name);
@@ -73,8 +75,14 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
.no_flush = !!(bs->open_flags & BDRV_O_NO_FLUSH),
};
- if (bs->node_name[0]) {
- info->node_name = g_strdup(bs->node_name);
+ info->node_name = g_strdup(bs->node_name);
+
+ children_list_tail = &info->children;
+ QLIST_FOREACH(child, &bs->children, next) {
+ BlockdevChild *child_ref = g_new0(BlockdevChild, 1);
+ child_ref->child = g_strdup(child->name);
+ child_ref->node_name = g_strdup(child->bs->node_name);
+ QAPI_LIST_APPEND(children_list_tail, child_ref);
}
backing = bdrv_cow_bs(bs);
diff --git a/block/qcow2.c b/block/qcow2.c
index 45451a7..4aa9f9e 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -2823,11 +2823,9 @@ qcow2_do_close(BlockDriverState *bs, bool close_data_file)
if (close_data_file && has_data_file(bs)) {
GLOBAL_STATE_CODE();
bdrv_graph_rdunlock_main_loop();
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
bdrv_unref_child(bs, s->data_file);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
s->data_file = NULL;
bdrv_graph_rdlock_main_loop();
}
diff --git a/block/quorum.c b/block/quorum.c
index cc3bc5f..76a4feb 100644
--- a/block/quorum.c
+++ b/block/quorum.c
@@ -1037,8 +1037,7 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
close_exit:
/* cleanup on error */
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
for (i = 0; i < s->num_children; i++) {
if (!opened[i]) {
continue;
@@ -1046,7 +1045,6 @@ close_exit:
bdrv_unref_child(bs, s->children[i]);
}
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
g_free(s->children);
g_free(opened);
exit:
@@ -1059,13 +1057,11 @@ static void quorum_close(BlockDriverState *bs)
BDRVQuorumState *s = bs->opaque;
int i;
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
for (i = 0; i < s->num_children; i++) {
bdrv_unref_child(bs, s->children[i]);
}
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
g_free(s->children);
}
diff --git a/block/replication.c b/block/replication.c
index 0879718..3a431e9 100644
--- a/block/replication.c
+++ b/block/replication.c
@@ -364,14 +364,15 @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
BlockReopenQueue *reopen_queue = NULL;
GLOBAL_STATE_CODE();
- GRAPH_RDLOCK_GUARD_MAINLOOP();
+ bdrv_graph_rdlock_main_loop();
/*
* s->hidden_disk and s->secondary_disk may not be set yet, as they will
* only be set after the children are writable.
*/
hidden_disk = bs->file->bs->backing;
secondary_disk = hidden_disk->bs->backing;
+ bdrv_graph_rdunlock_main_loop();
if (writable) {
s->orig_hidden_read_only = bdrv_is_read_only(hidden_disk->bs);
@@ -540,8 +541,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
return;
}
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
bdrv_ref(hidden_disk->bs);
s->hidden_disk = bdrv_attach_child(bs, hidden_disk->bs, "hidden disk",
@@ -550,7 +550,6 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
if (local_err) {
error_propagate(errp, local_err);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
return;
}
@@ -561,7 +560,6 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
if (local_err) {
error_propagate(errp, local_err);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
return;
}
@@ -574,14 +572,12 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
!check_top_bs(top_bs, bs)) {
error_setg(errp, "No top_bs or it is invalid");
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
reopen_backing_file(bs, false, NULL);
return;
}
bdrv_op_block_all(top_bs, s->blocker);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
s->backup_job = backup_job_create(
NULL, s->secondary_disk->bs, s->hidden_disk->bs,
@@ -656,14 +652,12 @@ static void replication_done(void *opaque, int ret)
if (ret == 0) {
s->stage = BLOCK_REPLICATION_DONE;
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
bdrv_unref_child(bs, s->secondary_disk);
s->secondary_disk = NULL;
bdrv_unref_child(bs, s->hidden_disk);
s->hidden_disk = NULL;
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
s->error = 0;
} else {
diff --git a/block/snapshot.c b/block/snapshot.c
index 28c9c43..bd9d759 100644
--- a/block/snapshot.c
+++ b/block/snapshot.c
@@ -291,11 +291,9 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
}
/* .bdrv_open() will re-attach it */
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
bdrv_unref_child(bs, fallback);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
ret = bdrv_snapshot_goto(fallback_bs, snapshot_id, errp);
memset(bs->opaque, 0, drv->instance_size);
diff --git a/block/stream.c b/block/stream.c
index f5441f2..c0616b6 100644
--- a/block/stream.c
+++ b/block/stream.c
@@ -51,7 +51,7 @@ static int coroutine_fn stream_populate(BlockBackend *blk,
return blk_co_preadv(blk, offset, bytes, NULL, BDRV_REQ_PREFETCH);
}
-static int stream_prepare(Job *job)
+static int GRAPH_UNLOCKED stream_prepare(Job *job)
{
StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
BlockDriverState *unfiltered_bs;
@@ -73,12 +73,11 @@ static int stream_prepare(Job *job)
s->cor_filter_bs = NULL;
/*
- * bdrv_set_backing_hd() requires that the unfiltered_bs and the COW child
- * of unfiltered_bs is drained. Drain already here and use
- * bdrv_set_backing_hd_drained() instead because the polling during
- * drained_begin() might change the graph, and if we do this only later, we
- * may end up working with the wrong base node (or it might even have gone
- * away by the time we want to use it).
+ * bdrv_set_backing_hd() requires that all block nodes are drained. Drain
+ * already here, because the polling during drained_begin() might change the
+ * graph, and if we do this only later, we may end up working with the wrong
+ * base node (or it might even have gone away by the time we want to use
+ * it).
*/
if (unfiltered_bs_cow) {
bdrv_ref(unfiltered_bs_cow);
@@ -105,7 +104,7 @@ static int stream_prepare(Job *job)
}
bdrv_graph_wrlock();
- bdrv_set_backing_hd_drained(unfiltered_bs, base, &local_err);
+ bdrv_set_backing_hd(unfiltered_bs, base, &local_err);
bdrv_graph_wrunlock();
/*
@@ -371,12 +370,10 @@ void stream_start(const char *job_id, BlockDriverState *bs,
* already have our own plans. Also don't allow resize as the image size is
* queried only at the job start and then cached.
*/
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
if (block_job_add_bdrv(&s->common, "active node", bs, 0,
basic_flags | BLK_PERM_WRITE, errp)) {
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
goto fail;
}
@@ -397,12 +394,10 @@ void stream_start(const char *job_id, BlockDriverState *bs,
basic_flags, errp);
if (ret < 0) {
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
goto fail;
}
}
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
s->base_overlay = base_overlay;
s->above_base = above_base;
diff --git a/block/vmdk.c b/block/vmdk.c
index 89a7250..7b98deb 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -271,8 +271,7 @@ static void vmdk_free_extents(BlockDriverState *bs)
BDRVVmdkState *s = bs->opaque;
VmdkExtent *e;
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
for (i = 0; i < s->num_extents; i++) {
e = &s->extents[i];
g_free(e->l1_table);
@@ -284,7 +283,6 @@ static void vmdk_free_extents(BlockDriverState *bs)
}
}
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
g_free(s->extents);
}
@@ -1231,9 +1229,11 @@ vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
extent_role |= BDRV_CHILD_METADATA;
}
+ bdrv_graph_rdunlock_main_loop();
extent_file = bdrv_open_child(extent_path, options, extent_opt_prefix,
bs, &child_of_bds, extent_role, false,
&local_err);
+ bdrv_graph_rdlock_main_loop();
g_free(extent_path);
if (!extent_file) {
error_propagate(errp, local_err);
@@ -1249,11 +1249,9 @@ vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
0, 0, 0, 0, 0, &extent, errp);
if (ret < 0) {
bdrv_graph_rdunlock_main_loop();
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
bdrv_unref_child(bs, extent_file);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
bdrv_graph_rdlock_main_loop();
goto out;
}
@@ -1270,11 +1268,9 @@ vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
g_free(buf);
if (ret) {
bdrv_graph_rdunlock_main_loop();
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
bdrv_unref_child(bs, extent_file);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
bdrv_graph_rdlock_main_loop();
goto out;
}
@@ -1283,11 +1279,9 @@ vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
ret = vmdk_open_se_sparse(bs, extent_file, bs->open_flags, errp);
if (ret) {
bdrv_graph_rdunlock_main_loop();
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
bdrv_unref_child(bs, extent_file);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
bdrv_graph_rdlock_main_loop();
goto out;
}
@@ -1295,11 +1289,9 @@ vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
} else {
error_setg(errp, "Unsupported extent type '%s'", type);
bdrv_graph_rdunlock_main_loop();
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
bdrv_unref_child(bs, extent_file);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
bdrv_graph_rdlock_main_loop();
ret = -ENOTSUP;
goto out;
@@ -1362,13 +1354,13 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
BDRVVmdkState *s = bs->opaque;
uint32_t magic;
- GRAPH_RDLOCK_GUARD_MAINLOOP();
-
ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
if (ret < 0) {
return ret;
}
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
+
buf = vmdk_read_desc(bs->file, 0, errp);
if (!buf) {
return -EINVAL;
diff --git a/blockdev.c b/blockdev.c
index 2e7fda6..b451fee 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1421,7 +1421,7 @@ static void external_snapshot_action(TransactionAction *action,
bdrv_graph_rdunlock_main_loop();
/* Paired with .clean() */
bdrv_drained_begin(state->old_bs);
- GRAPH_RDLOCK_GUARD_MAINLOOP();
+ bdrv_graph_rdlock_main_loop();
/* Make sure the associated bs did not change with the drain. */
check_bs = bdrv_lookup_bs(device, node_name, errp);
@@ -1430,18 +1430,18 @@ static void external_snapshot_action(TransactionAction *action,
error_setg(errp, "Block node of device '%s' unexpectedly changed",
device);
} /* else errp is already set */
- return;
+ goto unlock;
}
if (!bdrv_is_inserted(state->old_bs)) {
error_setg(errp, "Device '%s' has no medium",
bdrv_get_device_or_node_name(state->old_bs));
- return;
+ goto unlock;
}
if (bdrv_op_is_blocked(state->old_bs,
BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT, errp)) {
- return;
+ goto unlock;
}
if (!bdrv_is_read_only(state->old_bs)) {
@@ -1449,7 +1449,7 @@ static void external_snapshot_action(TransactionAction *action,
if (ret < 0) {
error_setg_errno(errp, -ret, "Write to node '%s' failed",
bdrv_get_device_or_node_name(state->old_bs));
- return;
+ goto unlock;
}
}
@@ -1461,13 +1461,13 @@ static void external_snapshot_action(TransactionAction *action,
if (node_name && !snapshot_node_name) {
error_setg(errp, "New overlay node-name missing");
- return;
+ goto unlock;
}
if (snapshot_node_name &&
bdrv_lookup_bs(snapshot_node_name, snapshot_node_name, NULL)) {
error_setg(errp, "New overlay node-name already in use");
- return;
+ goto unlock;
}
flags = state->old_bs->open_flags;
@@ -1480,7 +1480,7 @@ static void external_snapshot_action(TransactionAction *action,
int64_t size = bdrv_getlength(state->old_bs);
if (size < 0) {
error_setg_errno(errp, -size, "bdrv_getlength failed");
- return;
+ goto unlock;
}
bdrv_refresh_filename(state->old_bs);
@@ -1491,7 +1491,7 @@ static void external_snapshot_action(TransactionAction *action,
if (local_err) {
error_propagate(errp, local_err);
- return;
+ goto unlock;
}
}
@@ -1507,7 +1507,7 @@ static void external_snapshot_action(TransactionAction *action,
/* We will manually add the backing_hd field to the bs later */
if (!state->new_bs) {
- return;
+ goto unlock;
}
/*
@@ -1518,22 +1518,22 @@ static void external_snapshot_action(TransactionAction *action,
bdrv_get_cumulative_perm(state->new_bs, &perm, &shared);
if (perm & BLK_PERM_CONSISTENT_READ) {
error_setg(errp, "The overlay is already in use");
- return;
+ goto unlock;
}
if (state->new_bs->drv->is_filter) {
error_setg(errp, "Filters cannot be used as overlays");
- return;
+ goto unlock;
}
if (bdrv_cow_child(state->new_bs)) {
error_setg(errp, "The overlay already has a backing image");
- return;
+ goto unlock;
}
if (!state->new_bs->drv->supports_backing) {
error_setg(errp, "The overlay does not support backing images");
- return;
+ goto unlock;
}
/*
@@ -1546,17 +1546,23 @@ static void external_snapshot_action(TransactionAction *action,
* to keep this working.
*/
if (bdrv_is_inactive(state->old_bs) && !bdrv_is_inactive(state->new_bs)) {
+ bdrv_graph_rdunlock_main_loop();
+ bdrv_drain_all_begin();
+ bdrv_graph_rdlock_main_loop();
ret = bdrv_inactivate(state->new_bs, errp);
+ bdrv_drain_all_end();
if (ret < 0) {
- return;
+ goto unlock;
}
}
ret = bdrv_append(state->new_bs, state->old_bs, errp);
if (ret < 0) {
- return;
+ goto unlock;
}
state->overlay_appended = true;
+unlock:
+ bdrv_graph_rdunlock_main_loop();
}
static void external_snapshot_commit(void *opaque)
@@ -1580,10 +1586,18 @@ static void external_snapshot_abort(void *opaque)
AioContext *tmp_context;
int ret;
+ bdrv_graph_wrlock_drained();
+
aio_context = bdrv_get_aio_context(state->old_bs);
- bdrv_ref(state->old_bs); /* we can't let bdrv_set_backind_hd()
- close state->old_bs; we need it */
+ /*
+ * Note that state->old_bs would not disappear during the
+ * write-locked section, because the unref from
+ * bdrv_set_backing_hd() only happens at the end of the write-locked
+ * section. However, just be explicit about keeping a reference and
+ * don't rely on that implicit detail.
+ */
+ bdrv_ref(state->old_bs);
bdrv_set_backing_hd(state->new_bs, NULL, &error_abort);
/*
@@ -1593,16 +1607,14 @@ static void external_snapshot_abort(void *opaque)
*/
tmp_context = bdrv_get_aio_context(state->old_bs);
if (aio_context != tmp_context) {
- ret = bdrv_try_change_aio_context(state->old_bs,
- aio_context, NULL, NULL);
+ ret = bdrv_try_change_aio_context_locked(state->old_bs,
+ aio_context, NULL,
+ NULL);
assert(ret == 0);
}
- bdrv_drained_begin(state->new_bs);
- bdrv_graph_wrlock();
bdrv_replace_node(state->new_bs, state->old_bs, &error_abort);
bdrv_graph_wrunlock();
- bdrv_drained_end(state->new_bs);
bdrv_unref(state->old_bs); /* bdrv_replace_node() ref'ed old_bs */
}
@@ -1770,7 +1782,10 @@ static void drive_backup_action(DriveBackup *backup,
}
if (set_backing_hd) {
- if (bdrv_set_backing_hd(target_bs, source, errp) < 0) {
+ bdrv_graph_wrlock_drained();
+ ret = bdrv_set_backing_hd(target_bs, source, errp);
+ bdrv_graph_wrunlock();
+ if (ret < 0) {
goto unref;
}
}
@@ -3511,10 +3526,10 @@ void qmp_blockdev_del(const char *node_name, Error **errp)
void qmp_blockdev_set_active(const char *node_name, bool active, Error **errp)
{
+ BlockDriverState *bs;
int ret;
GLOBAL_STATE_CODE();
- GRAPH_RDLOCK_GUARD_MAINLOOP();
if (!node_name) {
if (active) {
@@ -3525,19 +3540,30 @@ void qmp_blockdev_set_active(const char *node_name, bool active, Error **errp)
error_setg_errno(errp, -ret, "Failed to inactivate all nodes");
}
}
+ return;
+ }
+
+ if (!active) {
+ bdrv_drain_all_begin();
+ }
+ bdrv_graph_rdlock_main_loop();
+
+ bs = bdrv_find_node(node_name);
+ if (!bs) {
+ error_setg(errp, "Failed to find node with node-name='%s'",
+ node_name);
+ goto unlock;
+ }
+ if (active) {
+ bdrv_activate(bs, errp);
} else {
- BlockDriverState *bs = bdrv_find_node(node_name);
- if (!bs) {
- error_setg(errp, "Failed to find node with node-name='%s'",
- node_name);
- return;
- }
+ bdrv_inactivate(bs, errp);
+ }
- if (active) {
- bdrv_activate(bs, errp);
- } else {
- bdrv_inactivate(bs, errp);
- }
+unlock:
+ bdrv_graph_rdunlock_main_loop();
+ if (!active) {
+ bdrv_drain_all_end();
}
}
@@ -3561,8 +3587,7 @@ void qmp_x_blockdev_change(const char *parent, const char *child,
BlockDriverState *parent_bs, *new_bs = NULL;
BdrvChild *p_child;
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
parent_bs = bdrv_lookup_bs(parent, parent, errp);
if (!parent_bs) {
@@ -3599,7 +3624,6 @@ void qmp_x_blockdev_change(const char *parent, const char *child,
out:
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
}
BlockJobInfoList *qmp_query_block_jobs(Error **errp)
diff --git a/blockjob.c b/blockjob.c
index e68181a..db7c3a6 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -198,8 +198,7 @@ void block_job_remove_all_bdrv(BlockJob *job)
* one to make sure that such a concurrent access does not attempt
* to process an already freed BdrvChild.
*/
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
while (job->nodes) {
GSList *l = job->nodes;
BdrvChild *c = l->data;
@@ -212,7 +211,6 @@ void block_job_remove_all_bdrv(BlockJob *job)
g_slist_free_1(l);
}
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
}
bool block_job_has_bdrv(BlockJob *job, BlockDriverState *bs)
@@ -498,8 +496,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
int ret;
GLOBAL_STATE_CODE();
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
if (job_id == NULL && !(flags & JOB_INTERNAL)) {
job_id = bdrv_get_device_name(bs);
@@ -509,7 +506,6 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
flags, cb, opaque, errp);
if (job == NULL) {
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
return NULL;
}
@@ -548,12 +544,10 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
}
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
return job;
fail:
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
job_early_fail(&job->job);
return NULL;
}
diff --git a/bsd-user/main.c b/bsd-user/main.c
index d0cc8e0..7e5d4bb 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -38,6 +38,7 @@
#include "qemu/plugin.h"
#include "user/guest-base.h"
#include "user/page-protection.h"
+#include "accel/accel-ops.h"
#include "tcg/startup.h"
#include "qemu/timer.h"
#include "qemu/envlist.h"
diff --git a/common-user/plugin-api.c.inc b/common-user/plugin-api.c.inc
index 5b8a139..63f3983 100644
--- a/common-user/plugin-api.c.inc
+++ b/common-user/plugin-api.c.inc
@@ -13,6 +13,7 @@
#include "qemu/osdep.h"
#include "qemu/main-loop.h"
#include "qemu/plugin.h"
+#include "accel/tcg/vcpu-state.h"
#include "qemu.h"
/*
diff --git a/configs/targets/alpha-linux-user.mak b/configs/targets/alpha-linux-user.mak
index ef8e365..aa25766 100644
--- a/configs/targets/alpha-linux-user.mak
+++ b/configs/targets/alpha-linux-user.mak
@@ -2,3 +2,4 @@ TARGET_ARCH=alpha
TARGET_SYSTBL_ABI=common
TARGET_SYSTBL=syscall.tbl
TARGET_LONG_BITS=64
+TARGET_XML_FILES= gdb-xml/alpha-core.xml
diff --git a/configs/targets/alpha-softmmu.mak b/configs/targets/alpha-softmmu.mak
index 5275076..e31f059 100644
--- a/configs/targets/alpha-softmmu.mak
+++ b/configs/targets/alpha-softmmu.mak
@@ -1,2 +1,3 @@
TARGET_ARCH=alpha
TARGET_LONG_BITS=64
+TARGET_XML_FILES= gdb-xml/alpha-core.xml
diff --git a/configs/targets/sparc64-linux-user.mak b/configs/targets/sparc64-linux-user.mak
index 64ea04e..7c2ecb7 100644
--- a/configs/targets/sparc64-linux-user.mak
+++ b/configs/targets/sparc64-linux-user.mak
@@ -4,4 +4,5 @@ TARGET_ABI_DIR=sparc
TARGET_SYSTBL_ABI=common,64
TARGET_SYSTBL=syscall.tbl
TARGET_BIG_ENDIAN=y
+TARGET_XML_FILES=gdb-xml/sparc64-core.xml
TARGET_LONG_BITS=64
diff --git a/configs/targets/sparc64-softmmu.mak b/configs/targets/sparc64-softmmu.mak
index 2504e31..d9d51d2 100644
--- a/configs/targets/sparc64-softmmu.mak
+++ b/configs/targets/sparc64-softmmu.mak
@@ -1,4 +1,5 @@
TARGET_ARCH=sparc64
TARGET_BASE_ARCH=sparc
TARGET_BIG_ENDIAN=y
+TARGET_XML_FILES=gdb-xml/sparc64-core.xml
TARGET_LONG_BITS=64
diff --git a/contrib/plugins/execlog.c b/contrib/plugins/execlog.c
index d67d010..06ec76d 100644
--- a/contrib/plugins/execlog.c
+++ b/contrib/plugins/execlog.c
@@ -232,12 +232,15 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
*/
if (disas_assist && rmatches) {
check_regs_next = false;
- gchar *args = g_strstr_len(insn_disas, -1, " ");
- for (int n = 0; n < all_reg_names->len; n++) {
- gchar *reg = g_ptr_array_index(all_reg_names, n);
- if (g_strrstr(args, reg)) {
- check_regs_next = true;
- skip = false;
+ g_auto(GStrv) args = g_strsplit_set(insn_disas, " \t", 2);
+ if (args && args[1]) {
+ for (int n = 0; n < all_reg_names->len; n++) {
+ const gchar *reg = g_ptr_array_index(all_reg_names, n);
+ if (g_strrstr(args[1], reg)) {
+ check_regs_next = true;
+ skip = false;
+ break;
+ }
}
}
}
diff --git a/cpu-target.c b/cpu-target.c
index 1c90a30..772e354 100644
--- a/cpu-target.c
+++ b/cpu-target.c
@@ -19,10 +19,9 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "system/accel-ops.h"
+#include "accel/accel-cpu-ops.h"
#include "system/cpus.h"
#include "exec/cpu-common.h"
-#include "exec/tswap.h"
#include "exec/replay-core.h"
#include "exec/log.h"
#include "hw/core/cpu.h"
@@ -85,9 +84,3 @@ void cpu_abort(CPUState *cpu, const char *fmt, ...)
#endif
abort();
}
-
-#undef target_big_endian
-bool target_big_endian(void)
-{
- return TARGET_BIG_ENDIAN;
-}
diff --git a/docs/devel/migration/vfio.rst b/docs/devel/migration/vfio.rst
index 2d8e5ca..0790e50 100644
--- a/docs/devel/migration/vfio.rst
+++ b/docs/devel/migration/vfio.rst
@@ -247,3 +247,22 @@ The multifd VFIO device state transfer is controlled by
"x-migration-multifd-transfer" VFIO device property. This property defaults to
AUTO, which means that VFIO device state transfer via multifd channels is
attempted in configurations that otherwise support it.
+
+Since the target QEMU needs to load device state buffers in-order it needs to
+queue incoming buffers until they can be loaded into the device.
+This means that a malicious QEMU source could theoretically cause the target
+QEMU to allocate unlimited amounts of memory for such buffers-in-flight.
+
+The "x-migration-max-queued-buffers-size" property allows capping the total size
+of these VFIO device state buffers queued at the destination.
+
+Because a malicious QEMU source causing OOM on the target is not expected to be
+a realistic threat in most of VFIO live migration use cases and the right value
+depends on the particular setup by default this queued buffers size limit is
+disabled by setting it to UINT64_MAX.
+
+Some host platforms (like ARM64) require that VFIO device config is loaded only
+after all iterables were loaded, during non-iterables loading phase.
+Such interlocking is controlled by "x-migration-load-config-after-iter" VFIO
+device property, which in its default setting (AUTO) does so only on platforms
+that actually require it.
diff --git a/docs/devel/qapi-code-gen.rst b/docs/devel/qapi-code-gen.rst
index 231cc0f..dfdbeac 100644
--- a/docs/devel/qapi-code-gen.rst
+++ b/docs/devel/qapi-code-gen.rst
@@ -876,25 +876,35 @@ structuring content.
Headings and subheadings
~~~~~~~~~~~~~~~~~~~~~~~~
-A free-form documentation comment containing a line which starts with
-some ``=`` symbols and then a space defines a section heading::
+Free-form documentation does not start with ``@SYMBOL`` and can contain
+arbitrary rST markup. Headings can be marked up using the standard rST
+syntax::
##
- # = This is a top level heading
+ # *************************
+ # This is a level 2 heading
+ # *************************
#
# This is a free-form comment which will go under the
# top level heading.
##
##
- # == This is a second level heading
+ # This is a third level heading
+ # ==============================
+ #
+ # Level 4
+ # _______
+ #
+ # Level 5
+ # ^^^^^^^
+ #
+ # Level 6
+ # """""""
##
-A heading line must be the first line of the documentation
-comment block.
-
-Section headings must always be correctly nested, so you can only
-define a third-level heading inside a second-level heading, and so on.
+Level 1 headings are reserved for use by the generated documentation
+page itself, leaving level 2 as the highest level that should be used.
Documentation markup
diff --git a/docs/devel/qapi-domain.rst b/docs/devel/qapi-domain.rst
index 1123872..b71890f 100644
--- a/docs/devel/qapi-domain.rst
+++ b/docs/devel/qapi-domain.rst
@@ -242,6 +242,37 @@ Example::
}
+``:return-nodesc:``
+-------------------
+
+Document the return type of a QAPI command, without an accompanying
+description.
+
+:availability: This field list is only available in the body of the
+ Command directive.
+:syntax: ``:return-nodesc: type``
+:type: `sphinx.util.docfields.Field
+ <https://pydoc.dev/sphinx/latest/sphinx.util.docfields.Field.html?private=1>`_
+
+
+Example::
+
+ .. qapi:command:: query-replay
+ :since: 5.2
+
+ Retrieve the record/replay information. It includes current
+ instruction count which may be used for ``replay-break`` and
+ ``replay-seek`` commands.
+
+ :return-nodesc: ReplayInfo
+
+ .. qmp-example::
+
+ -> { "execute": "query-replay" }
+ <- { "return": {
+ "mode": "play", "filename": "log.rr", "icount": 220414 }
+ }
+
``:value:``
-----------
diff --git a/docs/devel/testing/main.rst b/docs/devel/testing/main.rst
index 6b18ed8..2b5cb0c 100644
--- a/docs/devel/testing/main.rst
+++ b/docs/devel/testing/main.rst
@@ -604,9 +604,9 @@ below steps to debug it:
2. Add "V=1" to the command line, try again, to see the verbose output.
3. Further add "DEBUG=1" to the command line. This will pause in a shell prompt
in the container right before testing starts. You could either manually
- build QEMU and run tests from there, or press Ctrl-D to let the Docker
+ build QEMU and run tests from there, or press :kbd:`Ctrl+d` to let the Docker
testing continue.
-4. If you press Ctrl-D, the same building and testing procedure will begin, and
+4. If you press :kbd:`Ctrl+d`, the same building and testing procedure will begin, and
will hopefully run into the error again. After that, you will be dropped to
the prompt for debug.
diff --git a/docs/interop/firmware.json b/docs/interop/firmware.json
index 0711b6f..6bbe2cc 100644
--- a/docs/interop/firmware.json
+++ b/docs/interop/firmware.json
@@ -11,7 +11,9 @@
# later. See the COPYING file in the top-level directory.
##
-# = Firmware
+# ********
+# Firmware
+# ********
##
{ 'pragma': {
diff --git a/docs/interop/qemu-ga-ref.rst b/docs/interop/qemu-ga-ref.rst
index 25f6e24..ea6652a 100644
--- a/docs/interop/qemu-ga-ref.rst
+++ b/docs/interop/qemu-ga-ref.rst
@@ -2,5 +2,4 @@ QEMU Guest Agent Protocol Reference
===================================
.. qapi-doc:: qga/qapi-schema.json
- :transmogrify:
:namespace: QGA
diff --git a/docs/interop/qemu-qmp-ref.rst b/docs/interop/qemu-qmp-ref.rst
index 3bc1ca1..f0ce39a 100644
--- a/docs/interop/qemu-qmp-ref.rst
+++ b/docs/interop/qemu-qmp-ref.rst
@@ -7,5 +7,4 @@ QEMU QMP Reference Manual
:local:
.. qapi-doc:: qapi/qapi-schema.json
- :transmogrify:
:namespace: QMP
diff --git a/docs/interop/qemu-storage-daemon-qmp-ref.rst b/docs/interop/qemu-storage-daemon-qmp-ref.rst
index dc7bde2..4dbb6a2 100644
--- a/docs/interop/qemu-storage-daemon-qmp-ref.rst
+++ b/docs/interop/qemu-storage-daemon-qmp-ref.rst
@@ -5,5 +5,4 @@ QEMU Storage Daemon QMP Reference Manual
:local:
.. qapi-doc:: storage-daemon/qapi/qapi-schema.json
- :transmogrify:
:namespace: QSD
diff --git a/docs/interop/vhost-user.json b/docs/interop/vhost-user.json
index b6ade9e..095eb99 100644
--- a/docs/interop/vhost-user.json
+++ b/docs/interop/vhost-user.json
@@ -10,7 +10,9 @@
# later. See the COPYING file in the top-level directory.
##
-# = vhost user backend discovery & capabilities
+# *******************************************
+# vhost user backend discovery & capabilities
+# *******************************************
##
##
diff --git a/docs/sphinx/qapi_domain.py b/docs/sphinx/qapi_domain.py
index ebc46a7..f561dc4 100644
--- a/docs/sphinx/qapi_domain.py
+++ b/docs/sphinx/qapi_domain.py
@@ -532,6 +532,14 @@ class QAPICommand(QAPIObject):
names=("return",),
can_collapse=True,
),
+ # :return-nodesc: TypeName
+ CompatField(
+ "returnvalue",
+ label=_("Return"),
+ names=("return-nodesc",),
+ bodyrolename="type",
+ has_arg=False,
+ ),
]
)
diff --git a/docs/sphinx/qapidoc.py b/docs/sphinx/qapidoc.py
index 8011ac9..c2f09ba 100644
--- a/docs/sphinx/qapidoc.py
+++ b/docs/sphinx/qapidoc.py
@@ -64,8 +64,6 @@ from sphinx.util import logging
from sphinx.util.docutils import SphinxDirective, switch_source_input
from sphinx.util.nodes import nested_parse_with_titles
-from qapidoc_legacy import QAPISchemaGenRSTVisitor # type: ignore
-
if TYPE_CHECKING:
from typing import (
@@ -218,6 +216,11 @@ class Transmogrifier:
typ = self.format_type(member)
self.add_field(kind, member.name, body, info, typ)
+ @staticmethod
+ def reformat_arobase(text: str) -> str:
+ """ reformats @var to ``var`` """
+ return re.sub(r"@([\w-]+)", r"``\1``", text)
+
# Transmogrification helpers
def visit_paragraph(self, section: QAPIDoc.Section) -> None:
@@ -255,22 +258,28 @@ class Transmogrifier:
def visit_returns(self, section: QAPIDoc.Section) -> None:
assert isinstance(self.entity, QAPISchemaCommand)
rtype = self.entity.ret_type
- # q_empty can produce None, but we won't be documenting anything
- # without an explicit return statement in the doc block, and we
- # should not have any such explicit statements when there is no
- # return value.
+ # return statements will not be present (and won't be
+ # autogenerated) for any command that doesn't return
+ # *something*, so rtype will always be defined here.
assert rtype
typ = self.format_type(rtype)
assert typ
- assert section.text
- self.add_field("return", typ, section.text, section.info)
+
+ if section.text:
+ self.add_field("return", typ, section.text, section.info)
+ else:
+ self.add_lines(f":return-nodesc: {typ}", section.info)
def visit_errors(self, section: QAPIDoc.Section) -> None:
- # FIXME: the formatting for errors may be inconsistent and may
- # or may not require different newline placement to ensure
- # proper rendering as a nested list.
- self.add_lines(f":error:\n{section.text}", section.info)
+ # If the section text does not start with a space, it means text
+ # began on the same line as the "Error:" string and we should
+ # not insert a newline in this case.
+ if section.text[0].isspace():
+ text = f":error:\n{section.text}"
+ else:
+ text = f":error: {section.text}"
+ self.add_lines(text, section.info)
def preamble(self, ent: QAPISchemaDefinition) -> None:
"""
@@ -357,8 +366,7 @@ class Transmogrifier:
# Add sections in source order:
for i, section in enumerate(sections):
- # @var is translated to ``var``:
- section.text = re.sub(r"@([\w-]+)", r"``\1``", section.text)
+ section.text = self.reformat_arobase(section.text)
if section.kind == QAPIDoc.Kind.PLAIN:
self.visit_paragraph(section)
@@ -393,44 +401,9 @@ class Transmogrifier:
self.ensure_blank_line()
def visit_freeform(self, doc: QAPIDoc) -> None:
- # TODO: Once the old qapidoc transformer is deprecated, freeform
- # sections can be updated to pure rST, and this transformed removed.
- #
- # For now, translate our micro-format into rST. Code adapted
- # from Peter Maydell's freeform().
-
assert len(doc.all_sections) == 1, doc.all_sections
body = doc.all_sections[0]
- text = body.text
- info = doc.info
-
- if re.match(r"=+ ", text):
- # Section/subsection heading (if present, will always be the
- # first line of the block)
- (heading, _, text) = text.partition("\n")
- (leader, _, heading) = heading.partition(" ")
- # Implicit +1 for heading in the containing .rst doc
- level = len(leader) + 1
-
- # https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#sections
- markers = ' #*=_^"'
- overline = level <= 2
- marker = markers[level]
-
- self.ensure_blank_line()
- # This credits all 2 or 3 lines to the single source line.
- if overline:
- self.add_line(marker * len(heading), info)
- self.add_line(heading, info)
- self.add_line(marker * len(heading), info)
- self.ensure_blank_line()
-
- # Eat blank line(s) and advance info
- trimmed = text.lstrip("\n")
- text = trimmed
- info = info.next_line(len(text) - len(trimmed) + 1)
-
- self.add_lines(text, info)
+ self.add_lines(self.reformat_arobase(body.text), doc.info)
self.ensure_blank_line()
def visit_entity(self, ent: QAPISchemaDefinition) -> None:
@@ -504,15 +477,9 @@ class QAPIDocDirective(NestedDirective):
option_spec = {
"qapifile": directives.unchanged_required,
"namespace": directives.unchanged,
- "transmogrify": directives.flag,
}
has_content = False
- def new_serialno(self) -> str:
- """Return a unique new ID string suitable for use as a node's ID"""
- env = self.state.document.settings.env
- return "qapidoc-%d" % env.new_serialno("qapidoc")
-
def transmogrify(self, schema: QAPISchema) -> nodes.Element:
logger.info("Transmogrifying QAPI to rST ...")
vis = Transmogrifier()
@@ -590,21 +557,10 @@ class QAPIDocDirective(NestedDirective):
outfile.write(f" {rcol}")
outfile.write("\n")
- def legacy(self, schema: QAPISchema) -> nodes.Element:
- vis = QAPISchemaGenRSTVisitor(self)
- vis.visit_begin(schema)
- for doc in schema.docs:
- if doc.symbol:
- vis.symbol(doc, schema.lookup_entity(doc.symbol))
- else:
- vis.freeform(doc)
- return vis.get_document_node() # type: ignore
-
def run(self) -> Sequence[nodes.Node]:
env = self.state.document.settings.env
qapifile = env.config.qapidoc_srctree + "/" + self.arguments[0]
qapidir = os.path.dirname(qapifile)
- transmogrify = "transmogrify" in self.options
try:
schema = QAPISchema(qapifile)
@@ -617,11 +573,7 @@ class QAPIDocDirective(NestedDirective):
# so they are displayed nicely to the user
raise ExtensionError(str(err)) from err
- if transmogrify:
- contentnode = self.transmogrify(schema)
- else:
- contentnode = self.legacy(schema)
-
+ contentnode = self.transmogrify(schema)
return contentnode.children
diff --git a/docs/sphinx/qapidoc_legacy.py b/docs/sphinx/qapidoc_legacy.py
deleted file mode 100644
index 13520f4..0000000
--- a/docs/sphinx/qapidoc_legacy.py
+++ /dev/null
@@ -1,440 +0,0 @@
-# coding=utf-8
-# type: ignore
-#
-# QEMU qapidoc QAPI file parsing extension
-#
-# Copyright (c) 2020 Linaro
-#
-# This work is licensed under the terms of the GNU GPLv2 or later.
-# See the COPYING file in the top-level directory.
-
-"""
-qapidoc is a Sphinx extension that implements the qapi-doc directive
-
-The purpose of this extension is to read the documentation comments
-in QAPI schema files, and insert them all into the current document.
-
-It implements one new rST directive, "qapi-doc::".
-Each qapi-doc:: directive takes one argument, which is the
-pathname of the schema file to process, relative to the source tree.
-
-The docs/conf.py file must set the qapidoc_srctree config value to
-the root of the QEMU source tree.
-
-The Sphinx documentation on writing extensions is at:
-https://www.sphinx-doc.org/en/master/development/index.html
-"""
-
-import re
-import textwrap
-
-from docutils import nodes
-from docutils.statemachine import ViewList
-from qapi.error import QAPISemError
-from qapi.gen import QAPISchemaVisitor
-from qapi.parser import QAPIDoc
-
-
-def dedent(text: str) -> str:
- # Adjust indentation to make description text parse as paragraph.
-
- lines = text.splitlines(True)
- if re.match(r"\s+", lines[0]):
- # First line is indented; description started on the line after
- # the name. dedent the whole block.
- return textwrap.dedent(text)
-
- # Descr started on same line. Dedent line 2+.
- return lines[0] + textwrap.dedent("".join(lines[1:]))
-
-
-class QAPISchemaGenRSTVisitor(QAPISchemaVisitor):
- """A QAPI schema visitor which generates docutils/Sphinx nodes
-
- This class builds up a tree of docutils/Sphinx nodes corresponding
- to documentation for the various QAPI objects. To use it, first
- create a QAPISchemaGenRSTVisitor object, and call its
- visit_begin() method. Then you can call one of the two methods
- 'freeform' (to add documentation for a freeform documentation
- chunk) or 'symbol' (to add documentation for a QAPI symbol). These
- will cause the visitor to build up the tree of document
- nodes. Once you've added all the documentation via 'freeform' and
- 'symbol' method calls, you can call 'get_document_nodes' to get
- the final list of document nodes (in a form suitable for returning
- from a Sphinx directive's 'run' method).
- """
- def __init__(self, sphinx_directive):
- self._cur_doc = None
- self._sphinx_directive = sphinx_directive
- self._top_node = nodes.section()
- self._active_headings = [self._top_node]
-
- def _make_dlitem(self, term, defn):
- """Return a dlitem node with the specified term and definition.
-
- term should be a list of Text and literal nodes.
- defn should be one of:
- - a string, which will be handed to _parse_text_into_node
- - a list of Text and literal nodes, which will be put into
- a paragraph node
- """
- dlitem = nodes.definition_list_item()
- dlterm = nodes.term('', '', *term)
- dlitem += dlterm
- if defn:
- dldef = nodes.definition()
- if isinstance(defn, list):
- dldef += nodes.paragraph('', '', *defn)
- else:
- self._parse_text_into_node(defn, dldef)
- dlitem += dldef
- return dlitem
-
- def _make_section(self, title):
- """Return a section node with optional title"""
- section = nodes.section(ids=[self._sphinx_directive.new_serialno()])
- if title:
- section += nodes.title(title, title)
- return section
-
- def _nodes_for_ifcond(self, ifcond, with_if=True):
- """Return list of Text, literal nodes for the ifcond
-
- Return a list which gives text like ' (If: condition)'.
- If with_if is False, we don't return the "(If: " and ")".
- """
-
- doc = ifcond.docgen()
- if not doc:
- return []
- doc = nodes.literal('', doc)
- if not with_if:
- return [doc]
-
- nodelist = [nodes.Text(' ('), nodes.strong('', 'If: ')]
- nodelist.append(doc)
- nodelist.append(nodes.Text(')'))
- return nodelist
-
- def _nodes_for_one_member(self, member):
- """Return list of Text, literal nodes for this member
-
- Return a list of doctree nodes which give text like
- 'name: type (optional) (If: ...)' suitable for use as the
- 'term' part of a definition list item.
- """
- term = [nodes.literal('', member.name)]
- if member.type.doc_type():
- term.append(nodes.Text(': '))
- term.append(nodes.literal('', member.type.doc_type()))
- if member.optional:
- term.append(nodes.Text(' (optional)'))
- if member.ifcond.is_present():
- term.extend(self._nodes_for_ifcond(member.ifcond))
- return term
-
- def _nodes_for_variant_when(self, branches, variant):
- """Return list of Text, literal nodes for variant 'when' clause
-
- Return a list of doctree nodes which give text like
- 'when tagname is variant (If: ...)' suitable for use in
- the 'branches' part of a definition list.
- """
- term = [nodes.Text(' when '),
- nodes.literal('', branches.tag_member.name),
- nodes.Text(' is '),
- nodes.literal('', '"%s"' % variant.name)]
- if variant.ifcond.is_present():
- term.extend(self._nodes_for_ifcond(variant.ifcond))
- return term
-
- def _nodes_for_members(self, doc, what, base=None, branches=None):
- """Return list of doctree nodes for the table of members"""
- dlnode = nodes.definition_list()
- for section in doc.args.values():
- term = self._nodes_for_one_member(section.member)
- # TODO drop fallbacks when undocumented members are outlawed
- if section.text:
- defn = dedent(section.text)
- else:
- defn = [nodes.Text('Not documented')]
-
- dlnode += self._make_dlitem(term, defn)
-
- if base:
- dlnode += self._make_dlitem([nodes.Text('The members of '),
- nodes.literal('', base.doc_type())],
- None)
-
- if branches:
- for v in branches.variants:
- if v.type.name == 'q_empty':
- continue
- assert not v.type.is_implicit()
- term = [nodes.Text('The members of '),
- nodes.literal('', v.type.doc_type())]
- term.extend(self._nodes_for_variant_when(branches, v))
- dlnode += self._make_dlitem(term, None)
-
- if not dlnode.children:
- return []
-
- section = self._make_section(what)
- section += dlnode
- return [section]
-
- def _nodes_for_enum_values(self, doc):
- """Return list of doctree nodes for the table of enum values"""
- seen_item = False
- dlnode = nodes.definition_list()
- for section in doc.args.values():
- termtext = [nodes.literal('', section.member.name)]
- if section.member.ifcond.is_present():
- termtext.extend(self._nodes_for_ifcond(section.member.ifcond))
- # TODO drop fallbacks when undocumented members are outlawed
- if section.text:
- defn = dedent(section.text)
- else:
- defn = [nodes.Text('Not documented')]
-
- dlnode += self._make_dlitem(termtext, defn)
- seen_item = True
-
- if not seen_item:
- return []
-
- section = self._make_section('Values')
- section += dlnode
- return [section]
-
- def _nodes_for_arguments(self, doc, arg_type):
- """Return list of doctree nodes for the arguments section"""
- if arg_type and not arg_type.is_implicit():
- assert not doc.args
- section = self._make_section('Arguments')
- dlnode = nodes.definition_list()
- dlnode += self._make_dlitem(
- [nodes.Text('The members of '),
- nodes.literal('', arg_type.name)],
- None)
- section += dlnode
- return [section]
-
- return self._nodes_for_members(doc, 'Arguments')
-
- def _nodes_for_features(self, doc):
- """Return list of doctree nodes for the table of features"""
- seen_item = False
- dlnode = nodes.definition_list()
- for section in doc.features.values():
- dlnode += self._make_dlitem(
- [nodes.literal('', section.member.name)], dedent(section.text))
- seen_item = True
-
- if not seen_item:
- return []
-
- section = self._make_section('Features')
- section += dlnode
- return [section]
-
- def _nodes_for_sections(self, doc):
- """Return list of doctree nodes for additional sections"""
- nodelist = []
- for section in doc.sections:
- if section.kind == QAPIDoc.Kind.TODO:
- # Hide TODO: sections
- continue
-
- if section.kind == QAPIDoc.Kind.PLAIN:
- # Sphinx cannot handle sectionless titles;
- # Instead, just append the results to the prior section.
- container = nodes.container()
- self._parse_text_into_node(section.text, container)
- nodelist += container.children
- continue
-
- snode = self._make_section(section.kind.name.title())
- self._parse_text_into_node(dedent(section.text), snode)
- nodelist.append(snode)
- return nodelist
-
- def _nodes_for_if_section(self, ifcond):
- """Return list of doctree nodes for the "If" section"""
- nodelist = []
- if ifcond.is_present():
- snode = self._make_section('If')
- snode += nodes.paragraph(
- '', '', *self._nodes_for_ifcond(ifcond, with_if=False)
- )
- nodelist.append(snode)
- return nodelist
-
- def _add_doc(self, typ, sections):
- """Add documentation for a command/object/enum...
-
- We assume we're documenting the thing defined in self._cur_doc.
- typ is the type of thing being added ("Command", "Object", etc)
-
- sections is a list of nodes for sections to add to the definition.
- """
-
- doc = self._cur_doc
- snode = nodes.section(ids=[self._sphinx_directive.new_serialno()])
- snode += nodes.title('', '', *[nodes.literal(doc.symbol, doc.symbol),
- nodes.Text(' (' + typ + ')')])
- self._parse_text_into_node(doc.body.text, snode)
- for s in sections:
- if s is not None:
- snode += s
- self._add_node_to_current_heading(snode)
-
- def visit_enum_type(self, name, info, ifcond, features, members, prefix):
- doc = self._cur_doc
- self._add_doc('Enum',
- self._nodes_for_enum_values(doc)
- + self._nodes_for_features(doc)
- + self._nodes_for_sections(doc)
- + self._nodes_for_if_section(ifcond))
-
- def visit_object_type(self, name, info, ifcond, features,
- base, members, branches):
- doc = self._cur_doc
- if base and base.is_implicit():
- base = None
- self._add_doc('Object',
- self._nodes_for_members(doc, 'Members', base, branches)
- + self._nodes_for_features(doc)
- + self._nodes_for_sections(doc)
- + self._nodes_for_if_section(ifcond))
-
- def visit_alternate_type(self, name, info, ifcond, features,
- alternatives):
- doc = self._cur_doc
- self._add_doc('Alternate',
- self._nodes_for_members(doc, 'Members')
- + self._nodes_for_features(doc)
- + self._nodes_for_sections(doc)
- + self._nodes_for_if_section(ifcond))
-
- def visit_command(self, name, info, ifcond, features, arg_type,
- ret_type, gen, success_response, boxed, allow_oob,
- allow_preconfig, coroutine):
- doc = self._cur_doc
- self._add_doc('Command',
- self._nodes_for_arguments(doc, arg_type)
- + self._nodes_for_features(doc)
- + self._nodes_for_sections(doc)
- + self._nodes_for_if_section(ifcond))
-
- def visit_event(self, name, info, ifcond, features, arg_type, boxed):
- doc = self._cur_doc
- self._add_doc('Event',
- self._nodes_for_arguments(doc, arg_type)
- + self._nodes_for_features(doc)
- + self._nodes_for_sections(doc)
- + self._nodes_for_if_section(ifcond))
-
- def symbol(self, doc, entity):
- """Add documentation for one symbol to the document tree
-
- This is the main entry point which causes us to add documentation
- nodes for a symbol (which could be a 'command', 'object', 'event',
- etc). We do this by calling 'visit' on the schema entity, which
- will then call back into one of our visit_* methods, depending
- on what kind of thing this symbol is.
- """
- self._cur_doc = doc
- entity.visit(self)
- self._cur_doc = None
-
- def _start_new_heading(self, heading, level):
- """Start a new heading at the specified heading level
-
- Create a new section whose title is 'heading' and which is placed
- in the docutils node tree as a child of the most recent level-1
- heading. Subsequent document sections (commands, freeform doc chunks,
- etc) will be placed as children of this new heading section.
- """
- if len(self._active_headings) < level:
- raise QAPISemError(self._cur_doc.info,
- 'Level %d subheading found outside a '
- 'level %d heading'
- % (level, level - 1))
- snode = self._make_section(heading)
- self._active_headings[level - 1] += snode
- self._active_headings = self._active_headings[:level]
- self._active_headings.append(snode)
- return snode
-
- def _add_node_to_current_heading(self, node):
- """Add the node to whatever the current active heading is"""
- self._active_headings[-1] += node
-
- def freeform(self, doc):
- """Add a piece of 'freeform' documentation to the document tree
-
- A 'freeform' document chunk doesn't relate to any particular
- symbol (for instance, it could be an introduction).
-
- If the freeform document starts with a line of the form
- '= Heading text', this is a section or subsection heading, with
- the heading level indicated by the number of '=' signs.
- """
-
- # QAPIDoc documentation says free-form documentation blocks
- # must have only a body section, nothing else.
- assert not doc.sections
- assert not doc.args
- assert not doc.features
- self._cur_doc = doc
-
- text = doc.body.text
- if re.match(r'=+ ', text):
- # Section/subsection heading (if present, will always be
- # the first line of the block)
- (heading, _, text) = text.partition('\n')
- (leader, _, heading) = heading.partition(' ')
- node = self._start_new_heading(heading, len(leader))
- if text == '':
- return
- else:
- node = nodes.container()
-
- self._parse_text_into_node(text, node)
- self._cur_doc = None
-
- def _parse_text_into_node(self, doctext, node):
- """Parse a chunk of QAPI-doc-format text into the node
-
- The doc comment can contain most inline rST markup, including
- bulleted and enumerated lists.
- As an extra permitted piece of markup, @var will be turned
- into ``var``.
- """
-
- # Handle the "@var means ``var`` case
- doctext = re.sub(r'@([\w-]+)', r'``\1``', doctext)
-
- rstlist = ViewList()
- for line in doctext.splitlines():
- # The reported line number will always be that of the start line
- # of the doc comment, rather than the actual location of the error.
- # Being more precise would require overhaul of the QAPIDoc class
- # to track lines more exactly within all the sub-parts of the doc
- # comment, as well as counting lines here.
- rstlist.append(line, self._cur_doc.info.fname,
- self._cur_doc.info.line)
- # Append a blank line -- in some cases rST syntax errors get
- # attributed to the line after one with actual text, and if there
- # isn't anything in the ViewList corresponding to that then Sphinx
- # 1.6's AutodocReporter will then misidentify the source/line location
- # in the error message (usually attributing it to the top-level
- # .rst file rather than the offending .json file). The extra blank
- # line won't affect the rendered output.
- rstlist.append("", self._cur_doc.info.fname, self._cur_doc.info.line)
- self._sphinx_directive.do_parse(rstlist, node)
-
- def get_document_node(self):
- """Return the root docutils node which makes up the document"""
- return self._top_node
diff --git a/docs/system/images.rst b/docs/system/images.rst
index a555117..4370696 100644
--- a/docs/system/images.rst
+++ b/docs/system/images.rst
@@ -30,7 +30,7 @@ Snapshot mode
If you use the option ``-snapshot``, all disk images are considered as
read only. When sectors in written, they are written in a temporary file
created in ``/tmp``. You can however force the write back to the raw
-disk images by using the ``commit`` monitor command (or C-a s in the
+disk images by using the ``commit`` monitor command (or :kbd:`Ctrl+a s` in the
serial console).
.. _vm_005fsnapshots:
diff --git a/docs/system/keys.rst.inc b/docs/system/keys.rst.inc
index 59966a3..c28ae1a 100644
--- a/docs/system/keys.rst.inc
+++ b/docs/system/keys.rst.inc
@@ -1,36 +1,37 @@
During the graphical emulation, you can use special key combinations from
-the following table to change modes. By default the modifier is Ctrl-Alt
+the following table to change modes. By default the modifier is :kbd:`Ctrl+Alt`
(used in the table below) which can be changed with ``-display`` suboption
``mod=`` where appropriate. For example, ``-display sdl,
-grab-mod=lshift-lctrl-lalt`` changes the modifier key to Ctrl-Alt-Shift,
-while ``-display sdl,grab-mod=rctrl`` changes it to the right Ctrl key.
+grab-mod=lshift-lctrl-lalt`` changes the modifier key to :kbd:`Ctrl+Alt+Shift`,
+while ``-display sdl,grab-mod=rctrl`` changes it to the right :kbd:`Ctrl` key.
-Ctrl-Alt-f
- Toggle full screen
+.. list-table:: Multiplexer Keys
+ :widths: 10 90
+ :header-rows: 1
-Ctrl-Alt-+
- Enlarge the screen
+ * - Key Sequence
+ - Action
-Ctrl-Alt\--
- Shrink the screen
+ * - :kbd:`Ctrl+Alt+f`
+ - Toggle full screen
-Ctrl-Alt-u
- Restore the screen's un-scaled dimensions
+ * - :kbd:`Ctrl+Alt++`
+ - Enlarge the screen
-Ctrl-Alt-n
- Switch to virtual console 'n'. Standard console mappings are:
+ * - :kbd:`Ctrl+Alt+-`
+ - Shrink the screen
- *1*
- Target system display
+ * - :kbd:`Ctrl+Alt+u`
+ - Restore the screen's un-scaled dimensions
- *2*
- Monitor
+ * - :kbd:`Ctrl+Alt+n`
+ - Switch to virtual console 'n'. Standard console mappings are:
- *3*
- Serial port
+ - *1*: Target system display
+ - *2*: Monitor
+ - *3*: Serial port
+ * - :kbd:`Ctrl+Alt+g`
+ - Toggle mouse and keyboard grab.
-Ctrl-Alt-g
- Toggle mouse and keyboard grab.
-
-In the virtual consoles, you can use Ctrl-Up, Ctrl-Down, Ctrl-PageUp and
-Ctrl-PageDown to move in the back log.
+In the virtual consoles, you can use :kbd:`Ctrl+Up`, :kbd:`Ctrl+Down`, :kbd:`Ctrl+PageUp` and
+:kbd:`Ctrl+PageDown` to move in the back log.
diff --git a/docs/system/linuxboot.rst b/docs/system/linuxboot.rst
index 2328b4a..f7573ab 100644
--- a/docs/system/linuxboot.rst
+++ b/docs/system/linuxboot.rst
@@ -26,5 +26,5 @@ virtual serial port and the QEMU monitor to the console with the
|qemu_system| -kernel bzImage -drive file=rootdisk.img,format=raw \
-append "root=/dev/sda console=ttyS0" -nographic
-Use Ctrl-a c to switch between the serial console and the monitor (see
+Use :kbd:`Ctrl+a c` to switch between the serial console and the monitor (see
:ref:`GUI_keys`).
diff --git a/docs/system/mux-chardev.rst.inc b/docs/system/mux-chardev.rst.inc
index 84ea12c..c87ba31 100644
--- a/docs/system/mux-chardev.rst.inc
+++ b/docs/system/mux-chardev.rst.inc
@@ -1,27 +1,33 @@
During emulation, if you are using a character backend multiplexer
(which is the default if you are using ``-nographic``) then several
commands are available via an escape sequence. These key sequences all
-start with an escape character, which is Ctrl-a by default, but can be
+start with an escape character, which is :kbd:`Ctrl+a` by default, but can be
changed with ``-echr``. The list below assumes you're using the default.
-Ctrl-a h
- Print this help
+.. list-table:: Multiplexer Keys
+ :widths: 20 80
+ :header-rows: 1
-Ctrl-a x
- Exit emulator
+ * - Key Sequence
+ - Action
-Ctrl-a s
- Save disk data back to file (if -snapshot)
+ * - :kbd:`Ctrl+a h`
+ - Print this help
-Ctrl-a t
- Toggle console timestamps
+ * - :kbd:`Ctrl+a x`
+ - Exit emulator
-Ctrl-a b
- Send break (magic sysrq in Linux)
+ * - :kbd:`Ctrl+a s`
+ - Save disk data back to file (if -snapshot)
-Ctrl-a c
- Rotate between the frontends connected to the multiplexer (usually
- this switches between the monitor and the console)
+ * - :kbd:`Ctrl+a t`
+ - Toggle console timestamps
-Ctrl-a Ctrl-a
- Send the escape character to the frontend
+ * - :kbd:`Ctrl+a b`
+ - Send break (magic sysrq in Linux)
+
+ * - :kbd:`Ctrl+a c`
+ - Rotate between the frontends connected to the multiplexer (usually this switches between the monitor and the console)
+
+ * - :kbd:`Ctrl+a Ctrl+a`
+ - Send the escape character to the frontend
diff --git a/docs/system/virtio-net-failover.rst b/docs/system/virtio-net-failover.rst
index 6002dc5..0cc4654 100644
--- a/docs/system/virtio-net-failover.rst
+++ b/docs/system/virtio-net-failover.rst
@@ -26,43 +26,48 @@ and standby devices are not plugged into the same PCIe slot.
Usecase
-------
- Virtio-net standby allows easy migration while using a passed-through fast
- networking device by falling back to a virtio-net device for the duration of
- the migration. It is like a simple version of a bond, the difference is that it
- requires no configuration in the guest. When a guest is live-migrated to
- another host QEMU will unplug the primary device via the PCIe based hotplug
- handler and traffic will go through the virtio-net device. On the target
- system the primary device will be automatically plugged back and the
- net_failover module registers it again as the primary device.
+Virtio-net standby allows easy migration while using a passed-through
+fast networking device by falling back to a virtio-net device for the
+duration of the migration. It is like a simple version of a bond, the
+difference is that it requires no configuration in the guest. When a
+guest is live-migrated to another host QEMU will unplug the primary
+device via the PCIe based hotplug handler and traffic will go through
+the virtio-net device. On the target system the primary device will be
+automatically plugged back and the net_failover module registers it
+again as the primary device.
Usage
-----
- The primary device can be hotplugged or be part of the startup configuration
+The primary device can be hotplugged or be part of the startup configuration
- -device virtio-net-pci,netdev=hostnet1,id=net1,mac=52:54:00:6f:55:cc, \
- bus=root2,failover=on
+.. code-block:: shell
- With the parameter failover=on the VIRTIO_NET_F_STANDBY feature will be enabled.
+ -device virtio-net-pci,netdev=hostnet1,id=net1,mac=52:54:00:6f:55:cc,bus=root2,failover=on
+
+With the parameter ``failover=on`` the VIRTIO_NET_F_STANDBY feature will be enabled.
+
+.. code-block:: shell
-device vfio-pci,host=5e:00.2,id=hostdev0,bus=root1,failover_pair_id=net1
- failover_pair_id references the id of the virtio-net standby device. This
- is only for pairing the devices within QEMU. The guest kernel module
- net_failover will match devices with identical MAC addresses.
+``failover_pair_id`` references the id of the virtio-net standby device.
+This is only for pairing the devices within QEMU. The guest kernel
+module net_failover will match devices with identical MAC addresses.
Hotplug
-------
- Both primary and standby device can be hotplugged via the QEMU monitor. Note
- that if the virtio-net device is plugged first a warning will be issued that it
- couldn't find the primary device.
+Both primary and standby device can be hotplugged via the QEMU
+monitor. Note that if the virtio-net device is plugged first a warning
+will be issued that it couldn't find the primary device.
Migration
---------
- A new migration state wait-unplug was added for this feature. If failover primary
- devices are present in the configuration, migration will go into this state.
- It will wait until the device unplug is completed in the guest and then move into
- active state. On the target system the primary devices will be automatically hotplugged
- when the feature bit was negotiated for the virtio-net standby device.
+A new migration state wait-unplug was added for this feature. If
+failover primary devices are present in the configuration, migration
+will go into this state. It will wait until the device unplug is
+completed in the guest and then move into active state. On the target
+system the primary devices will be automatically hotplugged when the
+feature bit was negotiated for the virtio-net standby device.
diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst
index 3653adb..5e7b850 100644
--- a/docs/tools/qemu-img.rst
+++ b/docs/tools/qemu-img.rst
@@ -256,7 +256,7 @@ Parameters to snapshot subcommand:
.. option:: -l
- Lists all snapshots in the given image
+ Lists all snapshots in the given image (default action)
Command description:
@@ -419,7 +419,7 @@ Command description:
4
Error on reading data
-.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [--bitmaps [--skip-broken-bitmaps]] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE [-F BACKING_FMT]] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-r RATE_LIMIT] [-m NUM_COROUTINES] [-W] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME
+.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [--bitmaps [--skip-broken-bitmaps]] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-b BACKING_FILE [-F BACKING_FMT]] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-r RATE_LIMIT] [-m NUM_COROUTINES] [-W] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME
Convert the disk image *FILENAME* or a snapshot *SNAPSHOT_PARAM*
to disk image *OUTPUT_FILENAME* using format *OUTPUT_FMT*. It can
@@ -467,11 +467,11 @@ Command description:
``--skip-broken-bitmaps`` is also specified to copy only the
consistent bitmaps.
-.. option:: create [--object OBJECTDEF] [-q] [-f FMT] [-b BACKING_FILE [-F BACKING_FMT]] [-u] [-o OPTIONS] FILENAME [SIZE]
+.. option:: create [-f FMT] [-o FMT_OPTS] [-b BACKING_FILE [-B BACKING_FMT]] [-u] [-q] [--object OBJDEF] FILE [SIZE]
- Create the new disk image *FILENAME* of size *SIZE* and format
- *FMT*. Depending on the file format, you can add one or more *OPTIONS*
- that enable additional features of this format.
+ Create the new disk image *FILE* of size *SIZE* and format
+ *FMT*. Depending on the file format, you can add one or more *FMT_OPTS*
+ options that enable additional features of this format.
If the option *BACKING_FILE* is specified, then the image will record
only the differences from *BACKING_FILE*. No size needs to be specified in
@@ -479,7 +479,7 @@ Command description:
``commit`` monitor command (or ``qemu-img commit``).
If a relative path name is given, the backing file is looked up relative to
- the directory containing *FILENAME*.
+ the directory containing *FILE*.
Note that a given backing file will be opened to check that it is valid. Use
the ``-u`` option to enable unsafe backing file mode, which means that the
@@ -663,11 +663,11 @@ Command description:
bitmap support, or 0 if bitmaps are supported but there is nothing
to copy.
-.. option:: snapshot [--object OBJECTDEF] [--image-opts] [-U] [-q] [-l | -a SNAPSHOT | -c SNAPSHOT | -d SNAPSHOT] FILENAME
+.. option:: snapshot [--object OBJECTDEF] [-f FMT | --image-opts] [-U] [-q] [-l | -a SNAPSHOT | -c SNAPSHOT | -d SNAPSHOT] FILENAME
List, apply, create or delete snapshots in image *FILENAME*.
-.. option:: rebase [--object OBJECTDEF] [--image-opts] [-U] [-q] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-p] [-u] [-c] -b BACKING_FILE [-F BACKING_FMT] FILENAME
+.. option:: rebase [--object OBJECTDEF] [--image-opts] [-U] [-q] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-p] [-u] [-c] -b BACKING_FILE [-B BACKING_FMT] FILENAME
Changes the backing file of an image. Only the formats ``qcow2`` and
``qed`` support changing the backing file.
diff --git a/gdb-xml/alpha-core.xml b/gdb-xml/alpha-core.xml
new file mode 100644
index 0000000..c9e12f4
--- /dev/null
+++ b/gdb-xml/alpha-core.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2025 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.alpha.core">
+ <!-- IEEE rounding mode values -->
+ <enum id="dyn_rm_enum" size="8">
+ <!-- Chopped rounding mode -->
+ <evalue name="chop" value="0"/>
+ <!-- Minus infinity -->
+ <evalue name="-inf" value="1"/>
+ <!-- Normal rounding -->
+ <evalue name="norm" value="2"/>
+ <!-- Plus infinity -->
+ <evalue name="+inf" value="3"/>
+ </enum>
+
+ <!-- Floating-Point Control Register Flags -->
+ <flags id="fpcr_flags" size="8">
+ <!-- Denormal Operand Exception Disable -->
+ <field name="DNOD" start="47" end="47"/>
+ <!-- Denormal Operands to Zero -->
+ <field name="DNZ" start="48" end="48"/>
+ <!-- Invalid Operation Disable -->
+ <field name="INVD" start="49" end="49"/>
+ <!-- Division by Zero Disable -->
+ <field name="DZED" start="50" end="50"/>
+ <!-- Overflow Disable -->
+ <field name="OVFD" start="51" end="51"/>
+ <!-- Invalid Operation -->
+ <field name="INV" start="52" end="52"/>
+ <!-- Division by Zero -->
+ <field name="DZE" start="53" end="53"/>
+ <!-- Overflow -->
+ <field name="OVF" start="54" end="54"/>
+ <!-- Underflow -->
+ <field name="UNF" start="55" end="55"/>
+ <!-- Inexact Result -->
+ <field name="INE" start="56" end="56"/>
+ <!-- Integer Overflow -->
+ <field name="IOV" start="57" end="57"/>
+ <!-- Dynamic Rounding Mode -->
+ <field name="DYN_RM" start="58" end="59" type="dyn_rm_enum"/>
+ <!-- Underflow to Zero -->
+ <field name="UNDZ" start="60" end="60"/>
+ <!-- Underflow Disable -->
+ <field name="UNFD" start="61" end="61"/>
+ <!-- Inexact Disable -->
+ <field name="INED" start="62" end="62"/>
+ <!-- Summary Bit -->
+ <field name="SUM" start="63" end="63"/>
+ </flags>
+
+ <!-- Integer Registers -->
+ <reg name="v0" bitsize="64" type="int64"/>
+ <reg name="t0" bitsize="64" type="int64"/>
+ <reg name="t1" bitsize="64" type="int64"/>
+ <reg name="t2" bitsize="64" type="int64"/>
+ <reg name="t3" bitsize="64" type="int64"/>
+ <reg name="t4" bitsize="64" type="int64"/>
+ <reg name="t5" bitsize="64" type="int64"/>
+ <reg name="t6" bitsize="64" type="int64"/>
+ <reg name="t7" bitsize="64" type="int64"/>
+ <reg name="s0" bitsize="64" type="int64"/>
+ <reg name="s1" bitsize="64" type="int64"/>
+ <reg name="s2" bitsize="64" type="int64"/>
+ <reg name="s3" bitsize="64" type="int64"/>
+ <reg name="s4" bitsize="64" type="int64"/>
+ <reg name="s5" bitsize="64" type="int64"/>
+ <reg name="fp" bitsize="64" type="int64"/>
+ <reg name="a0" bitsize="64" type="int64"/>
+ <reg name="a1" bitsize="64" type="int64"/>
+ <reg name="a2" bitsize="64" type="int64"/>
+ <reg name="a3" bitsize="64" type="int64"/>
+ <reg name="a4" bitsize="64" type="int64"/>
+ <reg name="a5" bitsize="64" type="int64"/>
+ <reg name="t8" bitsize="64" type="int64"/>
+ <reg name="t9" bitsize="64" type="int64"/>
+ <reg name="t10" bitsize="64" type="int64"/>
+ <reg name="t11" bitsize="64" type="int64"/>
+ <reg name="ra" bitsize="64" type="int64"/>
+ <reg name="t12" bitsize="64" type="int64"/>
+ <reg name="at" bitsize="64" type="int64"/>
+ <reg name="gp" bitsize="64" type="data_ptr"/>
+ <reg name="sp" bitsize="64" type="data_ptr"/>
+ <reg name="zero" bitsize="64" type="int64" save-restore="no"/>
+
+ <!-- Floating-Point Registers -->
+ <reg name="f0" bitsize="64" type="float" group="float"/>
+ <reg name="f1" bitsize="64" type="float" group="float"/>
+ <reg name="f2" bitsize="64" type="float" group="float"/>
+ <reg name="f3" bitsize="64" type="float" group="float"/>
+ <reg name="f4" bitsize="64" type="float" group="float"/>
+ <reg name="f5" bitsize="64" type="float" group="float"/>
+ <reg name="f6" bitsize="64" type="float" group="float"/>
+ <reg name="f7" bitsize="64" type="float" group="float"/>
+ <reg name="f8" bitsize="64" type="float" group="float"/>
+ <reg name="f9" bitsize="64" type="float" group="float"/>
+ <reg name="f10" bitsize="64" type="float" group="float"/>
+ <reg name="f11" bitsize="64" type="float" group="float"/>
+ <reg name="f12" bitsize="64" type="float" group="float"/>
+ <reg name="f13" bitsize="64" type="float" group="float"/>
+ <reg name="f14" bitsize="64" type="float" group="float"/>
+ <reg name="f15" bitsize="64" type="float" group="float"/>
+ <reg name="f16" bitsize="64" type="float" group="float"/>
+ <reg name="f17" bitsize="64" type="float" group="float"/>
+ <reg name="f18" bitsize="64" type="float" group="float"/>
+ <reg name="f19" bitsize="64" type="float" group="float"/>
+ <reg name="f20" bitsize="64" type="float" group="float"/>
+ <reg name="f21" bitsize="64" type="float" group="float"/>
+ <reg name="f22" bitsize="64" type="float" group="float"/>
+ <reg name="f23" bitsize="64" type="float" group="float"/>
+ <reg name="f24" bitsize="64" type="float" group="float"/>
+ <reg name="f25" bitsize="64" type="float" group="float"/>
+ <reg name="f26" bitsize="64" type="float" group="float"/>
+ <reg name="f27" bitsize="64" type="float" group="float"/>
+ <reg name="f28" bitsize="64" type="float" group="float"/>
+ <reg name="f29" bitsize="64" type="float" group="float"/>
+ <reg name="f30" bitsize="64" type="float" group="float"/>
+
+ <!-- Floating-Point Control Register -->
+ <reg name="fpcr" bitsize="64" type="fpcr_flags" group="float"/>
+
+ <!-- Program Counter -->
+ <reg name="pc" bitsize="64" type="code_ptr"/>
+
+ <!-- Reserved Index for Former Virtual Register -->
+ <reg name="" bitsize="64" type="int64" save-restore="no"/>
+
+ <!-- PALcode Memory Slot -->
+ <reg name="unique" bitsize="64" type="int64" group="system"/>
+</feature>
diff --git a/gdb-xml/sparc64-core.xml b/gdb-xml/sparc64-core.xml
new file mode 100644
index 0000000..375b9bb
--- /dev/null
+++ b/gdb-xml/sparc64-core.xml
@@ -0,0 +1,99 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2013-2025 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.sparc.core">
+ <reg name="g0" bitsize="64" type="uint64" regnum="0"/>
+ <reg name="g1" bitsize="64" type="uint64" regnum="1"/>
+ <reg name="g2" bitsize="64" type="uint64" regnum="2"/>
+ <reg name="g3" bitsize="64" type="uint64" regnum="3"/>
+ <reg name="g4" bitsize="64" type="uint64" regnum="4"/>
+ <reg name="g5" bitsize="64" type="uint64" regnum="5"/>
+ <reg name="g6" bitsize="64" type="uint64" regnum="6"/>
+ <reg name="g7" bitsize="64" type="uint64" regnum="7"/>
+ <reg name="o0" bitsize="64" type="uint64" regnum="8"/>
+ <reg name="o1" bitsize="64" type="uint64" regnum="9"/>
+ <reg name="o2" bitsize="64" type="uint64" regnum="10"/>
+ <reg name="o3" bitsize="64" type="uint64" regnum="11"/>
+ <reg name="o4" bitsize="64" type="uint64" regnum="12"/>
+ <reg name="o5" bitsize="64" type="uint64" regnum="13"/>
+ <reg name="sp" bitsize="64" type="uint64" regnum="14"/>
+ <reg name="o7" bitsize="64" type="uint64" regnum="15"/>
+ <reg name="l0" bitsize="64" type="uint64" regnum="16"/>
+ <reg name="l1" bitsize="64" type="uint64" regnum="17"/>
+ <reg name="l2" bitsize="64" type="uint64" regnum="18"/>
+ <reg name="l3" bitsize="64" type="uint64" regnum="19"/>
+ <reg name="l4" bitsize="64" type="uint64" regnum="20"/>
+ <reg name="l5" bitsize="64" type="uint64" regnum="21"/>
+ <reg name="l6" bitsize="64" type="uint64" regnum="22"/>
+ <reg name="l7" bitsize="64" type="uint64" regnum="23"/>
+ <reg name="i0" bitsize="64" type="uint64" regnum="24"/>
+ <reg name="i1" bitsize="64" type="uint64" regnum="25"/>
+ <reg name="i2" bitsize="64" type="uint64" regnum="26"/>
+ <reg name="i3" bitsize="64" type="uint64" regnum="27"/>
+ <reg name="i4" bitsize="64" type="uint64" regnum="28"/>
+ <reg name="i5" bitsize="64" type="uint64" regnum="29"/>
+ <reg name="fp" bitsize="64" type="uint64" regnum="30"/>
+ <reg name="i7" bitsize="64" type="uint64" regnum="31"/>
+
+ <reg name="f0" bitsize="32" type="ieee_single" regnum="32"/>
+ <reg name="f1" bitsize="32" type="ieee_single" regnum="33"/>
+ <reg name="f2" bitsize="32" type="ieee_single" regnum="34"/>
+ <reg name="f3" bitsize="32" type="ieee_single" regnum="35"/>
+ <reg name="f4" bitsize="32" type="ieee_single" regnum="36"/>
+ <reg name="f5" bitsize="32" type="ieee_single" regnum="37"/>
+ <reg name="f6" bitsize="32" type="ieee_single" regnum="38"/>
+ <reg name="f7" bitsize="32" type="ieee_single" regnum="39"/>
+ <reg name="f8" bitsize="32" type="ieee_single" regnum="40"/>
+ <reg name="f9" bitsize="32" type="ieee_single" regnum="41"/>
+ <reg name="f10" bitsize="32" type="ieee_single" regnum="42"/>
+ <reg name="f11" bitsize="32" type="ieee_single" regnum="43"/>
+ <reg name="f12" bitsize="32" type="ieee_single" regnum="44"/>
+ <reg name="f13" bitsize="32" type="ieee_single" regnum="45"/>
+ <reg name="f14" bitsize="32" type="ieee_single" regnum="46"/>
+ <reg name="f15" bitsize="32" type="ieee_single" regnum="47"/>
+ <reg name="f16" bitsize="32" type="ieee_single" regnum="48"/>
+ <reg name="f17" bitsize="32" type="ieee_single" regnum="49"/>
+ <reg name="f18" bitsize="32" type="ieee_single" regnum="50"/>
+ <reg name="f19" bitsize="32" type="ieee_single" regnum="51"/>
+ <reg name="f20" bitsize="32" type="ieee_single" regnum="52"/>
+ <reg name="f21" bitsize="32" type="ieee_single" regnum="53"/>
+ <reg name="f22" bitsize="32" type="ieee_single" regnum="54"/>
+ <reg name="f23" bitsize="32" type="ieee_single" regnum="55"/>
+ <reg name="f24" bitsize="32" type="ieee_single" regnum="56"/>
+ <reg name="f25" bitsize="32" type="ieee_single" regnum="57"/>
+ <reg name="f26" bitsize="32" type="ieee_single" regnum="58"/>
+ <reg name="f27" bitsize="32" type="ieee_single" regnum="59"/>
+ <reg name="f28" bitsize="32" type="ieee_single" regnum="60"/>
+ <reg name="f29" bitsize="32" type="ieee_single" regnum="61"/>
+ <reg name="f30" bitsize="32" type="ieee_single" regnum="62"/>
+ <reg name="f31" bitsize="32" type="ieee_single" regnum="63"/>
+
+ <reg name="f32" bitsize="64" type="ieee_double" regnum="64"/>
+ <reg name="f34" bitsize="64" type="ieee_double" regnum="65"/>
+ <reg name="f36" bitsize="64" type="ieee_double" regnum="66"/>
+ <reg name="f38" bitsize="64" type="ieee_double" regnum="67"/>
+ <reg name="f40" bitsize="64" type="ieee_double" regnum="68"/>
+ <reg name="f42" bitsize="64" type="ieee_double" regnum="69"/>
+ <reg name="f44" bitsize="64" type="ieee_double" regnum="70"/>
+ <reg name="f46" bitsize="64" type="ieee_double" regnum="71"/>
+ <reg name="f48" bitsize="64" type="ieee_double" regnum="72"/>
+ <reg name="f50" bitsize="64" type="ieee_double" regnum="73"/>
+ <reg name="f52" bitsize="64" type="ieee_double" regnum="74"/>
+ <reg name="f54" bitsize="64" type="ieee_double" regnum="75"/>
+ <reg name="f56" bitsize="64" type="ieee_double" regnum="76"/>
+ <reg name="f58" bitsize="64" type="ieee_double" regnum="77"/>
+ <reg name="f60" bitsize="64" type="ieee_double" regnum="78"/>
+ <reg name="f62" bitsize="64" type="ieee_double" regnum="79"/>
+
+ <reg name="pc" bitsize="64" type="code_ptr" regnum="80"/>
+ <reg name="npc" bitsize="64" type="code_ptr" regnum="81"/>
+ <reg name="state" bitsize="64" type="uint64" regnum="82"/>
+ <reg name="fsr" bitsize="64" type="uint64" regnum="83"/>
+ <reg name="fprs" bitsize="64" type="uint64" regnum="84"/>
+ <reg name="y" bitsize="64" type="uint64" regnum="85"/>
+</feature>
diff --git a/gdbstub/system.c b/gdbstub/system.c
index 8a32d8e..5be0d3c 100644
--- a/gdbstub/system.c
+++ b/gdbstub/system.c
@@ -19,7 +19,8 @@
#include "gdbstub/commands.h"
#include "exec/hwaddr.h"
#include "exec/tb-flush.h"
-#include "system/accel-ops.h"
+#include "accel/accel-ops.h"
+#include "accel/accel-cpu-ops.h"
#include "system/cpus.h"
#include "system/runstate.h"
#include "system/replay.h"
diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
index d797922..6142f60 100644
--- a/hmp-commands-info.hx
+++ b/hmp-commands-info.hx
@@ -267,6 +267,18 @@ ERST
.cmd = hmp_info_sync_profile,
},
+ {
+ .name = "accel",
+ .args_type = "",
+ .params = "",
+ .help = "show accelerator info",
+ },
+
+SRST
+ ``info accel``
+ Show accelerator info.
+ERST
+
SRST
``info sync-profile [-m|-n]`` [*max*]
Show synchronization profiling info, up to *max* entries (default: 10),
diff --git a/hw/acpi/acpi-pci-hotplug-stub.c b/hw/acpi/acpi-pci-hotplug-stub.c
index b7bc6e4..d58ea72 100644
--- a/hw/acpi/acpi-pci-hotplug-stub.c
+++ b/hw/acpi/acpi-pci-hotplug-stub.c
@@ -4,7 +4,7 @@
const VMStateDescription vmstate_acpi_pcihp_pci_status;
-void acpi_pcihp_init(Object *owner, AcpiPciHpState *s, PCIBus *root_bus,
+void acpi_pcihp_init(Object *owner, AcpiPciHpState *s,
MemoryRegion *address_space_io, uint16_t io_base)
{
}
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index f8f93a9..1e685f9 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -160,7 +160,7 @@ void crs_replace_with_free_ranges(GPtrArray *ranges,
*/
static void crs_range_merge(GPtrArray *range)
{
- GPtrArray *tmp = g_ptr_array_new_with_free_func(crs_range_free);
+ g_autoptr(GPtrArray) tmp = g_ptr_array_new_with_free_func(crs_range_free);
CrsRangeEntry *entry;
uint64_t range_base, range_limit;
int i;
@@ -191,7 +191,6 @@ static void crs_range_merge(GPtrArray *range)
entry = g_ptr_array_index(tmp, i);
crs_range_insert(range, entry->base, entry->limit);
}
- g_ptr_array_free(tmp, true);
}
static void
@@ -2153,6 +2152,7 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms,
int64_t socket_id = -1, cluster_id = -1, core_id = -1;
uint32_t socket_offset = 0, cluster_offset = 0, core_offset = 0;
uint32_t pptt_start = table_data->len;
+ uint32_t root_offset;
int n;
AcpiTable table = { .sig = "PPTT", .rev = 2,
.oem_id = oem_id, .oem_table_id = oem_table_id };
@@ -2160,6 +2160,18 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms,
acpi_table_begin(&table, table_data);
/*
+ * Build a root node for all the processor nodes. Otherwise when
+ * building a multi-socket system each socket tree is separated
+ * and will be hard for the OS like Linux to know whether the
+ * system is homogeneous.
+ */
+ root_offset = table_data->len - pptt_start;
+ build_processor_hierarchy_node(table_data,
+ (1 << 0) | /* Physical package */
+ (1 << 4), /* Identical Implementation */
+ 0, 0, NULL, 0);
+
+ /*
* This works with the assumption that cpus[n].props.*_id has been
* sorted from top to down levels in mc->possible_cpu_arch_ids().
* Otherwise, the unexpected and duplicated containers will be
@@ -2173,8 +2185,9 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms,
core_id = -1;
socket_offset = table_data->len - pptt_start;
build_processor_hierarchy_node(table_data,
- (1 << 0), /* Physical package */
- 0, socket_id, NULL, 0);
+ (1 << 0) | /* Physical package */
+ (1 << 4), /* Identical Implementation */
+ root_offset, socket_id, NULL, 0);
}
if (mc->smp_props.clusters_supported && mc->smp_props.has_clusters) {
@@ -2184,7 +2197,8 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms,
core_id = -1;
cluster_offset = table_data->len - pptt_start;
build_processor_hierarchy_node(table_data,
- (0 << 0), /* Not a physical package */
+ (0 << 0) | /* Not a physical package */
+ (1 << 4), /* Identical Implementation */
socket_offset, cluster_id, NULL, 0);
}
} else {
@@ -2202,7 +2216,8 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms,
core_id = cpus->cpus[n].props.core_id;
core_offset = table_data->len - pptt_start;
build_processor_hierarchy_node(table_data,
- (0 << 0), /* Not a physical package */
+ (0 << 0) | /* Not a physical package */
+ (1 << 4), /* Identical Implementation */
cluster_offset, core_id, NULL, 0);
}
diff --git a/hw/acpi/bios-linker-loader.c b/hw/acpi/bios-linker-loader.c
index 1080618..c9ffe44 100644
--- a/hw/acpi/bios-linker-loader.c
+++ b/hw/acpi/bios-linker-loader.c
@@ -22,8 +22,6 @@
#include "hw/acpi/bios-linker-loader.h"
#include "hw/nvram/fw_cfg.h"
-#include "qemu/bswap.h"
-
/*
* Linker/loader is a paravirtualized interface that passes commands to guest.
* The commands can be used to request guest to
diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c
index 7a62f8d..95682b7 100644
--- a/hw/acpi/generic_event_device.c
+++ b/hw/acpi/generic_event_device.c
@@ -12,10 +12,13 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "hw/acpi/acpi.h"
+#include "hw/acpi/pcihp.h"
#include "hw/acpi/generic_event_device.h"
+#include "hw/pci/pci.h"
#include "hw/irq.h"
#include "hw/mem/pc-dimm.h"
#include "hw/mem/nvdimm.h"
+#include "hw/pci/pci_device.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
#include "qemu/error-report.h"
@@ -26,6 +29,7 @@ static const uint32_t ged_supported_events[] = {
ACPI_GED_PWR_DOWN_EVT,
ACPI_GED_NVDIMM_HOTPLUG_EVT,
ACPI_GED_CPU_HOTPLUG_EVT,
+ ACPI_GED_PCI_HOTPLUG_EVT,
};
/*
@@ -121,6 +125,12 @@ void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev,
aml_notify(aml_name("\\_SB.NVDR"),
aml_int(0x80)));
break;
+ case ACPI_GED_PCI_HOTPLUG_EVT:
+ aml_append(if_ctx,
+ aml_acquire(aml_name("\\_SB.PCI0.BLCK"), 0xFFFF));
+ aml_append(if_ctx, aml_call0("\\_SB.PCI0.PCNT"));
+ aml_append(if_ctx, aml_release(aml_name("\\_SB.PCI0.BLCK")));
+ break;
default:
/*
* Please make sure all the events in ged_supported_events[]
@@ -227,6 +237,14 @@ static const MemoryRegionOps ged_regs_ops = {
},
};
+static void acpi_ged_device_pre_plug_cb(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
+ acpi_pcihp_device_pre_plug_cb(hotplug_dev, dev, errp);
+ }
+}
+
static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
@@ -240,6 +258,8 @@ static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev,
}
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
acpi_cpu_plug_cb(hotplug_dev, &s->cpuhp_state, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
+ acpi_pcihp_device_plug_cb(hotplug_dev, &s->pcihp_state, dev, errp);
} else {
error_setg(errp, "virt: device plug request for unsupported device"
" type: %s", object_get_typename(OBJECT(dev)));
@@ -256,6 +276,9 @@ static void acpi_ged_unplug_request_cb(HotplugHandler *hotplug_dev,
acpi_memory_unplug_request_cb(hotplug_dev, &s->memhp_state, dev, errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
acpi_cpu_unplug_request_cb(hotplug_dev, &s->cpuhp_state, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
+ acpi_pcihp_device_unplug_request_cb(hotplug_dev, &s->pcihp_state,
+ dev, errp);
} else {
error_setg(errp, "acpi: device unplug request for unsupported device"
" type: %s", object_get_typename(OBJECT(dev)));
@@ -271,6 +294,8 @@ static void acpi_ged_unplug_cb(HotplugHandler *hotplug_dev,
acpi_memory_unplug_cb(&s->memhp_state, dev, errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
acpi_cpu_unplug_cb(&s->cpuhp_state, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
+ acpi_pcihp_device_unplug_cb(hotplug_dev, &s->pcihp_state, dev, errp);
} else {
error_setg(errp, "acpi: device unplug for unsupported device"
" type: %s", object_get_typename(OBJECT(dev)));
@@ -299,6 +324,8 @@ static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev)
sel = ACPI_GED_NVDIMM_HOTPLUG_EVT;
} else if (ev & ACPI_CPU_HOTPLUG_STATUS) {
sel = ACPI_GED_CPU_HOTPLUG_EVT;
+ } else if (ev & ACPI_PCI_HOTPLUG_STATUS) {
+ sel = ACPI_GED_PCI_HOTPLUG_EVT;
} else {
/* Unknown event. Return without generating interrupt. */
warn_report("GED: Unsupported event %d. No irq injected", ev);
@@ -318,6 +345,10 @@ static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev)
static const Property acpi_ged_properties[] = {
DEFINE_PROP_UINT32("ged-event", AcpiGedState, ged_event_bitmap, 0),
+ DEFINE_PROP_BOOL(ACPI_PM_PROP_ACPI_PCIHP_BRIDGE, AcpiGedState,
+ pcihp_state.use_acpi_hotplug_bridge, 0),
+ DEFINE_PROP_LINK("bus", AcpiGedState, pcihp_state.root,
+ TYPE_PCI_BUS, PCIBus *),
};
static const VMStateDescription vmstate_memhp_state = {
@@ -386,6 +417,25 @@ static const VMStateDescription vmstate_ghes_state = {
}
};
+static bool pcihp_needed(void *opaque)
+{
+ AcpiGedState *s = opaque;
+ return s->pcihp_state.use_acpi_hotplug_bridge;
+}
+
+static const VMStateDescription vmstate_pcihp_state = {
+ .name = "acpi-ged/pcihp",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = pcihp_needed,
+ .fields = (const VMStateField[]) {
+ VMSTATE_PCI_HOTPLUG(pcihp_state,
+ AcpiGedState,
+ NULL, NULL),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_acpi_ged = {
.name = "acpi-ged",
.version_id = 1,
@@ -398,6 +448,7 @@ static const VMStateDescription vmstate_acpi_ged = {
&vmstate_memhp_state,
&vmstate_cpuhp_state,
&vmstate_ghes_state,
+ &vmstate_pcihp_state,
NULL
}
};
@@ -406,9 +457,13 @@ static void acpi_ged_realize(DeviceState *dev, Error **errp)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
AcpiGedState *s = ACPI_GED(dev);
+ AcpiPciHpState *pcihp_state = &s->pcihp_state;
uint32_t ged_events;
int i;
+ if (pcihp_state->use_acpi_hotplug_bridge) {
+ s->ged_event_bitmap |= ACPI_GED_PCI_HOTPLUG_EVT;
+ }
ged_events = ctpop32(s->ged_event_bitmap);
for (i = 0; i < ARRAY_SIZE(ged_supported_events) && ged_events; i++) {
@@ -428,6 +483,13 @@ static void acpi_ged_realize(DeviceState *dev, Error **errp)
cpu_hotplug_hw_init(&s->container_cpuhp, OBJECT(dev),
&s->cpuhp_state, 0);
break;
+ case ACPI_GED_PCI_HOTPLUG_EVT:
+ memory_region_init(&s->container_pcihp, OBJECT(dev),
+ ACPI_PCIHP_REGION_NAME, ACPI_PCIHP_SIZE);
+ sysbus_init_mmio(sbd, &s->container_pcihp);
+ acpi_pcihp_init(OBJECT(s), &s->pcihp_state,
+ &s->container_pcihp, 0);
+ qbus_set_hotplug_handler(BUS(s->pcihp_state.root), OBJECT(dev));
}
ged_events--;
}
@@ -469,20 +531,34 @@ static void acpi_ged_initfn(Object *obj)
sysbus_init_mmio(sbd, &ged_st->regs);
}
+static void ged_reset_hold(Object *obj, ResetType type)
+{
+ AcpiGedState *s = ACPI_GED(obj);
+
+ if (s->pcihp_state.use_acpi_hotplug_bridge) {
+ acpi_pcihp_reset(&s->pcihp_state);
+ }
+}
+
static void acpi_ged_class_init(ObjectClass *class, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(class);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(class);
AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(class);
+ ResettableClass *rc = RESETTABLE_CLASS(class);
+ AcpiGedClass *gedc = ACPI_GED_CLASS(class);
dc->desc = "ACPI Generic Event Device";
device_class_set_props(dc, acpi_ged_properties);
dc->vmsd = &vmstate_acpi_ged;
dc->realize = acpi_ged_realize;
+ hc->pre_plug = acpi_ged_device_pre_plug_cb;
hc->plug = acpi_ged_device_plug_cb;
hc->unplug_request = acpi_ged_unplug_request_cb;
hc->unplug = acpi_ged_unplug_cb;
+ resettable_class_set_parent_phases(rc, NULL, ged_reset_hold, NULL,
+ &gedc->parent_phases);
adevc->ospm_status = acpi_ged_ospm_status;
adevc->send_event = acpi_ged_send_event;
@@ -494,6 +570,7 @@ static const TypeInfo acpi_ged_info = {
.instance_size = sizeof(AcpiGedState),
.instance_init = acpi_ged_initfn,
.class_init = acpi_ged_class_init,
+ .class_size = sizeof(AcpiGedClass),
.interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ TYPE_ACPI_DEVICE_IF },
diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c
index 967b674..2b3b493 100644
--- a/hw/acpi/ich9.c
+++ b/hw/acpi/ich9.c
@@ -322,9 +322,10 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, qemu_irq sci_irq)
}
if (pm->acpi_pci_hotplug.use_acpi_hotplug_bridge) {
+ object_property_set_link(OBJECT(lpc_pci), "bus",
+ OBJECT(pci_get_bus(lpc_pci)), &error_abort);
acpi_pcihp_init(OBJECT(lpc_pci),
&pm->acpi_pci_hotplug,
- pci_get_bus(lpc_pci),
pci_address_space_io(lpc_pci),
ACPI_PCIHP_ADDR_ICH9);
@@ -428,6 +429,10 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm)
object_property_add_uint32_ptr(obj, ACPI_PM_PROP_PM_IO_BASE,
&pm->pm_io_base, OBJ_PROP_FLAG_READ);
+ object_property_add_link(obj, "bus", TYPE_PCI_BUS,
+ (Object **)&pm->acpi_pci_hotplug.root,
+ object_property_allow_set_link,
+ OBJ_PROP_LINK_STRONG);
object_property_add(obj, ACPI_PM_PROP_GPE0_BLK, "uint32",
ich9_pm_get_gpe0_blk,
NULL, NULL, pm);
diff --git a/hw/acpi/pci-bridge.c b/hw/acpi/pci-bridge.c
index 7baa703..394a919 100644
--- a/hw/acpi/pci-bridge.c
+++ b/hw/acpi/pci-bridge.c
@@ -35,3 +35,57 @@ void build_pci_bridge_aml(AcpiDevAmlIf *adev, Aml *scope)
}
}
}
+
+Aml *build_pci_bridge_edsm(void)
+{
+ Aml *method, *ifctx;
+ Aml *zero = aml_int(0);
+ Aml *func = aml_arg(2);
+ Aml *ret = aml_local(0);
+ Aml *aidx = aml_local(1);
+ Aml *params = aml_arg(4);
+
+ method = aml_method("EDSM", 5, AML_SERIALIZED);
+
+ /* get supported functions */
+ ifctx = aml_if(aml_equal(func, zero));
+ {
+ /* 1: have supported functions */
+ /* 7: support for function 7 */
+ const uint8_t caps = 1 | BIT(7);
+ build_append_pci_dsm_func0_common(ifctx, ret);
+ aml_append(ifctx, aml_store(aml_int(caps), aml_index(ret, zero)));
+ aml_append(ifctx, aml_return(ret));
+ }
+ aml_append(method, ifctx);
+
+ /* handle specific functions requests */
+ /*
+ * PCI Firmware Specification 3.1
+ * 4.6.7. _DSM for Naming a PCI or PCI Express Device Under
+ * Operating Systems
+ */
+ ifctx = aml_if(aml_equal(func, aml_int(7)));
+ {
+ Aml *pkg = aml_package(2);
+ aml_append(pkg, zero);
+ /* optional, if not impl. should return null string */
+ aml_append(pkg, aml_string("%s", ""));
+ aml_append(ifctx, aml_store(pkg, ret));
+
+ /*
+ * IASL is fine when initializing Package with computational data,
+ * however it makes guest unhappy /it fails to process such AML/.
+ * So use runtime assignment to set acpi-index after initializer
+ * to make OSPM happy.
+ */
+ aml_append(ifctx,
+ aml_store(aml_derefof(aml_index(params, aml_int(0))), aidx));
+ aml_append(ifctx, aml_store(aidx, aml_index(ret, zero)));
+ aml_append(ifctx, aml_return(ret));
+ }
+ aml_append(method, ifctx);
+
+ return method;
+}
+
diff --git a/hw/acpi/pci.c b/hw/acpi/pci.c
index d511a85..2228f12 100644
--- a/hw/acpi/pci.c
+++ b/hw/acpi/pci.c
@@ -301,3 +301,53 @@ void build_srat_generic_affinity_structures(GArray *table_data)
object_child_foreach_recursive(object_get_root(), build_acpi_generic_port,
table_data);
}
+
+Aml *build_pci_host_bridge_osc_method(bool enable_native_pcie_hotplug)
+{
+ Aml *if_ctx;
+ Aml *if_ctx2;
+ Aml *else_ctx;
+ Aml *method;
+ Aml *a_cwd1 = aml_name("CDW1");
+ Aml *a_ctrl = aml_local(0);
+
+ method = aml_method("_OSC", 4, AML_NOTSERIALIZED);
+ aml_append(method, aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1"));
+
+ if_ctx = aml_if(aml_equal(
+ aml_arg(0), aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766")));
+ aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2"));
+ aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3"));
+
+ aml_append(if_ctx, aml_store(aml_name("CDW3"), a_ctrl));
+
+ /*
+ * Always allow native PME, AER (no dependencies)
+ * Allow SHPC (PCI bridges can have SHPC controller)
+ * Disable PCIe Native Hot-plug if ACPI PCI Hot-plug is enabled.
+ */
+ aml_append(if_ctx, aml_and(a_ctrl,
+ aml_int(0x1E | (enable_native_pcie_hotplug ? 0x1 : 0x0)), a_ctrl));
+
+ if_ctx2 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(1))));
+ /* Unknown revision */
+ aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x08), a_cwd1));
+ aml_append(if_ctx, if_ctx2);
+
+ if_ctx2 = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), a_ctrl)));
+ /* Capabilities bits were masked */
+ aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x10), a_cwd1));
+ aml_append(if_ctx, if_ctx2);
+
+ /* Update DWORD3 in the buffer */
+ aml_append(if_ctx, aml_store(a_ctrl, aml_name("CDW3")));
+ aml_append(method, if_ctx);
+
+ else_ctx = aml_else();
+ /* Unrecognized UUID */
+ aml_append(else_ctx, aml_or(a_cwd1, aml_int(4), a_cwd1));
+ aml_append(method, else_ctx);
+
+ aml_append(method, aml_return(aml_arg(3)));
+ return method;
+}
diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c
index 497281a..4922bbc 100644
--- a/hw/acpi/pcihp.c
+++ b/hw/acpi/pcihp.c
@@ -26,7 +26,8 @@
#include "qemu/osdep.h"
#include "hw/acpi/pcihp.h"
-
+#include "hw/acpi/aml-build.h"
+#include "hw/acpi/acpi_aml_interface.h"
#include "hw/pci-host/i440fx.h"
#include "hw/pci/pci.h"
#include "hw/pci/pci_bridge.h"
@@ -39,9 +40,9 @@
#include "migration/vmstate.h"
#include "qapi/error.h"
#include "qom/qom-qobject.h"
+#include "qobject/qnum.h"
#include "trace.h"
-#define ACPI_PCIHP_SIZE 0x0018
#define PCI_UP_BASE 0x0000
#define PCI_DOWN_BASE 0x0004
#define PCI_EJ_BASE 0x0008
@@ -97,10 +98,10 @@ static void *acpi_set_bsel(PCIBus *bus, void *opaque)
return info;
}
-static void acpi_set_pci_info(bool has_bridge_hotplug)
+static void acpi_set_pci_info(AcpiPciHpState *s)
{
static bool bsel_is_set;
- Object *host = acpi_get_i386_pci_host();
+ bool has_bridge_hotplug = s->use_acpi_hotplug_bridge;
PCIBus *bus;
BSELInfo info = { .bsel_alloc = ACPI_PCIHP_BSEL_DEFAULT,
.has_bridge_hotplug = has_bridge_hotplug };
@@ -110,11 +111,8 @@ static void acpi_set_pci_info(bool has_bridge_hotplug)
}
bsel_is_set = true;
- if (!host) {
- return;
- }
- bus = PCI_HOST_BRIDGE(host)->bus;
+ bus = s->root;
if (bus) {
/* Scan all PCI buses. Set property to enable acpi based hotplug. */
pci_for_each_bus_depth_first(bus, acpi_set_bsel, NULL, &info);
@@ -264,7 +262,7 @@ static void acpi_pcihp_update(AcpiPciHpState *s)
void acpi_pcihp_reset(AcpiPciHpState *s)
{
- acpi_set_pci_info(s->use_acpi_hotplug_bridge);
+ acpi_set_pci_info(s);
acpi_pcihp_update(s);
}
@@ -495,13 +493,13 @@ static const MemoryRegionOps acpi_pcihp_io_ops = {
},
};
-void acpi_pcihp_init(Object *owner, AcpiPciHpState *s, PCIBus *root_bus,
+void acpi_pcihp_init(Object *owner, AcpiPciHpState *s,
MemoryRegion *io, uint16_t io_base)
{
s->io_len = ACPI_PCIHP_SIZE;
s->io_base = io_base;
- s->root = root_bus;
+ assert(s->root);
memory_region_init_io(&s->io, owner, &acpi_pcihp_io_ops, s,
"acpi-pci-hotplug", s->io_len);
@@ -513,6 +511,425 @@ void acpi_pcihp_init(Object *owner, AcpiPciHpState *s, PCIBus *root_bus,
OBJ_PROP_FLAG_READ);
}
+void build_append_pci_dsm_func0_common(Aml *ctx, Aml *retvar)
+{
+ Aml *UUID, *ifctx1;
+ uint8_t byte_list[1] = { 0 }; /* nothing supported yet */
+
+ aml_append(ctx, aml_store(aml_buffer(1, byte_list), retvar));
+ /*
+ * PCI Firmware Specification 3.1
+ * 4.6. _DSM Definitions for PCI
+ */
+ UUID = aml_touuid("E5C937D0-3553-4D7A-9117-EA4D19C3434D");
+ ifctx1 = aml_if(aml_lnot(aml_equal(aml_arg(0), UUID)));
+ {
+ /* call is for unsupported UUID, bail out */
+ aml_append(ifctx1, aml_return(retvar));
+ }
+ aml_append(ctx, ifctx1);
+
+ ifctx1 = aml_if(aml_lless(aml_arg(1), aml_int(2)));
+ {
+ /* call is for unsupported REV, bail out */
+ aml_append(ifctx1, aml_return(retvar));
+ }
+ aml_append(ctx, ifctx1);
+}
+
+static Aml *aml_pci_pdsm(void)
+{
+ Aml *method, *ifctx, *ifctx1;
+ Aml *ret = aml_local(0);
+ Aml *caps = aml_local(1);
+ Aml *acpi_index = aml_local(2);
+ Aml *zero = aml_int(0);
+ Aml *one = aml_int(1);
+ Aml *not_supp = aml_int(0xFFFFFFFF);
+ Aml *func = aml_arg(2);
+ Aml *params = aml_arg(4);
+ Aml *bnum = aml_derefof(aml_index(params, aml_int(0)));
+ Aml *sunum = aml_derefof(aml_index(params, aml_int(1)));
+
+ method = aml_method("PDSM", 5, AML_SERIALIZED);
+
+ /* get supported functions */
+ ifctx = aml_if(aml_equal(func, zero));
+ {
+ build_append_pci_dsm_func0_common(ifctx, ret);
+
+ aml_append(ifctx, aml_store(zero, caps));
+ aml_append(ifctx,
+ aml_store(aml_call2("AIDX", bnum, sunum), acpi_index));
+ /*
+ * advertise function 7 if device has acpi-index
+ * acpi_index values:
+ * 0: not present (default value)
+ * FFFFFFFF: not supported (old QEMU without PIDX reg)
+ * other: device's acpi-index
+ */
+ ifctx1 = aml_if(aml_lnot(
+ aml_or(aml_equal(acpi_index, zero),
+ aml_equal(acpi_index, not_supp), NULL)
+ ));
+ {
+ /* have supported functions */
+ aml_append(ifctx1, aml_or(caps, one, caps));
+ /* support for function 7 */
+ aml_append(ifctx1,
+ aml_or(caps, aml_shiftleft(one, aml_int(7)), caps));
+ }
+ aml_append(ifctx, ifctx1);
+
+ aml_append(ifctx, aml_store(caps, aml_index(ret, zero)));
+ aml_append(ifctx, aml_return(ret));
+ }
+ aml_append(method, ifctx);
+
+ /* handle specific functions requests */
+ /*
+ * PCI Firmware Specification 3.1
+ * 4.6.7. _DSM for Naming a PCI or PCI Express Device Under
+ * Operating Systems
+ */
+ ifctx = aml_if(aml_equal(func, aml_int(7)));
+ {
+ Aml *pkg = aml_package(2);
+
+ aml_append(ifctx, aml_store(aml_call2("AIDX", bnum, sunum), acpi_index));
+ aml_append(ifctx, aml_store(pkg, ret));
+ /*
+ * Windows calls func=7 without checking if it's available,
+ * as workaround Microsoft has suggested to return invalid for func7
+ * Package, so return 2 elements package but only initialize elements
+ * when acpi_index is supported and leave them uninitialized, which
+ * leads elements to being Uninitialized ObjectType and should trip
+ * Windows into discarding result as an unexpected and prevent setting
+ * bogus 'PCI Label' on the device.
+ */
+ ifctx1 = aml_if(aml_lnot(aml_lor(
+ aml_equal(acpi_index, zero), aml_equal(acpi_index, not_supp)
+ )));
+ {
+ aml_append(ifctx1, aml_store(acpi_index, aml_index(ret, zero)));
+ /*
+ * optional, if not impl. should return null string
+ */
+ aml_append(ifctx1, aml_store(aml_string("%s", ""),
+ aml_index(ret, one)));
+ }
+ aml_append(ifctx, ifctx1);
+
+ aml_append(ifctx, aml_return(ret));
+ }
+
+ aml_append(method, ifctx);
+ return method;
+}
+
+void build_acpi_pci_hotplug(Aml *table, AmlRegionSpace rs, uint64_t pcihp_addr)
+{
+ Aml *scope;
+ Aml *field;
+ Aml *method;
+
+ scope = aml_scope("_SB.PCI0");
+
+ aml_append(scope,
+ aml_operation_region("PCST", rs, aml_int(pcihp_addr), 0x08));
+ field = aml_field("PCST", AML_DWORD_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS);
+ aml_append(field, aml_named_field("PCIU", 32));
+ aml_append(field, aml_named_field("PCID", 32));
+ aml_append(scope, field);
+
+ aml_append(scope,
+ aml_operation_region("SEJ", rs,
+ aml_int(pcihp_addr + ACPI_PCIHP_SEJ_BASE), 0x04));
+ field = aml_field("SEJ", AML_DWORD_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS);
+ aml_append(field, aml_named_field("B0EJ", 32));
+ aml_append(scope, field);
+
+ aml_append(scope,
+ aml_operation_region("BNMR", rs,
+ aml_int(pcihp_addr + ACPI_PCIHP_BNMR_BASE), 0x08));
+ field = aml_field("BNMR", AML_DWORD_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS);
+ aml_append(field, aml_named_field("BNUM", 32));
+ aml_append(field, aml_named_field("PIDX", 32));
+ aml_append(scope, field);
+
+ aml_append(scope, aml_mutex("BLCK", 0));
+
+ method = aml_method("PCEJ", 2, AML_NOTSERIALIZED);
+ aml_append(method, aml_acquire(aml_name("BLCK"), 0xFFFF));
+ aml_append(method, aml_store(aml_arg(0), aml_name("BNUM")));
+ aml_append(method,
+ aml_store(aml_shiftleft(aml_int(1), aml_arg(1)), aml_name("B0EJ")));
+ aml_append(method, aml_release(aml_name("BLCK")));
+ aml_append(method, aml_return(aml_int(0)));
+ aml_append(scope, method);
+
+ method = aml_method("AIDX", 2, AML_NOTSERIALIZED);
+ aml_append(method, aml_acquire(aml_name("BLCK"), 0xFFFF));
+ aml_append(method, aml_store(aml_arg(0), aml_name("BNUM")));
+ aml_append(method,
+ aml_store(aml_shiftleft(aml_int(1), aml_arg(1)), aml_name("PIDX")));
+ aml_append(method, aml_store(aml_name("PIDX"), aml_local(0)));
+ aml_append(method, aml_release(aml_name("BLCK")));
+ aml_append(method, aml_return(aml_local(0)));
+ aml_append(scope, method);
+
+ aml_append(scope, aml_pci_pdsm());
+
+ aml_append(table, scope);
+}
+
+/* Reserve PCIHP resources */
+void build_append_pcihp_resources(Aml *scope /* \\_SB.PCI0 */,
+ uint64_t io_addr, uint64_t io_len)
+{
+ Aml *dev, *crs;
+
+ dev = aml_device("PHPR");
+ aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A06")));
+ aml_append(dev,
+ aml_name_decl("_UID", aml_string("PCI Hotplug resources")));
+ /* device present, functioning, decoding, not shown in UI */
+ aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
+ crs = aml_resource_template();
+ aml_append(crs, aml_io(AML_DECODE16, io_addr, io_addr, 1, io_len));
+ aml_append(dev, aml_name_decl("_CRS", crs));
+ aml_append(scope, dev);
+}
+
+bool build_append_notification_callback(Aml *parent_scope, const PCIBus *bus)
+{
+ Aml *method;
+ PCIBus *sec;
+ QObject *bsel;
+ int nr_notifiers = 0;
+ GQueue *pcnt_bus_list = g_queue_new();
+
+ QLIST_FOREACH(sec, &bus->child, sibling) {
+ Aml *br_scope = aml_scope("S%.02X", sec->parent_dev->devfn);
+ if (pci_bus_is_root(sec)) {
+ continue;
+ }
+ nr_notifiers = nr_notifiers +
+ build_append_notification_callback(br_scope, sec);
+ /*
+ * add new child scope to parent
+ * and keep track of bus that have PCNT,
+ * bus list is used later to call children PCNTs from this level PCNT
+ */
+ if (nr_notifiers) {
+ g_queue_push_tail(pcnt_bus_list, sec);
+ aml_append(parent_scope, br_scope);
+ }
+ }
+
+ /*
+ * Append PCNT method to notify about events on local and child buses.
+ * ps: hostbridge might not have hotplug (bsel) enabled but might have
+ * child bridges that do have bsel.
+ */
+ method = aml_method("PCNT", 0, AML_NOTSERIALIZED);
+
+ /* If bus supports hotplug select it and notify about local events */
+ bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL);
+ if (bsel) {
+ uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel));
+
+ aml_append(method, aml_store(aml_int(bsel_val), aml_name("BNUM")));
+ aml_append(method, aml_call2("DVNT", aml_name("PCIU"),
+ aml_int(1))); /* Device Check */
+ aml_append(method, aml_call2("DVNT", aml_name("PCID"),
+ aml_int(3))); /* Eject Request */
+ nr_notifiers++;
+ }
+
+ /* Notify about child bus events in any case */
+ while ((sec = g_queue_pop_head(pcnt_bus_list))) {
+ aml_append(method, aml_name("^S%.02X.PCNT", sec->parent_dev->devfn));
+ }
+
+ aml_append(parent_scope, method);
+ qobject_unref(bsel);
+ g_queue_free(pcnt_bus_list);
+ return !!nr_notifiers;
+}
+
+static Aml *aml_pci_device_dsm(void)
+{
+ Aml *method;
+
+ method = aml_method("_DSM", 4, AML_SERIALIZED);
+ {
+ Aml *params = aml_local(0);
+ Aml *pkg = aml_package(2);
+ aml_append(pkg, aml_int(0));
+ aml_append(pkg, aml_int(0));
+ aml_append(method, aml_store(pkg, params));
+ aml_append(method,
+ aml_store(aml_name("BSEL"), aml_index(params, aml_int(0))));
+ aml_append(method,
+ aml_store(aml_name("ASUN"), aml_index(params, aml_int(1))));
+ aml_append(method,
+ aml_return(aml_call5("PDSM", aml_arg(0), aml_arg(1),
+ aml_arg(2), aml_arg(3), params))
+ );
+ }
+ return method;
+}
+
+static Aml *aml_pci_static_endpoint_dsm(PCIDevice *pdev)
+{
+ Aml *method;
+
+ g_assert(pdev->acpi_index != 0);
+ method = aml_method("_DSM", 4, AML_SERIALIZED);
+ {
+ Aml *params = aml_local(0);
+ Aml *pkg = aml_package(1);
+ aml_append(pkg, aml_int(pdev->acpi_index));
+ aml_append(method, aml_store(pkg, params));
+ aml_append(method,
+ aml_return(aml_call5("EDSM", aml_arg(0), aml_arg(1),
+ aml_arg(2), aml_arg(3), params))
+ );
+ }
+ return method;
+}
+
+static void build_append_pcihp_notify_entry(Aml *method, int slot)
+{
+ Aml *if_ctx;
+ int32_t devfn = PCI_DEVFN(slot, 0);
+
+ if_ctx = aml_if(aml_and(aml_arg(0), aml_int(0x1U << slot), NULL));
+ aml_append(if_ctx, aml_notify(aml_name("S%.02X", devfn), aml_arg(1)));
+ aml_append(method, if_ctx);
+}
+
+static bool is_devfn_ignored_generic(const int devfn, const PCIBus *bus)
+{
+ const PCIDevice *pdev = bus->devices[devfn];
+
+ if (PCI_FUNC(devfn)) {
+ if (IS_PCI_BRIDGE(pdev)) {
+ /*
+ * Ignore only hotplugged PCI bridges on !0 functions, but
+ * allow describing cold plugged bridges on all functions
+ */
+ if (DEVICE(pdev)->hotplugged) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static bool is_devfn_ignored_hotplug(const int devfn, const PCIBus *bus)
+{
+ PCIDevice *pdev = bus->devices[devfn];
+ if (pdev) {
+ return is_devfn_ignored_generic(devfn, bus) ||
+ !DEVICE_GET_CLASS(pdev)->hotpluggable ||
+ /* Cold plugged bridges aren't themselves hot-pluggable */
+ (IS_PCI_BRIDGE(pdev) && !DEVICE(pdev)->hotplugged);
+ } else { /* non populated slots */
+ /*
+ * hotplug is supported only for non-multifunction device
+ * so generate device description only for function 0
+ */
+ if (PCI_FUNC(devfn) ||
+ (pci_bus_is_express(bus) && PCI_SLOT(devfn) > 0)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void build_append_pcihp_slots(Aml *parent_scope, PCIBus *bus)
+{
+ int devfn;
+ Aml *dev, *notify_method = NULL, *method;
+ QObject *bsel = object_property_get_qobject(OBJECT(bus),
+ ACPI_PCIHP_PROP_BSEL, NULL);
+ uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel));
+ qobject_unref(bsel);
+
+ aml_append(parent_scope, aml_name_decl("BSEL", aml_int(bsel_val)));
+ notify_method = aml_method("DVNT", 2, AML_NOTSERIALIZED);
+
+ for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
+ int slot = PCI_SLOT(devfn);
+ int adr = slot << 16 | PCI_FUNC(devfn);
+
+ if (is_devfn_ignored_hotplug(devfn, bus)) {
+ continue;
+ }
+
+ if (bus->devices[devfn]) {
+ dev = aml_scope("S%.02X", devfn);
+ } else {
+ dev = aml_device("S%.02X", devfn);
+ aml_append(dev, aml_name_decl("_ADR", aml_int(adr)));
+ }
+
+ /*
+ * Can't declare _SUN here for every device as it changes 'slot'
+ * enumeration order in linux kernel, so use another variable for it
+ */
+ aml_append(dev, aml_name_decl("ASUN", aml_int(slot)));
+ aml_append(dev, aml_pci_device_dsm());
+
+ aml_append(dev, aml_name_decl("_SUN", aml_int(slot)));
+ /* add _EJ0 to make slot hotpluggable */
+ method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
+ aml_append(method,
+ aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN"))
+ );
+ aml_append(dev, method);
+
+ build_append_pcihp_notify_entry(notify_method, slot);
+
+ /* device descriptor has been composed, add it into parent context */
+ aml_append(parent_scope, dev);
+ }
+ aml_append(parent_scope, notify_method);
+}
+
+void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus)
+{
+ int devfn;
+ Aml *dev;
+
+ for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
+ /* ACPI spec: 1.0b: Table 6-2 _ADR Object Bus Types, PCI type */
+ int adr = PCI_SLOT(devfn) << 16 | PCI_FUNC(devfn);
+ PCIDevice *pdev = bus->devices[devfn];
+
+ if (!pdev || is_devfn_ignored_generic(devfn, bus)) {
+ continue;
+ }
+
+ /* start to compose PCI device descriptor */
+ dev = aml_device("S%.02X", devfn);
+ aml_append(dev, aml_name_decl("_ADR", aml_int(adr)));
+
+ call_dev_aml_func(DEVICE(bus->devices[devfn]), dev);
+ /* add _DSM if device has acpi-index set */
+ if (pdev->acpi_index &&
+ !object_property_get_bool(OBJECT(pdev), "hotpluggable",
+ &error_abort)) {
+ aml_append(dev, aml_pci_static_endpoint_dsm(pdev));
+ }
+
+ /* device descriptor has been composed, add it into parent context */
+ aml_append(parent_scope, dev);
+ }
+}
+
const VMStateDescription vmstate_acpi_pcihp_pci_status = {
.name = "acpi_pcihp_pci_status",
.version_id = 1,
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index d98b80d..7a18f18 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -567,7 +567,8 @@ static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
if (s->acpi_pci_hotplug.use_acpi_hotplug_bridge ||
s->acpi_pci_hotplug.use_acpi_root_pci_hotplug) {
- acpi_pcihp_init(OBJECT(s), &s->acpi_pci_hotplug, bus, parent,
+ object_property_set_link(OBJECT(s), "bus", OBJECT(bus), &error_abort);
+ acpi_pcihp_init(OBJECT(s), &s->acpi_pci_hotplug, parent,
ACPI_PCIHP_ADDR_PIIX4);
qbus_set_hotplug_handler(BUS(pci_get_bus(PCI_DEVICE(s))), OBJECT(s));
}
@@ -611,6 +612,8 @@ static const Property piix4_pm_properties[] = {
acpi_pci_hotplug.use_acpi_hotplug_bridge, true),
DEFINE_PROP_BOOL(ACPI_PM_PROP_ACPI_PCI_ROOTHP, PIIX4PMState,
acpi_pci_hotplug.use_acpi_root_pci_hotplug, true),
+ DEFINE_PROP_LINK("bus", PIIX4PMState, acpi_pci_hotplug.root,
+ TYPE_PCI_BUS, PCIBus *),
DEFINE_PROP_BOOL("memory-hotplug-support", PIIX4PMState,
acpi_memory_hotplug.is_enabled, true),
DEFINE_PROP_BOOL("smm-compat", PIIX4PMState, smm_compat, false),
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 1634e26..2aa4b5d 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -34,6 +34,8 @@ config ARM_VIRT
select ACPI_HW_REDUCED
select ACPI_APEI
select ACPI_VIOT
+ select ACPI_PCIHP
+ select ACPI_PCI_BRIDGE
select VIRTIO_MEM_SUPPORTED
select ACPI_CXL
select ACPI_HMAT
diff --git a/hw/arm/allwinner-r40.c b/hw/arm/allwinner-r40.c
index 0bf7008..c8eda39 100644
--- a/hw/arm/allwinner-r40.c
+++ b/hw/arm/allwinner-r40.c
@@ -20,7 +20,6 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
-#include "qemu/bswap.h"
#include "qemu/module.h"
#include "qemu/units.h"
#include "hw/boards.h"
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index becd827..d391cd0 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -15,6 +15,7 @@
#include "hw/arm/boot.h"
#include "hw/arm/linux-boot-if.h"
#include "cpu.h"
+#include "exec/tswap.h"
#include "exec/target_page.h"
#include "system/kvm.h"
#include "system/tcg.h"
@@ -29,6 +30,7 @@
#include "qemu/config-file.h"
#include "qemu/option.h"
#include "qemu/units.h"
+#include "qemu/bswap.h"
/* Kernel boot protocol is specified in the kernel docs
* Documentation/arm/Booting and Documentation/arm64/booting.txt
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
index 2f30c49..ecfae32 100644
--- a/hw/arm/npcm7xx.c
+++ b/hw/arm/npcm7xx.c
@@ -24,7 +24,7 @@
#include "hw/qdev-clock.h"
#include "hw/qdev-properties.h"
#include "qapi/error.h"
-#include "qemu/bswap.h"
+#include "exec/tswap.h"
#include "qemu/units.h"
#include "system/system.h"
#include "target/arm/cpu-qom.h"
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 0dfb8ec..b01fc4f 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -34,6 +34,7 @@
#include "hw/core/cpu.h"
#include "hw/acpi/acpi-defs.h"
#include "hw/acpi/acpi.h"
+#include "hw/acpi/pcihp.h"
#include "hw/nvram/fw_cfg_acpi.h"
#include "hw/acpi/bios-linker-loader.h"
#include "hw/acpi/aml-build.h"
@@ -144,12 +145,21 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap,
int ecam_id = VIRT_ECAM_ID(vms->highmem_ecam);
bool cxl_present = false;
PCIBus *bus = vms->bus;
+ bool acpi_pcihp = false;
+
+ if (vms->acpi_dev) {
+ acpi_pcihp = object_property_get_bool(OBJECT(vms->acpi_dev),
+ ACPI_PM_PROP_ACPI_PCIHP_BRIDGE,
+ NULL);
+ }
+
struct GPEXConfig cfg = {
.mmio32 = memmap[VIRT_PCIE_MMIO],
.pio = memmap[VIRT_PCIE_PIO],
.ecam = memmap[ecam_id],
.irq = irq,
.bus = vms->bus,
+ .pci_native_hotplug = !acpi_pcihp,
};
if (vms->highmem_mmio) {
@@ -897,6 +907,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
const int *irqmap = vms->irqmap;
AcpiTable table = { .sig = "DSDT", .rev = 2, .oem_id = vms->oem_id,
.oem_table_id = vms->oem_table_id };
+ Aml *pci0_scope;
acpi_table_begin(&table, table_data);
dsdt = init_aml_allocator();
@@ -950,6 +961,33 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
aml_append(dsdt, scope);
+ pci0_scope = aml_scope("\\_SB.PCI0");
+
+ aml_append(pci0_scope, build_pci_bridge_edsm());
+ build_append_pci_bus_devices(pci0_scope, vms->bus);
+ if (object_property_find(OBJECT(vms->bus), ACPI_PCIHP_PROP_BSEL)) {
+ build_append_pcihp_slots(pci0_scope, vms->bus);
+ }
+
+ if (vms->acpi_dev) {
+ bool acpi_pcihp;
+
+ acpi_pcihp = object_property_get_bool(OBJECT(vms->acpi_dev),
+ ACPI_PM_PROP_ACPI_PCIHP_BRIDGE,
+ NULL);
+
+ if (acpi_pcihp) {
+ build_acpi_pci_hotplug(dsdt, AML_SYSTEM_MEMORY,
+ memmap[VIRT_ACPI_PCIHP].base);
+ build_append_pcihp_resources(pci0_scope,
+ memmap[VIRT_ACPI_PCIHP].base,
+ memmap[VIRT_ACPI_PCIHP].size);
+
+ build_append_notification_callback(pci0_scope, vms->bus);
+ }
+ }
+ aml_append(dsdt, pci0_scope);
+
/* copy AML table into ACPI tables blob */
g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len);
@@ -1023,7 +1061,10 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
}
acpi_add_table(table_offsets, tables_blob);
- spcr_setup(tables_blob, tables->linker, vms);
+
+ if (ms->acpi_spcr_enabled) {
+ spcr_setup(tables_blob, tables->linker, vms);
+ }
acpi_add_table(table_offsets, tables_blob);
build_dbg2(tables_blob, tables->linker, vms);
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 8070ff7..ef6be36 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -76,6 +76,7 @@
#include "standard-headers/linux/input.h"
#include "hw/arm/smmuv3.h"
#include "hw/acpi/acpi.h"
+#include "hw/acpi/pcihp.h"
#include "target/arm/cpu-qom.h"
#include "target/arm/internals.h"
#include "target/arm/multiprocessing.h"
@@ -186,6 +187,7 @@ static const MemMapEntry base_memmap[] = {
[VIRT_NVDIMM_ACPI] = { 0x09090000, NVDIMM_ACPI_IO_LEN},
[VIRT_PVTIME] = { 0x090a0000, 0x00010000 },
[VIRT_SECURE_GPIO] = { 0x090b0000, 0x00001000 },
+ [VIRT_ACPI_PCIHP] = { 0x090c0000, ACPI_PCIHP_SIZE },
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
[VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 },
@@ -686,8 +688,10 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms)
{
DeviceState *dev;
MachineState *ms = MACHINE(vms);
+ SysBusDevice *sbdev;
int irq = vms->irqmap[VIRT_ACPI_GED];
uint32_t event = ACPI_GED_PWR_DOWN_EVT;
+ bool acpi_pcihp;
if (ms->ram_slots) {
event |= ACPI_GED_MEM_HOTPLUG_EVT;
@@ -699,11 +703,26 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms)
dev = qdev_new(TYPE_ACPI_GED);
qdev_prop_set_uint32(dev, "ged-event", event);
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+ object_property_set_link(OBJECT(dev), "bus", OBJECT(vms->bus), &error_abort);
+ sbdev = SYS_BUS_DEVICE(dev);
+ sysbus_realize_and_unref(sbdev, &error_fatal);
+
+ sysbus_mmio_map_name(sbdev, TYPE_ACPI_GED, vms->memmap[VIRT_ACPI_GED].base);
+ sysbus_mmio_map_name(sbdev, ACPI_MEMHP_REGION_NAME,
+ vms->memmap[VIRT_PCDIMM_ACPI].base);
+
+ acpi_pcihp = object_property_get_bool(OBJECT(dev),
+ ACPI_PM_PROP_ACPI_PCIHP_BRIDGE, NULL);
+
+ if (acpi_pcihp) {
+ int pcihp_region_index;
+
+ pcihp_region_index = sysbus_mmio_map_name(sbdev, ACPI_PCIHP_REGION_NAME,
+ vms->memmap[VIRT_ACPI_PCIHP].base);
+ assert(pcihp_region_index >= 0);
+ }
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_ACPI_GED].base);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, vms->memmap[VIRT_PCDIMM_ACPI].base);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(vms->gic, irq));
+ sysbus_connect_irq(sbdev, 0, qdev_get_gpio_in(vms->gic, irq));
return dev;
}
diff --git a/hw/arm/xen-pvh.c b/hw/arm/xen-pvh.c
index 4b26bcf..1a9eeb0 100644
--- a/hw/arm/xen-pvh.c
+++ b/hw/arm/xen-pvh.c
@@ -10,7 +10,6 @@
#include "hw/boards.h"
#include "system/system.h"
#include "hw/xen/xen-pvh-common.h"
-#include "hw/xen/arch_hvm.h"
#define TYPE_XEN_ARM MACHINE_TYPE_NAME("xenpvh")
diff --git a/hw/block/hd-geometry.c b/hw/block/hd-geometry.c
index f3939e7..db22190 100644
--- a/hw/block/hd-geometry.c
+++ b/hw/block/hd-geometry.c
@@ -33,7 +33,6 @@
#include "qemu/osdep.h"
#include "system/block-backend.h"
#include "qapi/qapi-types-block.h"
-#include "qemu/bswap.h"
#include "hw/block/block.h"
#include "trace.h"
diff --git a/hw/block/meson.build b/hw/block/meson.build
index 6557044..43ed296 100644
--- a/hw/block/meson.build
+++ b/hw/block/meson.build
@@ -13,7 +13,9 @@ system_ss.add(when: 'CONFIG_SSI_M25P80', if_true: files('m25p80_sfdp.c'))
system_ss.add(when: 'CONFIG_SWIM', if_true: files('swim.c'))
system_ss.add(when: 'CONFIG_XEN_BUS', if_true: files('xen-block.c'))
-specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c', 'virtio-blk-common.c'))
-specific_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk.c', 'virtio-blk-common.c'))
+specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c'))
+system_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk-common.c'))
+specific_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk.c'))
+system_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('virtio-blk-common.c'))
subdir('dataplane')
diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c
index 0eebbcd..c0cc5f6 100644
--- a/hw/block/vhost-user-blk.c
+++ b/hw/block/vhost-user-blk.c
@@ -210,6 +210,7 @@ static int vhost_user_blk_stop(VirtIODevice *vdev)
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
int ret;
+ bool force_stop = false;
if (!s->started_vu) {
return 0;
@@ -220,7 +221,11 @@ static int vhost_user_blk_stop(VirtIODevice *vdev)
return 0;
}
- ret = vhost_dev_stop(&s->dev, vdev, true);
+ force_stop = s->skip_get_vring_base_on_force_shutdown &&
+ qemu_force_shutdown_requested();
+
+ ret = force_stop ? vhost_dev_force_stop(&s->dev, vdev, true) :
+ vhost_dev_stop(&s->dev, vdev, true);
if (k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false) < 0) {
error_report("vhost guest notifier cleanup failed: %d", ret);
@@ -584,6 +589,8 @@ static const Property vhost_user_blk_properties[] = {
VIRTIO_BLK_F_DISCARD, true),
DEFINE_PROP_BIT64("write-zeroes", VHostUserBlk, parent_obj.host_features,
VIRTIO_BLK_F_WRITE_ZEROES, true),
+ DEFINE_PROP_BOOL("skip-get-vring-base-on-force-shutdown", VHostUserBlk,
+ skip_get_vring_base_on_force_shutdown, false),
};
static void vhost_user_blk_class_init(ObjectClass *klass, const void *data)
diff --git a/hw/char/riscv_htif.c b/hw/char/riscv_htif.c
index c884be5..a78ea9b 100644
--- a/hw/char/riscv_htif.c
+++ b/hw/char/riscv_htif.c
@@ -29,7 +29,6 @@
#include "qemu/timer.h"
#include "qemu/error-report.h"
#include "system/address-spaces.h"
-#include "exec/tswap.h"
#include "system/dma.h"
#include "system/runstate.h"
#include "trace.h"
diff --git a/hw/core/cpu-system.c b/hw/core/cpu-system.c
index 3c84176..a975405 100644
--- a/hw/core/cpu-system.c
+++ b/hw/core/cpu-system.c
@@ -24,7 +24,7 @@
#include "exec/cputlb.h"
#include "system/memory.h"
#include "exec/tb-flush.h"
-#include "exec/tswap.h"
+#include "qemu/target-info.h"
#include "hw/qdev-core.h"
#include "hw/qdev-properties.h"
#include "hw/core/sysemu-cpu-ops.h"
diff --git a/hw/core/machine-hmp-cmds.c b/hw/core/machine-hmp-cmds.c
index c6325cd..3a612e2 100644
--- a/hw/core/machine-hmp-cmds.c
+++ b/hw/core/machine-hmp-cmds.c
@@ -18,6 +18,7 @@
#include "monitor/monitor.h"
#include "qapi/error.h"
#include "qapi/qapi-builtin-visit.h"
+#include "qapi/qapi-commands-accelerator.h"
#include "qapi/qapi-commands-machine.h"
#include "qobject/qdict.h"
#include "qapi/string-output-visitor.h"
@@ -32,6 +33,7 @@ void hmp_info_cpus(Monitor *mon, const QDict *qdict)
cpu_list = qmp_query_cpus_fast(NULL);
for (cpu = cpu_list; cpu; cpu = cpu->next) {
+ g_autofree char *cpu_model = cpu_model_from_type(cpu->value->qom_type);
int active = ' ';
if (cpu->value->cpu_index == monitor_get_cpu_index(mon)) {
@@ -40,7 +42,8 @@ void hmp_info_cpus(Monitor *mon, const QDict *qdict)
monitor_printf(mon, "%c CPU #%" PRId64 ":", active,
cpu->value->cpu_index);
- monitor_printf(mon, " thread_id=%" PRId64 "\n", cpu->value->thread_id);
+ monitor_printf(mon, " thread_id=%" PRId64 " model=%s\n",
+ cpu->value->thread_id, cpu_model);
}
qapi_free_CpuInfoFastList(cpu_list);
diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c
index d82043e..6aca1a6 100644
--- a/hw/core/machine-qmp-cmds.c
+++ b/hw/core/machine-qmp-cmds.c
@@ -14,12 +14,13 @@
#include "hw/mem/memory-device.h"
#include "qapi/error.h"
#include "qapi/qapi-builtin-visit.h"
+#include "qapi/qapi-commands-accelerator.h"
#include "qapi/qapi-commands-machine.h"
#include "qobject/qobject.h"
#include "qapi/qobject-input-visitor.h"
#include "qapi/type-helpers.h"
#include "qemu/uuid.h"
-#include "qemu/target-info.h"
+#include "qemu/target-info-qapi.h"
#include "qom/qom-qobject.h"
#include "system/hostmem.h"
#include "system/hw_accel.h"
@@ -37,8 +38,7 @@ CpuInfoFastList *qmp_query_cpus_fast(Error **errp)
MachineState *ms = MACHINE(qdev_get_machine());
MachineClass *mc = MACHINE_GET_CLASS(ms);
CpuInfoFastList *head = NULL, **tail = &head;
- SysEmuTarget target = qapi_enum_parse(&SysEmuTarget_lookup, target_name(),
- -1, &error_abort);
+ SysEmuTarget target = target_arch();
CPUState *cpu;
CPU_FOREACH(cpu) {
@@ -47,6 +47,7 @@ CpuInfoFastList *qmp_query_cpus_fast(Error **errp)
value->cpu_index = cpu->cpu_index;
value->qom_path = object_get_canonical_path(OBJECT(cpu));
value->thread_id = cpu->thread_id;
+ value->qom_type = g_strdup(object_get_typename(OBJECT(cpu)));
if (mc->cpu_index_to_instance_props) {
CpuInstanceProperties *props;
@@ -139,8 +140,7 @@ QemuTargetInfo *qmp_query_target(Error **errp)
{
QemuTargetInfo *info = g_malloc0(sizeof(*info));
- info->arch = qapi_enum_parse(&SysEmuTarget_lookup, target_name(), -1,
- &error_abort);
+ info->arch = target_arch();
return info;
}
diff --git a/hw/core/machine.c b/hw/core/machine.c
index e869821..8063271 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -39,6 +39,7 @@
GlobalProperty hw_compat_10_0[] = {
{ "scsi-hd", "dpofua", "off" },
+ { "vfio-pci", "x-migration-load-config-after-iter", "off" },
};
const size_t hw_compat_10_0_len = G_N_ELEMENTS(hw_compat_10_0);
@@ -577,6 +578,20 @@ static void machine_set_nvdimm(Object *obj, bool value, Error **errp)
ms->nvdimms_state->is_enabled = value;
}
+static bool machine_get_spcr(Object *obj, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+
+ return ms->acpi_spcr_enabled;
+}
+
+static void machine_set_spcr(Object *obj, bool value, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+
+ ms->acpi_spcr_enabled = value;
+}
+
static bool machine_get_hmat(Object *obj, Error **errp)
{
MachineState *ms = MACHINE(obj);
@@ -1281,6 +1296,14 @@ static void machine_initfn(Object *obj)
"Table (HMAT)");
}
+ /* SPCR */
+ ms->acpi_spcr_enabled = true;
+ object_property_add_bool(obj, "spcr", machine_get_spcr, machine_set_spcr);
+ object_property_set_description(obj, "spcr",
+ "Set on/off to enable/disable "
+ "ACPI Serial Port Console Redirection "
+ "Table (spcr)");
+
/* default to mc->default_cpus */
ms->smp.cpus = mc->default_cpus;
ms->smp.max_cpus = mc->default_cpus;
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index 24e145d..1f810b7 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -1299,3 +1299,47 @@ const PropertyInfo qdev_prop_vmapple_virtio_blk_variant = {
.set = qdev_propinfo_set_enum,
.set_default_value = qdev_propinfo_set_default_value_enum,
};
+
+/* --- VirtIOGPUOutputList --- */
+
+static void get_virtio_gpu_output_list(Object *obj, Visitor *v,
+ const char *name, void *opaque, Error **errp)
+{
+ VirtIOGPUOutputList **prop_ptr =
+ object_field_prop_ptr(obj, opaque);
+
+ visit_type_VirtIOGPUOutputList(v, name, prop_ptr, errp);
+}
+
+static void set_virtio_gpu_output_list(Object *obj, Visitor *v,
+ const char *name, void *opaque, Error **errp)
+{
+ VirtIOGPUOutputList **prop_ptr =
+ object_field_prop_ptr(obj, opaque);
+ VirtIOGPUOutputList *list;
+
+ if (!visit_type_VirtIOGPUOutputList(v, name, &list, errp)) {
+ return;
+ }
+
+ qapi_free_VirtIOGPUOutputList(*prop_ptr);
+ *prop_ptr = list;
+}
+
+static void release_virtio_gpu_output_list(Object *obj,
+ const char *name, void *opaque)
+{
+ VirtIOGPUOutputList **prop_ptr =
+ object_field_prop_ptr(obj, opaque);
+
+ qapi_free_VirtIOGPUOutputList(*prop_ptr);
+ *prop_ptr = NULL;
+}
+
+const PropertyInfo qdev_prop_virtio_gpu_output_list = {
+ .type = "VirtIOGPUOutputList",
+ .description = "VirtIO GPU output list [{\"name\":\"<name>\"},...]",
+ .get = get_virtio_gpu_output_list,
+ .set = set_virtio_gpu_output_list,
+ .release = release_virtio_gpu_output_list,
+};
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index 147b3ff..b7e8a89 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -2,6 +2,7 @@
#include "hw/qdev-properties.h"
#include "qapi/error.h"
#include "qapi/qapi-types-misc.h"
+#include "qapi/qapi-visit-common.h"
#include "qobject/qlist.h"
#include "qemu/ctype.h"
#include "qemu/error-report.h"
@@ -180,7 +181,8 @@ const PropertyInfo qdev_prop_bit = {
static uint64_t qdev_get_prop_mask64(const Property *prop)
{
- assert(prop->info == &qdev_prop_bit64);
+ assert(prop->info == &qdev_prop_bit64 ||
+ prop->info == &qdev_prop_on_off_auto_bit64);
return 0x1ull << prop->bitnr;
}
@@ -225,6 +227,69 @@ const PropertyInfo qdev_prop_bit64 = {
.set_default_value = set_default_value_bool,
};
+static void prop_get_on_off_auto_bit64(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ Property *prop = opaque;
+ OnOffAutoBit64 *p = object_field_prop_ptr(obj, prop);
+ OnOffAuto value;
+ uint64_t mask = qdev_get_prop_mask64(prop);
+
+ if (p->auto_bits & mask) {
+ value = ON_OFF_AUTO_AUTO;
+ } else if (p->on_bits & mask) {
+ value = ON_OFF_AUTO_ON;
+ } else {
+ value = ON_OFF_AUTO_OFF;
+ }
+
+ visit_type_OnOffAuto(v, name, &value, errp);
+}
+
+static void prop_set_on_off_auto_bit64(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ Property *prop = opaque;
+ OnOffAutoBit64 *p = object_field_prop_ptr(obj, prop);
+ OnOffAuto value;
+ uint64_t mask = qdev_get_prop_mask64(prop);
+
+ if (!visit_type_OnOffAuto(v, name, &value, errp)) {
+ return;
+ }
+
+ switch (value) {
+ case ON_OFF_AUTO_AUTO:
+ p->on_bits &= ~mask;
+ p->auto_bits |= mask;
+ break;
+
+ case ON_OFF_AUTO_ON:
+ p->on_bits |= mask;
+ p->auto_bits &= ~mask;
+ break;
+
+ case ON_OFF_AUTO_OFF:
+ p->on_bits &= ~mask;
+ p->auto_bits &= ~mask;
+ break;
+
+ case ON_OFF_AUTO__MAX:
+ g_assert_not_reached();
+ }
+}
+
+const PropertyInfo qdev_prop_on_off_auto_bit64 = {
+ .type = "OnOffAuto",
+ .description = "on/off/auto",
+ .enum_table = &OnOffAuto_lookup,
+ .get = prop_get_on_off_auto_bit64,
+ .set = prop_set_on_off_auto_bit64,
+ .set_default_value = qdev_propinfo_set_default_value_enum,
+};
+
/* --- bool --- */
static void get_bool(Object *obj, Visitor *v, const char *name, void *opaque,
diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c
index e71367a..ec69e87 100644
--- a/hw/core/sysbus.c
+++ b/hw/core/sysbus.c
@@ -151,6 +151,17 @@ void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr)
sysbus_mmio_map_common(dev, n, addr, false, 0);
}
+int sysbus_mmio_map_name(SysBusDevice *dev, const char *name, hwaddr addr)
+{
+ for (int i = 0; i < dev->num_mmio; i++) {
+ if (!strcmp(dev->mmio[i].memory->name, name)) {
+ sysbus_mmio_map(dev, i, addr);
+ return i;
+ }
+ }
+ return -1;
+}
+
void sysbus_mmio_map_overlap(SysBusDevice *dev, int n, hwaddr addr,
int priority)
{
diff --git a/hw/cxl/cxl-events.c b/hw/cxl/cxl-events.c
index 12dee2e..7583dd9 100644
--- a/hw/cxl/cxl-events.c
+++ b/hw/cxl/cxl-events.c
@@ -8,8 +8,6 @@
*/
#include "qemu/osdep.h"
-
-#include "qemu/bswap.h"
#include "qemu/error-report.h"
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
@@ -260,3 +258,41 @@ void cxl_event_irq_assert(CXLType3Dev *ct3d)
}
}
}
+
+void cxl_create_dc_event_records_for_extents(CXLType3Dev *ct3d,
+ CXLDCEventType type,
+ CXLDCExtentRaw extents[],
+ uint32_t ext_count)
+{
+ CXLEventDynamicCapacity event_rec = {};
+ int i;
+
+ cxl_assign_event_header(&event_rec.hdr,
+ &dynamic_capacity_uuid,
+ (1 << CXL_EVENT_TYPE_INFO),
+ sizeof(event_rec),
+ cxl_device_get_timestamp(&ct3d->cxl_dstate));
+ event_rec.type = type;
+ event_rec.validity_flags = 1;
+ event_rec.host_id = 0;
+ event_rec.updated_region_id = 0;
+ event_rec.extents_avail = CXL_NUM_EXTENTS_SUPPORTED -
+ ct3d->dc.total_extent_count;
+
+ for (i = 0; i < ext_count; i++) {
+ memcpy(&event_rec.dynamic_capacity_extent,
+ &extents[i],
+ sizeof(CXLDCExtentRaw));
+ event_rec.flags = 0;
+ if (i < ext_count - 1) {
+ /* Set "More" flag */
+ event_rec.flags |= BIT(0);
+ }
+
+ if (cxl_event_insert(&ct3d->cxl_dstate,
+ CXL_EVENT_TYPE_DYNAMIC_CAP,
+ (CXLEventRecordRaw *)&event_rec)) {
+ cxl_event_irq_assert(ct3d);
+ }
+ }
+}
diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c
index 299f232..68c7cc9 100644
--- a/hw/cxl/cxl-mailbox-utils.c
+++ b/hw/cxl/cxl-mailbox-utils.c
@@ -18,15 +18,16 @@
#include "hw/pci/pci.h"
#include "hw/pci-bridge/cxl_upstream_port.h"
#include "qemu/cutils.h"
+#include "qemu/host-utils.h"
#include "qemu/log.h"
#include "qemu/units.h"
#include "qemu/uuid.h"
#include "system/hostmem.h"
#include "qemu/range.h"
+#include "qapi/qapi-types-cxl.h"
#define CXL_CAPACITY_MULTIPLIER (256 * MiB)
#define CXL_DC_EVENT_LOG_SIZE 8
-#define CXL_NUM_EXTENTS_SUPPORTED 512
#define CXL_NUM_TAGS_SUPPORTED 0
#define CXL_ALERTS_LIFE_USED_WARN_THRESH (1 << 0)
#define CXL_ALERTS_OVER_TEMP_WARN_THRESH (1 << 1)
@@ -117,6 +118,13 @@ enum {
#define GET_PHYSICAL_PORT_STATE 0x1
TUNNEL = 0x53,
#define MANAGEMENT_COMMAND 0x0
+ FMAPI_DCD_MGMT = 0x56,
+ #define GET_DCD_INFO 0x0
+ #define GET_HOST_DC_REGION_CONFIG 0x1
+ #define SET_DC_REGION_CONFIG 0x2
+ #define GET_DC_REGION_EXTENT_LIST 0x3
+ #define INITIATE_DC_ADD 0x4
+ #define INITIATE_DC_RELEASE 0x5
};
/* CCI Message Format CXL r3.1 Figure 7-19 */
@@ -2750,7 +2758,7 @@ static CXLRetCode cmd_dcd_get_dyn_cap_ext_list(const struct cxl_cmd *cmd,
uint16_t out_pl_len, size;
CXLDCExtent *ent;
- if (start_extent_id > ct3d->dc.total_extent_count) {
+ if (start_extent_id > ct3d->dc.nr_extents_accepted) {
return CXL_MBOX_INVALID_INPUT;
}
@@ -2761,7 +2769,7 @@ static CXLRetCode cmd_dcd_get_dyn_cap_ext_list(const struct cxl_cmd *cmd,
out_pl_len = sizeof(*out) + record_count * sizeof(out->records[0]);
stl_le_p(&out->count, record_count);
- stl_le_p(&out->total_extents, ct3d->dc.total_extent_count);
+ stl_le_p(&out->total_extents, ct3d->dc.nr_extents_accepted);
stl_le_p(&out->generation_num, ct3d->dc.ext_list_gen_seq);
if (record_count > 0) {
@@ -2883,16 +2891,20 @@ void cxl_extent_group_list_insert_tail(CXLDCExtentGroupList *list,
QTAILQ_INSERT_TAIL(list, group, node);
}
-void cxl_extent_group_list_delete_front(CXLDCExtentGroupList *list)
+uint32_t cxl_extent_group_list_delete_front(CXLDCExtentGroupList *list)
{
CXLDCExtent *ent, *ent_next;
CXLDCExtentGroup *group = QTAILQ_FIRST(list);
+ uint32_t extents_deleted = 0;
QTAILQ_REMOVE(list, group, node);
QTAILQ_FOREACH_SAFE(ent, &group->list, node, ent_next) {
cxl_remove_extent_from_extent_list(&group->list, ent);
+ extents_deleted++;
}
g_free(group);
+
+ return extents_deleted;
}
/*
@@ -3011,7 +3023,7 @@ static CXLRetCode cmd_dcd_add_dyn_cap_rsp(const struct cxl_cmd *cmd,
CXLUpdateDCExtentListInPl *in = (void *)payload_in;
CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
CXLDCExtentList *extent_list = &ct3d->dc.extents;
- uint32_t i;
+ uint32_t i, num;
uint64_t dpa, len;
CXLRetCode ret;
@@ -3020,7 +3032,8 @@ static CXLRetCode cmd_dcd_add_dyn_cap_rsp(const struct cxl_cmd *cmd,
}
if (in->num_entries_updated == 0) {
- cxl_extent_group_list_delete_front(&ct3d->dc.extents_pending);
+ num = cxl_extent_group_list_delete_front(&ct3d->dc.extents_pending);
+ ct3d->dc.total_extent_count -= num;
return CXL_MBOX_SUCCESS;
}
@@ -3051,10 +3064,12 @@ static CXLRetCode cmd_dcd_add_dyn_cap_rsp(const struct cxl_cmd *cmd,
cxl_insert_extent_to_extent_list(extent_list, dpa, len, NULL, 0);
ct3d->dc.total_extent_count += 1;
+ ct3d->dc.nr_extents_accepted += 1;
ct3_set_region_block_backed(ct3d, dpa, len);
}
/* Remove the first extent group in the pending list */
- cxl_extent_group_list_delete_front(&ct3d->dc.extents_pending);
+ num = cxl_extent_group_list_delete_front(&ct3d->dc.extents_pending);
+ ct3d->dc.total_extent_count -= num;
return CXL_MBOX_SUCCESS;
}
@@ -3160,7 +3175,7 @@ free_and_exit:
}
*updated_list_size = 0;
} else {
- *updated_list_size = ct3d->dc.total_extent_count + cnt_delta;
+ *updated_list_size = ct3d->dc.nr_extents_accepted + cnt_delta;
}
return ret;
@@ -3222,11 +3237,495 @@ static CXLRetCode cmd_dcd_release_dyn_cap(const struct cxl_cmd *cmd,
ct3_set_region_block_backed(ct3d, ent->start_dpa, ent->len);
cxl_remove_extent_from_extent_list(&updated_list, ent);
}
- ct3d->dc.total_extent_count = updated_list_size;
+ ct3d->dc.total_extent_count += (updated_list_size -
+ ct3d->dc.nr_extents_accepted);
+
+ ct3d->dc.nr_extents_accepted = updated_list_size;
+
+ return CXL_MBOX_SUCCESS;
+}
+
+/* CXL r3.2 section 7.6.7.6.1: Get DCD Info (Opcode 5600h) */
+static CXLRetCode cmd_fm_get_dcd_info(const struct cxl_cmd *cmd,
+ uint8_t *payload_in,
+ size_t len_in,
+ uint8_t *payload_out,
+ size_t *len_out,
+ CXLCCI *cci)
+{
+ struct {
+ uint8_t num_hosts;
+ uint8_t num_regions_supported;
+ uint8_t rsvd1[2];
+ uint16_t supported_add_sel_policy_bitmask;
+ uint8_t rsvd2[2];
+ uint16_t supported_removal_policy_bitmask;
+ uint8_t sanitize_on_release_bitmask;
+ uint8_t rsvd3;
+ uint64_t total_dynamic_capacity;
+ uint64_t region_blk_size_bitmasks[8];
+ } QEMU_PACKED *out = (void *)payload_out;
+ CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
+ CXLDCRegion *region;
+ int i;
+
+ out->num_hosts = 1;
+ out->num_regions_supported = ct3d->dc.num_regions;
+ stw_le_p(&out->supported_add_sel_policy_bitmask,
+ BIT(CXL_EXTENT_SELECTION_POLICY_PRESCRIPTIVE));
+ stw_le_p(&out->supported_removal_policy_bitmask,
+ BIT(CXL_EXTENT_REMOVAL_POLICY_PRESCRIPTIVE));
+ out->sanitize_on_release_bitmask = 0;
+
+ stq_le_p(&out->total_dynamic_capacity,
+ ct3d->dc.total_capacity / CXL_CAPACITY_MULTIPLIER);
+
+ for (i = 0; i < ct3d->dc.num_regions; i++) {
+ region = &ct3d->dc.regions[i];
+ memcpy(&out->region_blk_size_bitmasks[i],
+ &region->supported_blk_size_bitmask,
+ sizeof(out->region_blk_size_bitmasks[i]));
+ }
+
+ *len_out = sizeof(*out);
+ return CXL_MBOX_SUCCESS;
+}
+
+static void build_dsmas_flags(uint8_t *flags, CXLDCRegion *region)
+{
+ *flags = 0;
+
+ if (region->nonvolatile) {
+ *flags |= BIT(CXL_DSMAS_FLAGS_NONVOLATILE);
+ }
+ if (region->sharable) {
+ *flags |= BIT(CXL_DSMAS_FLAGS_SHARABLE);
+ }
+ if (region->hw_managed_coherency) {
+ *flags |= BIT(CXL_DSMAS_FLAGS_HW_MANAGED_COHERENCY);
+ }
+ if (region->ic_specific_dc_management) {
+ *flags |= BIT(CXL_DSMAS_FLAGS_IC_SPECIFIC_DC_MANAGEMENT);
+ }
+ if (region->rdonly) {
+ *flags |= BIT(CXL_DSMAS_FLAGS_RDONLY);
+ }
+}
+
+/*
+ * CXL r3.2 section 7.6.7.6.2:
+ * Get Host DC Region Configuration (Opcode 5601h)
+ */
+static CXLRetCode cmd_fm_get_host_dc_region_config(const struct cxl_cmd *cmd,
+ uint8_t *payload_in,
+ size_t len_in,
+ uint8_t *payload_out,
+ size_t *len_out,
+ CXLCCI *cci)
+{
+ struct {
+ uint16_t host_id;
+ uint8_t region_cnt;
+ uint8_t start_rid;
+ } QEMU_PACKED *in = (void *)payload_in;
+ struct {
+ uint16_t host_id;
+ uint8_t num_regions;
+ uint8_t regions_returned;
+ struct {
+ uint64_t base;
+ uint64_t decode_len;
+ uint64_t region_len;
+ uint64_t block_size;
+ uint8_t flags;
+ uint8_t rsvd1[3];
+ uint8_t sanitize;
+ uint8_t rsvd2[3];
+ } QEMU_PACKED records[];
+ } QEMU_PACKED *out = (void *)payload_out;
+ struct {
+ uint32_t num_extents_supported;
+ uint32_t num_extents_available;
+ uint32_t num_tags_supported;
+ uint32_t num_tags_available;
+ } QEMU_PACKED *extra_out;
+ CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
+ uint16_t record_count, out_pl_len, i;
+
+ if (in->start_rid >= ct3d->dc.num_regions) {
+ return CXL_MBOX_INVALID_INPUT;
+ }
+ record_count = MIN(ct3d->dc.num_regions - in->start_rid, in->region_cnt);
+
+ out_pl_len = sizeof(*out) + record_count * sizeof(out->records[0]);
+ extra_out = (void *)out + out_pl_len;
+ out_pl_len += sizeof(*extra_out);
+
+ assert(out_pl_len <= CXL_MAILBOX_MAX_PAYLOAD_SIZE);
+
+ stw_le_p(&out->host_id, 0);
+ out->num_regions = ct3d->dc.num_regions;
+ out->regions_returned = record_count;
+
+ for (i = 0; i < record_count; i++) {
+ stq_le_p(&out->records[i].base,
+ ct3d->dc.regions[in->start_rid + i].base);
+ stq_le_p(&out->records[i].decode_len,
+ ct3d->dc.regions[in->start_rid + i].decode_len /
+ CXL_CAPACITY_MULTIPLIER);
+ stq_le_p(&out->records[i].region_len,
+ ct3d->dc.regions[in->start_rid + i].len);
+ stq_le_p(&out->records[i].block_size,
+ ct3d->dc.regions[in->start_rid + i].block_size);
+ build_dsmas_flags(&out->records[i].flags,
+ &ct3d->dc.regions[in->start_rid + i]);
+ /* Sanitize is bit 0 of flags. */
+ out->records[i].sanitize =
+ ct3d->dc.regions[in->start_rid + i].flags & BIT(0);
+ }
+
+ stl_le_p(&extra_out->num_extents_supported, CXL_NUM_EXTENTS_SUPPORTED);
+ stl_le_p(&extra_out->num_extents_available, CXL_NUM_EXTENTS_SUPPORTED -
+ ct3d->dc.total_extent_count);
+ stl_le_p(&extra_out->num_tags_supported, CXL_NUM_TAGS_SUPPORTED);
+ stl_le_p(&extra_out->num_tags_available, CXL_NUM_TAGS_SUPPORTED);
+
+ *len_out = out_pl_len;
+ return CXL_MBOX_SUCCESS;
+}
+
+/* CXL r3.2 section 7.6.7.6.3: Set Host DC Region Configuration (Opcode 5602) */
+static CXLRetCode cmd_fm_set_dc_region_config(const struct cxl_cmd *cmd,
+ uint8_t *payload_in,
+ size_t len_in,
+ uint8_t *payload_out,
+ size_t *len_out,
+ CXLCCI *cci)
+{
+ struct {
+ uint8_t reg_id;
+ uint8_t rsvd[3];
+ uint64_t block_sz;
+ uint8_t flags;
+ uint8_t rsvd2[3];
+ } QEMU_PACKED *in = (void *)payload_in;
+ CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
+ CXLEventDynamicCapacity dcEvent = {};
+ CXLDCRegion *region = &ct3d->dc.regions[in->reg_id];
+
+ /*
+ * CXL r3.2 7.6.7.6.3: Set DC Region Configuration
+ * This command shall fail with Unsupported when the Sanitize on Release
+ * field does not match the region’s configuration... and the device
+ * does not support reconfiguration of the Sanitize on Release setting.
+ *
+ * Currently not reconfigurable, so always fail if sanitize bit (bit 0)
+ * doesn't match.
+ */
+ if ((in->flags & 0x1) != (region->flags & 0x1)) {
+ return CXL_MBOX_UNSUPPORTED;
+ }
+
+ if (in->reg_id >= DCD_MAX_NUM_REGION) {
+ return CXL_MBOX_UNSUPPORTED;
+ }
+
+ /* Check that no extents are in the region being reconfigured */
+ if (!bitmap_empty(region->blk_bitmap, region->len / region->block_size)) {
+ return CXL_MBOX_UNSUPPORTED;
+ }
+
+ /* Check that new block size is supported */
+ if (!is_power_of_2(in->block_sz) ||
+ !(in->block_sz & region->supported_blk_size_bitmask)) {
+ return CXL_MBOX_INVALID_INPUT;
+ }
+
+ /* Return success if new block size == current block size */
+ if (in->block_sz == region->block_size) {
+ return CXL_MBOX_SUCCESS;
+ }
+
+ /* Free bitmap and create new one for new block size. */
+ qemu_mutex_lock(&region->bitmap_lock);
+ g_free(region->blk_bitmap);
+ region->blk_bitmap = bitmap_new(region->len / in->block_sz);
+ qemu_mutex_unlock(&region->bitmap_lock);
+ region->block_size = in->block_sz;
+
+ /* Create event record and insert into event log */
+ cxl_assign_event_header(&dcEvent.hdr,
+ &dynamic_capacity_uuid,
+ (1 << CXL_EVENT_TYPE_INFO),
+ sizeof(dcEvent),
+ cxl_device_get_timestamp(&ct3d->cxl_dstate));
+ dcEvent.type = DC_EVENT_REGION_CONFIG_UPDATED;
+ dcEvent.validity_flags = 1;
+ dcEvent.host_id = 0;
+ dcEvent.updated_region_id = in->reg_id;
+
+ if (cxl_event_insert(&ct3d->cxl_dstate,
+ CXL_EVENT_TYPE_DYNAMIC_CAP,
+ (CXLEventRecordRaw *)&dcEvent)) {
+ cxl_event_irq_assert(ct3d);
+ }
+ return CXL_MBOX_SUCCESS;
+}
+
+/* CXL r3.2 section 7.6.7.6.4: Get DC Region Extent Lists (Opcode 5603h) */
+static CXLRetCode cmd_fm_get_dc_region_extent_list(const struct cxl_cmd *cmd,
+ uint8_t *payload_in,
+ size_t len_in,
+ uint8_t *payload_out,
+ size_t *len_out,
+ CXLCCI *cci)
+{
+ struct {
+ uint16_t host_id;
+ uint8_t rsvd[2];
+ uint32_t extent_cnt;
+ uint32_t start_extent_id;
+ } QEMU_PACKED *in = (void *)payload_in;
+ struct {
+ uint16_t host_id;
+ uint8_t rsvd[2];
+ uint32_t start_extent_id;
+ uint32_t extents_returned;
+ uint32_t total_extents;
+ uint32_t list_generation_num;
+ uint8_t rsvd2[4];
+ CXLDCExtentRaw records[];
+ } QEMU_PACKED *out = (void *)payload_out;
+ QEMU_BUILD_BUG_ON(sizeof(*in) != 0xc);
+ CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
+ CXLDCExtent *ent;
+ CXLDCExtentRaw *out_rec;
+ uint16_t record_count = 0, record_done = 0, i = 0;
+ uint16_t out_pl_len, max_size;
+
+ if (in->host_id != 0) {
+ return CXL_MBOX_INVALID_INPUT;
+ }
+
+ if (in->start_extent_id > ct3d->dc.nr_extents_accepted) {
+ return CXL_MBOX_INVALID_INPUT;
+ }
+ record_count = MIN(in->extent_cnt,
+ ct3d->dc.nr_extents_accepted - in->start_extent_id);
+ max_size = CXL_MAILBOX_MAX_PAYLOAD_SIZE - sizeof(*out);
+ record_count = MIN(record_count, max_size / sizeof(out->records[0]));
+ out_pl_len = sizeof(*out) + record_count * sizeof(out->records[0]);
+
+ stw_le_p(&out->host_id, in->host_id);
+ stl_le_p(&out->start_extent_id, in->start_extent_id);
+ stl_le_p(&out->extents_returned, record_count);
+ stl_le_p(&out->total_extents, ct3d->dc.nr_extents_accepted);
+ stl_le_p(&out->list_generation_num, ct3d->dc.ext_list_gen_seq);
+
+ if (record_count > 0) {
+ QTAILQ_FOREACH(ent, &ct3d->dc.extents, node) {
+ if (i++ < in->start_extent_id) {
+ continue;
+ }
+ out_rec = &out->records[record_done];
+ stq_le_p(&out_rec->start_dpa, ent->start_dpa);
+ stq_le_p(&out_rec->len, ent->len);
+ memcpy(&out_rec->tag, ent->tag, 0x10);
+ stw_le_p(&out_rec->shared_seq, ent->shared_seq);
+
+ record_done++;
+ if (record_done == record_count) {
+ break;
+ }
+ }
+ }
+
+ *len_out = out_pl_len;
return CXL_MBOX_SUCCESS;
}
+/*
+ * Helper function to convert CXLDCExtentRaw to CXLUpdateDCExtentListInPl
+ * in order to reuse cxl_detect_malformed_extent_list() function which accepts
+ * CXLUpdateDCExtentListInPl as a parameter.
+ */
+static void convert_raw_extents(CXLDCExtentRaw raw_extents[],
+ CXLUpdateDCExtentListInPl *extent_list,
+ int count)
+{
+ int i;
+
+ extent_list->num_entries_updated = count;
+
+ for (i = 0; i < count; i++) {
+ extent_list->updated_entries[i].start_dpa = raw_extents[i].start_dpa;
+ extent_list->updated_entries[i].len = raw_extents[i].len;
+ }
+}
+
+/* CXL r3.2 Section 7.6.7.6.5: Initiate Dynamic Capacity Add (Opcode 5604h) */
+static CXLRetCode cmd_fm_initiate_dc_add(const struct cxl_cmd *cmd,
+ uint8_t *payload_in,
+ size_t len_in,
+ uint8_t *payload_out,
+ size_t *len_out,
+ CXLCCI *cci)
+{
+ struct {
+ uint16_t host_id;
+ uint8_t selection_policy;
+ uint8_t reg_num;
+ uint64_t length;
+ uint8_t tag[0x10];
+ uint32_t ext_count;
+ CXLDCExtentRaw extents[];
+ } QEMU_PACKED *in = (void *)payload_in;
+ CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
+ int i, rc;
+
+ switch (in->selection_policy) {
+ case CXL_EXTENT_SELECTION_POLICY_PRESCRIPTIVE: {
+ /* Adding extents exceeds device's extent tracking ability. */
+ if (in->ext_count + ct3d->dc.total_extent_count >
+ CXL_NUM_EXTENTS_SUPPORTED) {
+ return CXL_MBOX_RESOURCES_EXHAUSTED;
+ }
+
+ g_autofree CXLUpdateDCExtentListInPl *list =
+ g_malloc0(sizeof(*list) +
+ in->ext_count * sizeof(*list->updated_entries));
+
+ convert_raw_extents(in->extents, list, in->ext_count);
+ rc = cxl_detect_malformed_extent_list(ct3d, list);
+
+ for (i = 0; i < in->ext_count; i++) {
+ CXLDCExtentRaw *ext = &in->extents[i];
+
+ /* Check requested extents do not overlap with pending ones. */
+ if (cxl_extent_groups_overlaps_dpa_range(&ct3d->dc.extents_pending,
+ ext->start_dpa,
+ ext->len)) {
+ return CXL_MBOX_INVALID_EXTENT_LIST;
+ }
+ /* Check requested extents do not overlap with existing ones. */
+ if (cxl_extents_overlaps_dpa_range(&ct3d->dc.extents,
+ ext->start_dpa,
+ ext->len)) {
+ return CXL_MBOX_INVALID_EXTENT_LIST;
+ }
+ }
+
+ if (rc) {
+ return rc;
+ }
+
+ CXLDCExtentGroup *group = NULL;
+ for (i = 0; i < in->ext_count; i++) {
+ CXLDCExtentRaw *ext = &in->extents[i];
+
+ group = cxl_insert_extent_to_extent_group(group, ext->start_dpa,
+ ext->len, ext->tag,
+ ext->shared_seq);
+ }
+
+ cxl_extent_group_list_insert_tail(&ct3d->dc.extents_pending, group);
+ ct3d->dc.total_extent_count += in->ext_count;
+ cxl_create_dc_event_records_for_extents(ct3d,
+ DC_EVENT_ADD_CAPACITY,
+ in->extents,
+ in->ext_count);
+
+ return CXL_MBOX_SUCCESS;
+ }
+ default: {
+ qemu_log_mask(LOG_UNIMP,
+ "CXL extent selection policy not supported.\n");
+ return CXL_MBOX_INVALID_INPUT;
+ }
+ }
+}
+
+#define CXL_EXTENT_REMOVAL_POLICY_MASK 0x0F
+#define CXL_FORCED_REMOVAL_MASK (1 << 4)
+/*
+ * CXL r3.2 Section 7.6.7.6.6:
+ * Initiate Dynamic Capacity Release (Opcode 5605h)
+ */
+static CXLRetCode cmd_fm_initiate_dc_release(const struct cxl_cmd *cmd,
+ uint8_t *payload_in,
+ size_t len_in,
+ uint8_t *payload_out,
+ size_t *len_out,
+ CXLCCI *cci)
+{
+ struct {
+ uint16_t host_id;
+ uint8_t flags;
+ uint8_t reg_num;
+ uint64_t length;
+ uint8_t tag[0x10];
+ uint32_t ext_count;
+ CXLDCExtentRaw extents[];
+ } QEMU_PACKED *in = (void *)payload_in;
+ CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
+ int i, rc;
+
+ switch (in->flags & CXL_EXTENT_REMOVAL_POLICY_MASK) {
+ case CXL_EXTENT_REMOVAL_POLICY_PRESCRIPTIVE: {
+ CXLDCExtentList updated_list;
+ uint32_t updated_list_size;
+ g_autofree CXLUpdateDCExtentListInPl *list =
+ g_malloc0(sizeof(*list) +
+ in->ext_count * sizeof(*list->updated_entries));
+
+ convert_raw_extents(in->extents, list, in->ext_count);
+ rc = cxl_detect_malformed_extent_list(ct3d, list);
+ if (rc) {
+ return rc;
+ }
+
+ /*
+ * Fail with Invalid PA if an extent is pending and Forced Removal
+ * flag not set.
+ */
+ if (!(in->flags & CXL_FORCED_REMOVAL_MASK)) {
+ for (i = 0; i < in->ext_count; i++) {
+ CXLDCExtentRaw ext = in->extents[i];
+ /*
+ * Check requested extents don't overlap with pending
+ * extents.
+ */
+ if (cxl_extent_groups_overlaps_dpa_range(
+ &ct3d->dc.extents_pending,
+ ext.start_dpa,
+ ext.len)) {
+ return CXL_MBOX_INVALID_PA;
+ }
+ }
+ }
+
+ rc = cxl_dc_extent_release_dry_run(ct3d,
+ list,
+ &updated_list,
+ &updated_list_size);
+ if (rc) {
+ return rc;
+ }
+ cxl_create_dc_event_records_for_extents(ct3d,
+ DC_EVENT_RELEASE_CAPACITY,
+ in->extents,
+ in->ext_count);
+ return CXL_MBOX_SUCCESS;
+ }
+ default: {
+ qemu_log_mask(LOG_UNIMP,
+ "CXL extent removal policy not supported.\n");
+ return CXL_MBOX_INVALID_INPUT;
+ }
+ }
+}
+
static const struct cxl_cmd cxl_cmd_set[256][256] = {
[INFOSTAT][BACKGROUND_OPERATION_ABORT] = { "BACKGROUND_OPERATION_ABORT",
cmd_infostat_bg_op_abort, 0, 0 },
@@ -3340,6 +3839,36 @@ static const struct cxl_cmd cxl_cmd_set_sw[256][256] = {
cmd_tunnel_management_cmd, ~0, 0 },
};
+static const struct cxl_cmd cxl_cmd_set_fm_dcd[256][256] = {
+ [FMAPI_DCD_MGMT][GET_DCD_INFO] = { "GET_DCD_INFO",
+ cmd_fm_get_dcd_info, 0, 0 },
+ [FMAPI_DCD_MGMT][GET_HOST_DC_REGION_CONFIG] = { "GET_HOST_DC_REGION_CONFIG",
+ cmd_fm_get_host_dc_region_config, 4, 0 },
+ [FMAPI_DCD_MGMT][SET_DC_REGION_CONFIG] = { "SET_DC_REGION_CONFIG",
+ cmd_fm_set_dc_region_config, 16,
+ (CXL_MBOX_CONFIG_CHANGE_COLD_RESET |
+ CXL_MBOX_CONFIG_CHANGE_CONV_RESET |
+ CXL_MBOX_CONFIG_CHANGE_CXL_RESET |
+ CXL_MBOX_IMMEDIATE_CONFIG_CHANGE |
+ CXL_MBOX_IMMEDIATE_DATA_CHANGE) },
+ [FMAPI_DCD_MGMT][GET_DC_REGION_EXTENT_LIST] = { "GET_DC_REGION_EXTENT_LIST",
+ cmd_fm_get_dc_region_extent_list, 12, 0 },
+ [FMAPI_DCD_MGMT][INITIATE_DC_ADD] = { "INIT_DC_ADD",
+ cmd_fm_initiate_dc_add, ~0,
+ (CXL_MBOX_CONFIG_CHANGE_COLD_RESET |
+ CXL_MBOX_CONFIG_CHANGE_CONV_RESET |
+ CXL_MBOX_CONFIG_CHANGE_CXL_RESET |
+ CXL_MBOX_IMMEDIATE_CONFIG_CHANGE |
+ CXL_MBOX_IMMEDIATE_DATA_CHANGE) },
+ [FMAPI_DCD_MGMT][INITIATE_DC_RELEASE] = { "INIT_DC_RELEASE",
+ cmd_fm_initiate_dc_release, ~0,
+ (CXL_MBOX_CONFIG_CHANGE_COLD_RESET |
+ CXL_MBOX_CONFIG_CHANGE_CONV_RESET |
+ CXL_MBOX_CONFIG_CHANGE_CXL_RESET |
+ CXL_MBOX_IMMEDIATE_CONFIG_CHANGE |
+ CXL_MBOX_IMMEDIATE_DATA_CHANGE) },
+};
+
/*
* While the command is executing in the background, the device should
* update the percentage complete in the Background Command Status Register
@@ -3614,7 +4143,12 @@ void cxl_initialize_t3_fm_owned_ld_mctpcci(CXLCCI *cci, DeviceState *d,
DeviceState *intf,
size_t payload_max)
{
+ CXLType3Dev *ct3d = CXL_TYPE3(d);
+
cxl_copy_cci_commands(cci, cxl_cmd_set_t3_fm_owned_ld_mctp);
+ if (ct3d->dc.num_regions) {
+ cxl_copy_cci_commands(cci, cxl_cmd_set_fm_dcd);
+ }
cci->d = d;
cci->intf = intf;
cxl_init_cci(cci, payload_max);
diff --git a/hw/display/artist.c b/hw/display/artist.c
index 3fafc8a..3c884c9 100644
--- a/hw/display/artist.c
+++ b/hw/display/artist.c
@@ -12,6 +12,7 @@
#include "qemu/log.h"
#include "qemu/module.h"
#include "qemu/units.h"
+#include "qemu/bswap.h"
#include "qapi/error.h"
#include "hw/sysbus.h"
#include "hw/loader.h"
diff --git a/hw/display/ati.c b/hw/display/ati.c
index 7de2773..f7c0006 100644
--- a/hw/display/ati.c
+++ b/hw/display/ati.c
@@ -22,6 +22,7 @@
#include "vga-access.h"
#include "hw/qdev-properties.h"
#include "vga_regs.h"
+#include "qemu/bswap.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "qemu/error-report.h"
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 20475eb..90b89cf 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -26,7 +26,7 @@
#include "qemu/units.h"
#include "system/reset.h"
#include "qapi/error.h"
-#include "exec/tswap.h"
+#include "qemu/target-info.h"
#include "hw/display/vga.h"
#include "hw/i386/x86.h"
#include "hw/pci/pci.h"
diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c
index 9eb806b..7269477 100644
--- a/hw/display/virtio-gpu-base.c
+++ b/hw/display/virtio-gpu-base.c
@@ -19,6 +19,7 @@
#include "qemu/error-report.h"
#include "hw/display/edid.h"
#include "trace.h"
+#include "qapi/qapi-types-virtio.h"
void
virtio_gpu_base_reset(VirtIOGPUBase *g)
@@ -56,6 +57,8 @@ void
virtio_gpu_base_generate_edid(VirtIOGPUBase *g, int scanout,
struct virtio_gpu_resp_edid *edid)
{
+ size_t output_idx;
+ VirtIOGPUOutputList *node;
qemu_edid_info info = {
.width_mm = g->req_state[scanout].width_mm,
.height_mm = g->req_state[scanout].height_mm,
@@ -64,6 +67,14 @@ virtio_gpu_base_generate_edid(VirtIOGPUBase *g, int scanout,
.refresh_rate = g->req_state[scanout].refresh_rate,
};
+ for (output_idx = 0, node = g->conf.outputs;
+ output_idx <= scanout && node; output_idx++, node = node->next) {
+ if (output_idx == scanout && node->value && node->value->name) {
+ info.name = node->value->name;
+ break;
+ }
+ }
+
edid->size = cpu_to_le32(sizeof(edid->edid));
qemu_edid_generate(edid->edid, sizeof(edid->edid), &info);
}
@@ -172,6 +183,8 @@ virtio_gpu_base_device_realize(DeviceState *qdev,
VirtIOHandleOutput cursor_cb,
Error **errp)
{
+ size_t output_idx;
+ VirtIOGPUOutputList *node;
VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
VirtIOGPUBase *g = VIRTIO_GPU_BASE(qdev);
int i;
@@ -181,6 +194,20 @@ virtio_gpu_base_device_realize(DeviceState *qdev,
return false;
}
+ for (output_idx = 0, node = g->conf.outputs;
+ node; output_idx++, node = node->next) {
+ if (output_idx == g->conf.max_outputs) {
+ error_setg(errp, "invalid outputs > %d", g->conf.max_outputs);
+ return false;
+ }
+ if (node->value && node->value->name &&
+ strlen(node->value->name) > EDID_NAME_MAX_LENGTH) {
+ error_setg(errp, "invalid output name '%s' > %d",
+ node->value->name, EDID_NAME_MAX_LENGTH);
+ return false;
+ }
+ }
+
if (virtio_gpu_virgl_enabled(g->conf)) {
error_setg(&g->migration_blocker, "virgl is not yet migratable");
if (migrate_add_blocker(&g->migration_blocker, errp) < 0) {
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 61851cc..423c495 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -338,405 +338,6 @@ build_facs(GArray *table_data)
g_array_append_vals(table_data, reserved, 40); /* Reserved */
}
-Aml *aml_pci_device_dsm(void)
-{
- Aml *method;
-
- method = aml_method("_DSM", 4, AML_SERIALIZED);
- {
- Aml *params = aml_local(0);
- Aml *pkg = aml_package(2);
- aml_append(pkg, aml_int(0));
- aml_append(pkg, aml_int(0));
- aml_append(method, aml_store(pkg, params));
- aml_append(method,
- aml_store(aml_name("BSEL"), aml_index(params, aml_int(0))));
- aml_append(method,
- aml_store(aml_name("ASUN"), aml_index(params, aml_int(1))));
- aml_append(method,
- aml_return(aml_call5("PDSM", aml_arg(0), aml_arg(1),
- aml_arg(2), aml_arg(3), params))
- );
- }
- return method;
-}
-
-static void build_append_pci_dsm_func0_common(Aml *ctx, Aml *retvar)
-{
- Aml *UUID, *ifctx1;
- uint8_t byte_list[1] = { 0 }; /* nothing supported yet */
-
- aml_append(ctx, aml_store(aml_buffer(1, byte_list), retvar));
- /*
- * PCI Firmware Specification 3.1
- * 4.6. _DSM Definitions for PCI
- */
- UUID = aml_touuid("E5C937D0-3553-4D7A-9117-EA4D19C3434D");
- ifctx1 = aml_if(aml_lnot(aml_equal(aml_arg(0), UUID)));
- {
- /* call is for unsupported UUID, bail out */
- aml_append(ifctx1, aml_return(retvar));
- }
- aml_append(ctx, ifctx1);
-
- ifctx1 = aml_if(aml_lless(aml_arg(1), aml_int(2)));
- {
- /* call is for unsupported REV, bail out */
- aml_append(ifctx1, aml_return(retvar));
- }
- aml_append(ctx, ifctx1);
-}
-
-static Aml *aml_pci_edsm(void)
-{
- Aml *method, *ifctx;
- Aml *zero = aml_int(0);
- Aml *func = aml_arg(2);
- Aml *ret = aml_local(0);
- Aml *aidx = aml_local(1);
- Aml *params = aml_arg(4);
-
- method = aml_method("EDSM", 5, AML_SERIALIZED);
-
- /* get supported functions */
- ifctx = aml_if(aml_equal(func, zero));
- {
- /* 1: have supported functions */
- /* 7: support for function 7 */
- const uint8_t caps = 1 | BIT(7);
- build_append_pci_dsm_func0_common(ifctx, ret);
- aml_append(ifctx, aml_store(aml_int(caps), aml_index(ret, zero)));
- aml_append(ifctx, aml_return(ret));
- }
- aml_append(method, ifctx);
-
- /* handle specific functions requests */
- /*
- * PCI Firmware Specification 3.1
- * 4.6.7. _DSM for Naming a PCI or PCI Express Device Under
- * Operating Systems
- */
- ifctx = aml_if(aml_equal(func, aml_int(7)));
- {
- Aml *pkg = aml_package(2);
- aml_append(pkg, zero);
- /* optional, if not impl. should return null string */
- aml_append(pkg, aml_string("%s", ""));
- aml_append(ifctx, aml_store(pkg, ret));
-
- /*
- * IASL is fine when initializing Package with computational data,
- * however it makes guest unhappy /it fails to process such AML/.
- * So use runtime assignment to set acpi-index after initializer
- * to make OSPM happy.
- */
- aml_append(ifctx,
- aml_store(aml_derefof(aml_index(params, aml_int(0))), aidx));
- aml_append(ifctx, aml_store(aidx, aml_index(ret, zero)));
- aml_append(ifctx, aml_return(ret));
- }
- aml_append(method, ifctx);
-
- return method;
-}
-
-static Aml *aml_pci_static_endpoint_dsm(PCIDevice *pdev)
-{
- Aml *method;
-
- g_assert(pdev->acpi_index != 0);
- method = aml_method("_DSM", 4, AML_SERIALIZED);
- {
- Aml *params = aml_local(0);
- Aml *pkg = aml_package(1);
- aml_append(pkg, aml_int(pdev->acpi_index));
- aml_append(method, aml_store(pkg, params));
- aml_append(method,
- aml_return(aml_call5("EDSM", aml_arg(0), aml_arg(1),
- aml_arg(2), aml_arg(3), params))
- );
- }
- return method;
-}
-
-static void build_append_pcihp_notify_entry(Aml *method, int slot)
-{
- Aml *if_ctx;
- int32_t devfn = PCI_DEVFN(slot, 0);
-
- if_ctx = aml_if(aml_and(aml_arg(0), aml_int(0x1U << slot), NULL));
- aml_append(if_ctx, aml_notify(aml_name("S%.02X", devfn), aml_arg(1)));
- aml_append(method, if_ctx);
-}
-
-static bool is_devfn_ignored_generic(const int devfn, const PCIBus *bus)
-{
- const PCIDevice *pdev = bus->devices[devfn];
-
- if (PCI_FUNC(devfn)) {
- if (IS_PCI_BRIDGE(pdev)) {
- /*
- * Ignore only hotplugged PCI bridges on !0 functions, but
- * allow describing cold plugged bridges on all functions
- */
- if (DEVICE(pdev)->hotplugged) {
- return true;
- }
- }
- }
- return false;
-}
-
-static bool is_devfn_ignored_hotplug(const int devfn, const PCIBus *bus)
-{
- PCIDevice *pdev = bus->devices[devfn];
- if (pdev) {
- return is_devfn_ignored_generic(devfn, bus) ||
- !DEVICE_GET_CLASS(pdev)->hotpluggable ||
- /* Cold plugged bridges aren't themselves hot-pluggable */
- (IS_PCI_BRIDGE(pdev) && !DEVICE(pdev)->hotplugged);
- } else { /* non populated slots */
- /*
- * hotplug is supported only for non-multifunction device
- * so generate device description only for function 0
- */
- if (PCI_FUNC(devfn) ||
- (pci_bus_is_express(bus) && PCI_SLOT(devfn) > 0)) {
- return true;
- }
- }
- return false;
-}
-
-void build_append_pcihp_slots(Aml *parent_scope, PCIBus *bus)
-{
- int devfn;
- Aml *dev, *notify_method = NULL, *method;
- QObject *bsel = object_property_get_qobject(OBJECT(bus),
- ACPI_PCIHP_PROP_BSEL, NULL);
- uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel));
- qobject_unref(bsel);
-
- aml_append(parent_scope, aml_name_decl("BSEL", aml_int(bsel_val)));
- notify_method = aml_method("DVNT", 2, AML_NOTSERIALIZED);
-
- for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
- int slot = PCI_SLOT(devfn);
- int adr = slot << 16 | PCI_FUNC(devfn);
-
- if (is_devfn_ignored_hotplug(devfn, bus)) {
- continue;
- }
-
- if (bus->devices[devfn]) {
- dev = aml_scope("S%.02X", devfn);
- } else {
- dev = aml_device("S%.02X", devfn);
- aml_append(dev, aml_name_decl("_ADR", aml_int(adr)));
- }
-
- /*
- * Can't declare _SUN here for every device as it changes 'slot'
- * enumeration order in linux kernel, so use another variable for it
- */
- aml_append(dev, aml_name_decl("ASUN", aml_int(slot)));
- aml_append(dev, aml_pci_device_dsm());
-
- aml_append(dev, aml_name_decl("_SUN", aml_int(slot)));
- /* add _EJ0 to make slot hotpluggable */
- method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
- aml_append(method,
- aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN"))
- );
- aml_append(dev, method);
-
- build_append_pcihp_notify_entry(notify_method, slot);
-
- /* device descriptor has been composed, add it into parent context */
- aml_append(parent_scope, dev);
- }
- aml_append(parent_scope, notify_method);
-}
-
-void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus)
-{
- int devfn;
- Aml *dev;
-
- for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
- /* ACPI spec: 1.0b: Table 6-2 _ADR Object Bus Types, PCI type */
- int adr = PCI_SLOT(devfn) << 16 | PCI_FUNC(devfn);
- PCIDevice *pdev = bus->devices[devfn];
-
- if (!pdev || is_devfn_ignored_generic(devfn, bus)) {
- continue;
- }
-
- /* start to compose PCI device descriptor */
- dev = aml_device("S%.02X", devfn);
- aml_append(dev, aml_name_decl("_ADR", aml_int(adr)));
-
- call_dev_aml_func(DEVICE(bus->devices[devfn]), dev);
- /* add _DSM if device has acpi-index set */
- if (pdev->acpi_index &&
- !object_property_get_bool(OBJECT(pdev), "hotpluggable",
- &error_abort)) {
- aml_append(dev, aml_pci_static_endpoint_dsm(pdev));
- }
-
- /* device descriptor has been composed, add it into parent context */
- aml_append(parent_scope, dev);
- }
-}
-
-static bool build_append_notification_callback(Aml *parent_scope,
- const PCIBus *bus)
-{
- Aml *method;
- PCIBus *sec;
- QObject *bsel;
- int nr_notifiers = 0;
- GQueue *pcnt_bus_list = g_queue_new();
-
- QLIST_FOREACH(sec, &bus->child, sibling) {
- Aml *br_scope = aml_scope("S%.02X", sec->parent_dev->devfn);
- if (pci_bus_is_root(sec)) {
- continue;
- }
- nr_notifiers = nr_notifiers +
- build_append_notification_callback(br_scope, sec);
- /*
- * add new child scope to parent
- * and keep track of bus that have PCNT,
- * bus list is used later to call children PCNTs from this level PCNT
- */
- if (nr_notifiers) {
- g_queue_push_tail(pcnt_bus_list, sec);
- aml_append(parent_scope, br_scope);
- }
- }
-
- /*
- * Append PCNT method to notify about events on local and child buses.
- * ps: hostbridge might not have hotplug (bsel) enabled but might have
- * child bridges that do have bsel.
- */
- method = aml_method("PCNT", 0, AML_NOTSERIALIZED);
-
- /* If bus supports hotplug select it and notify about local events */
- bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL);
- if (bsel) {
- uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel));
-
- aml_append(method, aml_store(aml_int(bsel_val), aml_name("BNUM")));
- aml_append(method, aml_call2("DVNT", aml_name("PCIU"),
- aml_int(1))); /* Device Check */
- aml_append(method, aml_call2("DVNT", aml_name("PCID"),
- aml_int(3))); /* Eject Request */
- nr_notifiers++;
- }
-
- /* Notify about child bus events in any case */
- while ((sec = g_queue_pop_head(pcnt_bus_list))) {
- aml_append(method, aml_name("^S%.02X.PCNT", sec->parent_dev->devfn));
- }
-
- aml_append(parent_scope, method);
- qobject_unref(bsel);
- g_queue_free(pcnt_bus_list);
- return !!nr_notifiers;
-}
-
-static Aml *aml_pci_pdsm(void)
-{
- Aml *method, *ifctx, *ifctx1;
- Aml *ret = aml_local(0);
- Aml *caps = aml_local(1);
- Aml *acpi_index = aml_local(2);
- Aml *zero = aml_int(0);
- Aml *one = aml_int(1);
- Aml *not_supp = aml_int(0xFFFFFFFF);
- Aml *func = aml_arg(2);
- Aml *params = aml_arg(4);
- Aml *bnum = aml_derefof(aml_index(params, aml_int(0)));
- Aml *sunum = aml_derefof(aml_index(params, aml_int(1)));
-
- method = aml_method("PDSM", 5, AML_SERIALIZED);
-
- /* get supported functions */
- ifctx = aml_if(aml_equal(func, zero));
- {
- build_append_pci_dsm_func0_common(ifctx, ret);
-
- aml_append(ifctx, aml_store(zero, caps));
- aml_append(ifctx,
- aml_store(aml_call2("AIDX", bnum, sunum), acpi_index));
- /*
- * advertise function 7 if device has acpi-index
- * acpi_index values:
- * 0: not present (default value)
- * FFFFFFFF: not supported (old QEMU without PIDX reg)
- * other: device's acpi-index
- */
- ifctx1 = aml_if(aml_lnot(
- aml_or(aml_equal(acpi_index, zero),
- aml_equal(acpi_index, not_supp), NULL)
- ));
- {
- /* have supported functions */
- aml_append(ifctx1, aml_or(caps, one, caps));
- /* support for function 7 */
- aml_append(ifctx1,
- aml_or(caps, aml_shiftleft(one, aml_int(7)), caps));
- }
- aml_append(ifctx, ifctx1);
-
- aml_append(ifctx, aml_store(caps, aml_index(ret, zero)));
- aml_append(ifctx, aml_return(ret));
- }
- aml_append(method, ifctx);
-
- /* handle specific functions requests */
- /*
- * PCI Firmware Specification 3.1
- * 4.6.7. _DSM for Naming a PCI or PCI Express Device Under
- * Operating Systems
- */
- ifctx = aml_if(aml_equal(func, aml_int(7)));
- {
- Aml *pkg = aml_package(2);
-
- aml_append(ifctx, aml_store(aml_call2("AIDX", bnum, sunum), acpi_index));
- aml_append(ifctx, aml_store(pkg, ret));
- /*
- * Windows calls func=7 without checking if it's available,
- * as workaround Microsoft has suggested to return invalid for func7
- * Package, so return 2 elements package but only initialize elements
- * when acpi_index is supported and leave them uninitialized, which
- * leads elements to being Uninitialized ObjectType and should trip
- * Windows into discarding result as an unexpected and prevent setting
- * bogus 'PCI Label' on the device.
- */
- ifctx1 = aml_if(aml_lnot(aml_lor(
- aml_equal(acpi_index, zero), aml_equal(acpi_index, not_supp)
- )));
- {
- aml_append(ifctx1, aml_store(acpi_index, aml_index(ret, zero)));
- /*
- * optional, if not impl. should return null string
- */
- aml_append(ifctx1, aml_store(aml_string("%s", ""),
- aml_index(ret, one)));
- }
- aml_append(ifctx, ifctx1);
-
- aml_append(ifctx, aml_return(ret));
- }
-
- aml_append(method, ifctx);
- return method;
-}
-
/*
* build_prt - Define interrupt routing rules
*
@@ -1227,112 +828,6 @@ static Aml *build_q35_dram_controller(const AcpiMcfgInfo *mcfg)
return dev;
}
-static void build_x86_acpi_pci_hotplug(Aml *table, uint64_t pcihp_addr)
-{
- Aml *scope;
- Aml *field;
- Aml *method;
-
- scope = aml_scope("_SB.PCI0");
-
- aml_append(scope,
- aml_operation_region("PCST", AML_SYSTEM_IO, aml_int(pcihp_addr), 0x08));
- field = aml_field("PCST", AML_DWORD_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS);
- aml_append(field, aml_named_field("PCIU", 32));
- aml_append(field, aml_named_field("PCID", 32));
- aml_append(scope, field);
-
- aml_append(scope,
- aml_operation_region("SEJ", AML_SYSTEM_IO,
- aml_int(pcihp_addr + ACPI_PCIHP_SEJ_BASE), 0x04));
- field = aml_field("SEJ", AML_DWORD_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS);
- aml_append(field, aml_named_field("B0EJ", 32));
- aml_append(scope, field);
-
- aml_append(scope,
- aml_operation_region("BNMR", AML_SYSTEM_IO,
- aml_int(pcihp_addr + ACPI_PCIHP_BNMR_BASE), 0x08));
- field = aml_field("BNMR", AML_DWORD_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS);
- aml_append(field, aml_named_field("BNUM", 32));
- aml_append(field, aml_named_field("PIDX", 32));
- aml_append(scope, field);
-
- aml_append(scope, aml_mutex("BLCK", 0));
-
- method = aml_method("PCEJ", 2, AML_NOTSERIALIZED);
- aml_append(method, aml_acquire(aml_name("BLCK"), 0xFFFF));
- aml_append(method, aml_store(aml_arg(0), aml_name("BNUM")));
- aml_append(method,
- aml_store(aml_shiftleft(aml_int(1), aml_arg(1)), aml_name("B0EJ")));
- aml_append(method, aml_release(aml_name("BLCK")));
- aml_append(method, aml_return(aml_int(0)));
- aml_append(scope, method);
-
- method = aml_method("AIDX", 2, AML_NOTSERIALIZED);
- aml_append(method, aml_acquire(aml_name("BLCK"), 0xFFFF));
- aml_append(method, aml_store(aml_arg(0), aml_name("BNUM")));
- aml_append(method,
- aml_store(aml_shiftleft(aml_int(1), aml_arg(1)), aml_name("PIDX")));
- aml_append(method, aml_store(aml_name("PIDX"), aml_local(0)));
- aml_append(method, aml_release(aml_name("BLCK")));
- aml_append(method, aml_return(aml_local(0)));
- aml_append(scope, method);
-
- aml_append(scope, aml_pci_pdsm());
-
- aml_append(table, scope);
-}
-
-static Aml *build_q35_osc_method(bool enable_native_pcie_hotplug)
-{
- Aml *if_ctx;
- Aml *if_ctx2;
- Aml *else_ctx;
- Aml *method;
- Aml *a_cwd1 = aml_name("CDW1");
- Aml *a_ctrl = aml_local(0);
-
- method = aml_method("_OSC", 4, AML_NOTSERIALIZED);
- aml_append(method, aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1"));
-
- if_ctx = aml_if(aml_equal(
- aml_arg(0), aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766")));
- aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2"));
- aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3"));
-
- aml_append(if_ctx, aml_store(aml_name("CDW3"), a_ctrl));
-
- /*
- * Always allow native PME, AER (no dependencies)
- * Allow SHPC (PCI bridges can have SHPC controller)
- * Disable PCIe Native Hot-plug if ACPI PCI Hot-plug is enabled.
- */
- aml_append(if_ctx, aml_and(a_ctrl,
- aml_int(0x1E | (enable_native_pcie_hotplug ? 0x1 : 0x0)), a_ctrl));
-
- if_ctx2 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(1))));
- /* Unknown revision */
- aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x08), a_cwd1));
- aml_append(if_ctx, if_ctx2);
-
- if_ctx2 = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), a_ctrl)));
- /* Capabilities bits were masked */
- aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x10), a_cwd1));
- aml_append(if_ctx, if_ctx2);
-
- /* Update DWORD3 in the buffer */
- aml_append(if_ctx, aml_store(a_ctrl, aml_name("CDW3")));
- aml_append(method, if_ctx);
-
- else_ctx = aml_else();
- /* Unrecognized UUID */
- aml_append(else_ctx, aml_or(a_cwd1, aml_int(4), a_cwd1));
- aml_append(method, else_ctx);
-
- aml_append(method, aml_return(aml_arg(3)));
- return method;
-}
-
static void build_acpi0017(Aml *table)
{
Aml *dev, *scope, *method;
@@ -1389,12 +884,12 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
dev = aml_device("PCI0");
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A03")));
aml_append(dev, aml_name_decl("_UID", aml_int(pcmc->pci_root_uid)));
- aml_append(dev, aml_pci_edsm());
+ aml_append(dev, build_pci_bridge_edsm());
aml_append(sb_scope, dev);
aml_append(dsdt, sb_scope);
if (pm->pcihp_bridge_en || pm->pcihp_root_en) {
- build_x86_acpi_pci_hotplug(dsdt, pm->pcihp_io_base);
+ build_acpi_pci_hotplug(dsdt, AML_SYSTEM_IO, pm->pcihp_io_base);
}
build_piix4_pci0_int(dsdt);
} else if (q35) {
@@ -1403,8 +898,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08")));
aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03")));
aml_append(dev, aml_name_decl("_UID", aml_int(pcmc->pci_root_uid)));
- aml_append(dev, build_q35_osc_method(!pm->pcihp_bridge_en));
- aml_append(dev, aml_pci_edsm());
+ aml_append(dev, build_pci_host_bridge_osc_method(!pm->pcihp_bridge_en));
+ aml_append(dev, build_pci_bridge_edsm());
aml_append(sb_scope, dev);
if (mcfg_valid) {
aml_append(sb_scope, build_q35_dram_controller(&mcfg));
@@ -1438,7 +933,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
aml_append(dsdt, sb_scope);
if (pm->pcihp_bridge_en) {
- build_x86_acpi_pci_hotplug(dsdt, pm->pcihp_io_base);
+ build_acpi_pci_hotplug(dsdt, AML_SYSTEM_IO, pm->pcihp_io_base);
}
build_q35_pci0_int(dsdt);
}
@@ -1525,7 +1020,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03")));
/* Expander bridges do not have ACPI PCI Hot-plug enabled */
- aml_append(dev, build_q35_osc_method(true));
+ aml_append(dev, build_pci_host_bridge_osc_method(true));
} else {
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A03")));
}
@@ -1654,19 +1149,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
/* reserve PCIHP resources */
if (pm->pcihp_io_len && (pm->pcihp_bridge_en || pm->pcihp_root_en)) {
- dev = aml_device("PHPR");
- aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A06")));
- aml_append(dev,
- aml_name_decl("_UID", aml_string("PCI Hotplug resources")));
- /* device present, functioning, decoding, not shown in UI */
- aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
- crs = aml_resource_template();
- aml_append(crs,
- aml_io(AML_DECODE16, pm->pcihp_io_base, pm->pcihp_io_base, 1,
- pm->pcihp_io_len)
- );
- aml_append(dev, aml_name_decl("_CRS", crs));
- aml_append(scope, dev);
+ build_append_pcihp_resources(scope,
+ pm->pcihp_io_base, pm->pcihp_io_len);
}
aml_append(dsdt, scope);
diff --git a/hw/i386/acpi-build.h b/hw/i386/acpi-build.h
index 275ec05..8ba3c33 100644
--- a/hw/i386/acpi-build.h
+++ b/hw/i386/acpi-build.h
@@ -5,10 +5,6 @@
extern const struct AcpiGenericAddress x86_nvdimm_acpi_dsmio;
-/* PCI Hot-plug registers' base. See docs/specs/acpi_pci_hotplug.rst */
-#define ACPI_PCIHP_SEJ_BASE 0x8
-#define ACPI_PCIHP_BNMR_BASE 0x10
-
void acpi_setup(void);
Object *acpi_get_i386_pci_host(void);
diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
index 963aa24..5a24c17 100644
--- a/hw/i386/amd_iommu.c
+++ b/hw/i386/amd_iommu.c
@@ -140,7 +140,7 @@ static void amdvi_writeq(AMDVIState *s, hwaddr addr, uint64_t val)
{
uint64_t romask = ldq_le_p(&s->romask[addr]);
uint64_t w1cmask = ldq_le_p(&s->w1cmask[addr]);
- uint32_t oldval = ldq_le_p(&s->mmior[addr]);
+ uint64_t oldval = ldq_le_p(&s->mmior[addr]);
stq_le_p(&s->mmior[addr],
((oldval & romask) | (val & ~romask)) & ~(val & w1cmask));
}
@@ -508,7 +508,7 @@ static void amdvi_inval_inttable(AMDVIState *s, uint64_t *cmd)
static void iommu_inval_iotlb(AMDVIState *s, uint64_t *cmd)
{
- uint16_t devid = extract64(cmd[0], 0, 16);
+ uint16_t devid = cpu_to_le16(extract64(cmd[0], 0, 16));
if (extract64(cmd[1], 1, 1) || extract64(cmd[1], 3, 1) ||
extract64(cmd[1], 6, 6)) {
amdvi_log_illegalcom_error(s, extract64(cmd[0], 60, 4),
@@ -521,7 +521,7 @@ static void iommu_inval_iotlb(AMDVIState *s, uint64_t *cmd)
&devid);
} else {
amdvi_iotlb_remove_page(s, cpu_to_le64(extract64(cmd[1], 12, 52)) << 12,
- cpu_to_le16(extract64(cmd[1], 0, 16)));
+ devid);
}
trace_amdvi_iotlb_inval();
}
@@ -665,8 +665,8 @@ static inline void amdvi_handle_devtab_write(AMDVIState *s)
uint64_t val = amdvi_readq(s, AMDVI_MMIO_DEVICE_TABLE);
s->devtab = (val & AMDVI_MMIO_DEVTAB_BASE_MASK);
- /* set device table length */
- s->devtab_len = ((val & AMDVI_MMIO_DEVTAB_SIZE_MASK) + 1 *
+ /* set device table length (i.e. number of entries table can hold) */
+ s->devtab_len = (((val & AMDVI_MMIO_DEVTAB_SIZE_MASK) + 1) *
(AMDVI_MMIO_DEVTAB_SIZE_UNIT /
AMDVI_MMIO_DEVTAB_ENTRY_SIZE));
}
@@ -848,9 +848,10 @@ static inline uint64_t amdvi_get_perms(uint64_t entry)
static bool amdvi_validate_dte(AMDVIState *s, uint16_t devid,
uint64_t *dte)
{
- if ((dte[0] & AMDVI_DTE_LOWER_QUAD_RESERVED)
- || (dte[1] & AMDVI_DTE_MIDDLE_QUAD_RESERVED)
- || (dte[2] & AMDVI_DTE_UPPER_QUAD_RESERVED) || dte[3]) {
+ if ((dte[0] & AMDVI_DTE_QUAD0_RESERVED) ||
+ (dte[1] & AMDVI_DTE_QUAD1_RESERVED) ||
+ (dte[2] & AMDVI_DTE_QUAD2_RESERVED) ||
+ (dte[3] & AMDVI_DTE_QUAD3_RESERVED)) {
amdvi_log_illegaldevtab_error(s, devid,
s->devtab +
devid * AMDVI_DEVTAB_ENTRY_SIZE, 0);
diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h
index 5672bde..8b42913 100644
--- a/hw/i386/amd_iommu.h
+++ b/hw/i386/amd_iommu.h
@@ -25,6 +25,8 @@
#include "hw/i386/x86-iommu.h"
#include "qom/object.h"
+#define GENMASK64(h, l) (((~0ULL) >> (63 - (h) + (l))) << (l))
+
/* Capability registers */
#define AMDVI_CAPAB_BAR_LOW 0x04
#define AMDVI_CAPAB_BAR_HIGH 0x08
@@ -66,34 +68,34 @@
#define AMDVI_MMIO_SIZE 0x4000
-#define AMDVI_MMIO_DEVTAB_SIZE_MASK ((1ULL << 12) - 1)
-#define AMDVI_MMIO_DEVTAB_BASE_MASK (((1ULL << 52) - 1) & ~ \
- AMDVI_MMIO_DEVTAB_SIZE_MASK)
+#define AMDVI_MMIO_DEVTAB_SIZE_MASK GENMASK64(8, 0)
+#define AMDVI_MMIO_DEVTAB_BASE_MASK GENMASK64(51, 12)
+
#define AMDVI_MMIO_DEVTAB_ENTRY_SIZE 32
#define AMDVI_MMIO_DEVTAB_SIZE_UNIT 4096
/* some of this are similar but just for readability */
#define AMDVI_MMIO_CMDBUF_SIZE_BYTE (AMDVI_MMIO_COMMAND_BASE + 7)
#define AMDVI_MMIO_CMDBUF_SIZE_MASK 0x0f
-#define AMDVI_MMIO_CMDBUF_BASE_MASK AMDVI_MMIO_DEVTAB_BASE_MASK
-#define AMDVI_MMIO_CMDBUF_HEAD_MASK (((1ULL << 19) - 1) & ~0x0f)
-#define AMDVI_MMIO_CMDBUF_TAIL_MASK AMDVI_MMIO_EVTLOG_HEAD_MASK
+#define AMDVI_MMIO_CMDBUF_BASE_MASK GENMASK64(51, 12)
+#define AMDVI_MMIO_CMDBUF_HEAD_MASK GENMASK64(18, 4)
+#define AMDVI_MMIO_CMDBUF_TAIL_MASK GENMASK64(18, 4)
#define AMDVI_MMIO_EVTLOG_SIZE_BYTE (AMDVI_MMIO_EVENT_BASE + 7)
-#define AMDVI_MMIO_EVTLOG_SIZE_MASK AMDVI_MMIO_CMDBUF_SIZE_MASK
-#define AMDVI_MMIO_EVTLOG_BASE_MASK AMDVI_MMIO_CMDBUF_BASE_MASK
-#define AMDVI_MMIO_EVTLOG_HEAD_MASK (((1ULL << 19) - 1) & ~0x0f)
-#define AMDVI_MMIO_EVTLOG_TAIL_MASK AMDVI_MMIO_EVTLOG_HEAD_MASK
+#define AMDVI_MMIO_EVTLOG_SIZE_MASK 0x0f
+#define AMDVI_MMIO_EVTLOG_BASE_MASK GENMASK64(51, 12)
+#define AMDVI_MMIO_EVTLOG_HEAD_MASK GENMASK64(18, 4)
+#define AMDVI_MMIO_EVTLOG_TAIL_MASK GENMASK64(18, 4)
-#define AMDVI_MMIO_PPRLOG_SIZE_BYTE (AMDVI_MMIO_EVENT_BASE + 7)
-#define AMDVI_MMIO_PPRLOG_HEAD_MASK AMDVI_MMIO_EVTLOG_HEAD_MASK
-#define AMDVI_MMIO_PPRLOG_TAIL_MASK AMDVI_MMIO_EVTLOG_HEAD_MASK
-#define AMDVI_MMIO_PPRLOG_BASE_MASK AMDVI_MMIO_EVTLOG_BASE_MASK
-#define AMDVI_MMIO_PPRLOG_SIZE_MASK AMDVI_MMIO_EVTLOG_SIZE_MASK
+#define AMDVI_MMIO_PPRLOG_SIZE_BYTE (AMDVI_MMIO_PPR_BASE + 7)
+#define AMDVI_MMIO_PPRLOG_SIZE_MASK 0x0f
+#define AMDVI_MMIO_PPRLOG_BASE_MASK GENMASK64(51, 12)
+#define AMDVI_MMIO_PPRLOG_HEAD_MASK GENMASK64(18, 4)
+#define AMDVI_MMIO_PPRLOG_TAIL_MASK GENMASK64(18, 4)
#define AMDVI_MMIO_EXCL_ENABLED_MASK (1ULL << 0)
#define AMDVI_MMIO_EXCL_ALLOW_MASK (1ULL << 1)
-#define AMDVI_MMIO_EXCL_LIMIT_MASK AMDVI_MMIO_DEVTAB_BASE_MASK
+#define AMDVI_MMIO_EXCL_LIMIT_MASK GENMASK64(51, 12)
#define AMDVI_MMIO_EXCL_LIMIT_LOW 0xfff
/* mmio control register flags */
@@ -130,14 +132,14 @@
#define AMDVI_DEV_TRANSLATION_VALID (1ULL << 1)
#define AMDVI_DEV_MODE_MASK 0x7
#define AMDVI_DEV_MODE_RSHIFT 9
-#define AMDVI_DEV_PT_ROOT_MASK 0xffffffffff000
+#define AMDVI_DEV_PT_ROOT_MASK GENMASK64(51, 12)
#define AMDVI_DEV_PT_ROOT_RSHIFT 12
#define AMDVI_DEV_PERM_SHIFT 61
#define AMDVI_DEV_PERM_READ (1ULL << 61)
#define AMDVI_DEV_PERM_WRITE (1ULL << 62)
/* Device table entry bits 64:127 */
-#define AMDVI_DEV_DOMID_ID_MASK ((1ULL << 16) - 1)
+#define AMDVI_DEV_DOMID_ID_MASK GENMASK64(15, 0)
/* Event codes and flags, as stored in the info field */
#define AMDVI_EVENT_ILLEGAL_DEVTAB_ENTRY (0x1U << 12)
@@ -162,9 +164,10 @@
#define AMDVI_FEATURE_PC (1ULL << 9) /* Perf counters */
/* reserved DTE bits */
-#define AMDVI_DTE_LOWER_QUAD_RESERVED 0x80300000000000fc
-#define AMDVI_DTE_MIDDLE_QUAD_RESERVED 0x0000000000000100
-#define AMDVI_DTE_UPPER_QUAD_RESERVED 0x08f0000000000000
+#define AMDVI_DTE_QUAD0_RESERVED (GENMASK64(6, 2) | GENMASK64(63, 63))
+#define AMDVI_DTE_QUAD1_RESERVED 0
+#define AMDVI_DTE_QUAD2_RESERVED GENMASK64(53, 52)
+#define AMDVI_DTE_QUAD3_RESERVED (GENMASK64(14, 0) | GENMASK64(53, 48))
/* AMDVI paging mode */
#define AMDVI_GATS_MODE (2ULL << 12)
@@ -194,16 +197,12 @@
#define AMDVI_PAGE_SIZE (1ULL << AMDVI_PAGE_SHIFT)
#define AMDVI_PAGE_SHIFT_4K 12
-#define AMDVI_PAGE_MASK_4K (~((1ULL << AMDVI_PAGE_SHIFT_4K) - 1))
-
-#define AMDVI_MAX_VA_ADDR (48UL << 5)
-#define AMDVI_MAX_PH_ADDR (40UL << 8)
-#define AMDVI_MAX_GVA_ADDR (48UL << 15)
+#define AMDVI_PAGE_MASK_4K GENMASK64(63, 12)
-/* Completion Wait data size */
-#define AMDVI_COMPLETION_DATA_SIZE 8
+#define AMDVI_MAX_GVA_ADDR (2UL << 5)
+#define AMDVI_MAX_PH_ADDR (40UL << 8)
+#define AMDVI_MAX_VA_ADDR (48UL << 15)
-#define AMDVI_COMMAND_SIZE 16
/* Completion Wait data size */
#define AMDVI_COMPLETION_DATA_SIZE 8
@@ -228,7 +227,7 @@
#define AMDVI_IR_INTCTL_PASS 1
#define AMDVI_IR_INTCTL_REMAP 2
-#define AMDVI_IR_PHYS_ADDR_MASK (((1ULL << 45) - 1) << 6)
+#define AMDVI_IR_PHYS_ADDR_MASK GENMASK64(51, 6)
/* MSI data 10:0 bits (section 2.2.5.1 Fig 14) */
#define AMDVI_IRTE_OFFSET 0x7ff
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index 69d72ad..fe9a5f2 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -1987,9 +1987,9 @@ static int vtd_iova_to_flpte(IntelIOMMUState *s, VTDContextEntry *ce,
uint32_t pasid)
{
dma_addr_t addr = vtd_get_iova_pgtbl_base(s, ce, pasid);
- uint32_t level = vtd_get_iova_level(s, ce, pasid);
uint32_t offset;
uint64_t flpte, flag_ad = VTD_FL_A;
+ *flpte_level = vtd_get_iova_level(s, ce, pasid);
if (!vtd_iova_fl_check_canonical(s, iova, ce, pasid)) {
error_report_once("%s: detected non canonical IOVA (iova=0x%" PRIx64 ","
@@ -1998,11 +1998,11 @@ static int vtd_iova_to_flpte(IntelIOMMUState *s, VTDContextEntry *ce,
}
while (true) {
- offset = vtd_iova_level_offset(iova, level);
+ offset = vtd_iova_level_offset(iova, *flpte_level);
flpte = vtd_get_pte(addr, offset);
if (flpte == (uint64_t)-1) {
- if (level == vtd_get_iova_level(s, ce, pasid)) {
+ if (*flpte_level == vtd_get_iova_level(s, ce, pasid)) {
/* Invalid programming of pasid-entry */
return -VTD_FR_PASID_ENTRY_FSPTPTR_INV;
} else {
@@ -2028,15 +2028,15 @@ static int vtd_iova_to_flpte(IntelIOMMUState *s, VTDContextEntry *ce,
if (is_write && !(flpte & VTD_FL_RW)) {
return -VTD_FR_SM_WRITE;
}
- if (vtd_flpte_nonzero_rsvd(flpte, level)) {
+ if (vtd_flpte_nonzero_rsvd(flpte, *flpte_level)) {
error_report_once("%s: detected flpte reserved non-zero "
"iova=0x%" PRIx64 ", level=0x%" PRIx32
"flpte=0x%" PRIx64 ", pasid=0x%" PRIX32 ")",
- __func__, iova, level, flpte, pasid);
+ __func__, iova, *flpte_level, flpte, pasid);
return -VTD_FR_FS_PAGING_ENTRY_RSVD;
}
- if (vtd_is_last_pte(flpte, level) && is_write) {
+ if (vtd_is_last_pte(flpte, *flpte_level) && is_write) {
flag_ad |= VTD_FL_D;
}
@@ -2044,14 +2044,13 @@ static int vtd_iova_to_flpte(IntelIOMMUState *s, VTDContextEntry *ce,
return -VTD_FR_FS_BIT_UPDATE_FAILED;
}
- if (vtd_is_last_pte(flpte, level)) {
+ if (vtd_is_last_pte(flpte, *flpte_level)) {
*flptep = flpte;
- *flpte_level = level;
return 0;
}
addr = vtd_get_pte_addr(flpte, aw_bits);
- level--;
+ (*flpte_level)--;
}
}
@@ -2092,7 +2091,8 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
uint8_t bus_num = pci_bus_num(bus);
VTDContextCacheEntry *cc_entry;
uint64_t pte, page_mask;
- uint32_t level, pasid = vtd_as->pasid;
+ uint32_t level = UINT32_MAX;
+ uint32_t pasid = vtd_as->pasid;
uint16_t source_id = PCI_BUILD_BDF(bus_num, devfn);
int ret_fr;
bool is_fpd_set = false;
@@ -2251,14 +2251,19 @@ out:
entry->iova = addr & page_mask;
entry->translated_addr = vtd_get_pte_addr(pte, s->aw_bits) & page_mask;
entry->addr_mask = ~page_mask;
- entry->perm = access_flags;
+ entry->perm = (is_write ? access_flags : (access_flags & (~IOMMU_WO)));
return true;
error:
vtd_iommu_unlock(s);
entry->iova = 0;
entry->translated_addr = 0;
- entry->addr_mask = 0;
+ /*
+ * Set the mask for ATS (the range must be present even when the
+ * translation fails : PCIe rev 5 10.2.3.5)
+ */
+ entry->addr_mask = (level != UINT32_MAX) ?
+ (~vtd_pt_level_page_mask(level)) : (~VTD_PAGE_MASK_4K);
entry->perm = IOMMU_NONE;
return false;
}
@@ -2503,6 +2508,7 @@ static void vtd_iotlb_page_invalidate_notify(IntelIOMMUState *s,
.translated_addr = 0,
.addr_mask = size - 1,
.perm = IOMMU_NONE,
+ .pasid = vtd_as->pasid,
},
};
memory_region_notify_iommu(&vtd_as->iommu, 0, event);
@@ -3090,6 +3096,7 @@ static void do_invalidate_device_tlb(VTDAddressSpace *vtd_dev_as,
event.entry.iova = addr;
event.entry.perm = IOMMU_NONE;
event.entry.translated_addr = 0;
+ event.entry.pasid = vtd_dev_as->pasid;
memory_region_notify_iommu(&vtd_dev_as->iommu, 0, event);
}
@@ -3672,6 +3679,7 @@ static IOMMUTLBEntry vtd_iommu_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
IOMMUTLBEntry iotlb = {
/* We'll fill in the rest later. */
.target_as = &address_space_memory,
+ .pasid = vtd_as->pasid,
};
bool success;
@@ -4587,7 +4595,7 @@ static void vtd_cap_init(IntelIOMMUState *s)
}
if (s->pasid) {
- s->ecap |= VTD_ECAP_PASID;
+ s->ecap |= VTD_ECAP_PASID | VTD_ECAP_PSS;
}
}
@@ -4730,10 +4738,118 @@ static AddressSpace *vtd_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
return &vtd_as->as;
}
+static IOMMUTLBEntry vtd_iommu_ats_do_translate(IOMMUMemoryRegion *iommu,
+ hwaddr addr,
+ IOMMUAccessFlags flags)
+{
+ IOMMUTLBEntry entry;
+ VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu);
+
+ if (vtd_is_interrupt_addr(addr)) {
+ vtd_report_ir_illegal_access(vtd_as, addr, flags & IOMMU_WO);
+ entry.target_as = &address_space_memory;
+ entry.iova = 0;
+ entry.translated_addr = 0;
+ entry.addr_mask = ~VTD_PAGE_MASK_4K;
+ entry.perm = IOMMU_NONE;
+ entry.pasid = PCI_NO_PASID;
+ } else {
+ entry = vtd_iommu_translate(iommu, addr, flags, 0);
+ }
+
+ return entry;
+}
+
+static ssize_t vtd_ats_request_translation(PCIBus *bus, void *opaque,
+ int devfn, uint32_t pasid,
+ bool priv_req, bool exec_req,
+ hwaddr addr, size_t length,
+ bool no_write, IOMMUTLBEntry *result,
+ size_t result_length,
+ uint32_t *err_count)
+{
+ IntelIOMMUState *s = opaque;
+ VTDAddressSpace *vtd_as;
+ IOMMUAccessFlags flags = IOMMU_ACCESS_FLAG_FULL(true, !no_write, exec_req,
+ priv_req, false, false);
+ ssize_t res_index = 0;
+ hwaddr target_address = addr + length;
+ IOMMUTLBEntry entry;
+
+ vtd_as = vtd_find_add_as(s, bus, devfn, pasid);
+ *err_count = 0;
+
+ while ((addr < target_address) && (res_index < result_length)) {
+ entry = vtd_iommu_ats_do_translate(&vtd_as->iommu, addr, flags);
+ entry.perm &= ~IOMMU_GLOBAL; /* Spec 4.1.2: Global Mapping never set */
+
+ if ((entry.perm & flags) != flags) {
+ *err_count += 1; /* Less than expected */
+ }
+
+ result[res_index] = entry;
+ res_index += 1;
+ addr = (addr & (~entry.addr_mask)) + (entry.addr_mask + 1);
+ }
+
+ /* Buffer too small */
+ if (addr < target_address) {
+ return -ENOMEM;
+ }
+
+ return res_index;
+}
+
+static void vtd_init_iotlb_notifier(PCIBus *bus, void *opaque, int devfn,
+ IOMMUNotifier *n, IOMMUNotify fn,
+ void *user_opaque)
+{
+ n->opaque = user_opaque;
+ iommu_notifier_init(n, fn, IOMMU_NOTIFIER_DEVIOTLB_EVENTS, 0,
+ HWADDR_MAX, 0);
+}
+
+static void vtd_get_iotlb_info(void *opaque, uint8_t *addr_width,
+ uint32_t *min_page_size)
+{
+ IntelIOMMUState *s = opaque;
+
+ *addr_width = s->aw_bits;
+ *min_page_size = VTD_PAGE_SIZE;
+}
+
+static void vtd_register_iotlb_notifier(PCIBus *bus, void *opaque,
+ int devfn, uint32_t pasid,
+ IOMMUNotifier *n)
+{
+ IntelIOMMUState *s = opaque;
+ VTDAddressSpace *vtd_as;
+
+ vtd_as = vtd_find_add_as(s, bus, devfn, pasid);
+ memory_region_register_iommu_notifier(MEMORY_REGION(&vtd_as->iommu), n,
+ &error_fatal);
+}
+
+static void vtd_unregister_iotlb_notifier(PCIBus *bus, void *opaque,
+ int devfn, uint32_t pasid,
+ IOMMUNotifier *n)
+{
+ IntelIOMMUState *s = opaque;
+ VTDAddressSpace *vtd_as;
+
+ vtd_as = vtd_find_add_as(s, bus, devfn, pasid);
+ memory_region_unregister_iommu_notifier(MEMORY_REGION(&vtd_as->iommu), n);
+}
+
static PCIIOMMUOps vtd_iommu_ops = {
.get_address_space = vtd_host_dma_iommu,
.set_iommu_device = vtd_dev_set_iommu_device,
.unset_iommu_device = vtd_dev_unset_iommu_device,
+ .get_iotlb_info = vtd_get_iotlb_info,
+ .init_iotlb_notifier = vtd_init_iotlb_notifier,
+ .register_iotlb_notifier = vtd_register_iotlb_notifier,
+ .unregister_iotlb_notifier = vtd_unregister_iotlb_notifier,
+ .ats_request_translation = vtd_ats_request_translation,
};
static bool vtd_decide_config(IntelIOMMUState *s, Error **errp)
diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h
index e8b211e..360e937 100644
--- a/hw/i386/intel_iommu_internal.h
+++ b/hw/i386/intel_iommu_internal.h
@@ -192,6 +192,7 @@
#define VTD_ECAP_SC (1ULL << 7)
#define VTD_ECAP_MHMV (15ULL << 20)
#define VTD_ECAP_SRS (1ULL << 31)
+#define VTD_ECAP_PSS (7ULL << 35) /* limit: MemTxAttrs::pid */
#define VTD_ECAP_PASID (1ULL << 40)
#define VTD_ECAP_SMTS (1ULL << 43)
#define VTD_ECAP_SLTS (1ULL << 46)
diff --git a/hw/intc/loongarch_extioi_kvm.c b/hw/intc/loongarch_extioi_kvm.c
index 0133540..aa2e8c7 100644
--- a/hw/intc/loongarch_extioi_kvm.c
+++ b/hw/intc/loongarch_extioi_kvm.c
@@ -6,7 +6,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu/typedefs.h"
#include "hw/intc/loongarch_extioi.h"
#include "linux/kvm.h"
#include "qapi/error.h"
diff --git a/hw/loongarch/virt-acpi-build.c b/hw/loongarch/virt-acpi-build.c
index 2cd2d9d..8c2228a 100644
--- a/hw/loongarch/virt-acpi-build.c
+++ b/hw/loongarch/virt-acpi-build.c
@@ -557,7 +557,9 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine)
acpi_add_table(table_offsets, tables_blob);
build_srat(tables_blob, tables->linker, machine);
acpi_add_table(table_offsets, tables_blob);
- spcr_setup(tables_blob, tables->linker, machine);
+
+ if (machine->acpi_spcr_enabled)
+ spcr_setup(tables_blob, tables->linker, machine);
if (machine->numa_state->num_nodes) {
if (machine->numa_state->have_numa_distance) {
diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c
index 94e7274..be609ff 100644
--- a/hw/mem/cxl_type3.c
+++ b/hw/mem/cxl_type3.c
@@ -8,6 +8,7 @@
*
* SPDX-License-Identifier: GPL-v2-only
*/
+#include <math.h>
#include "qemu/osdep.h"
#include "qemu/units.h"
@@ -225,10 +226,16 @@ static int ct3_build_cdat_table(CDATSubHeader ***cdat_table, void *priv)
* future.
*/
for (i = 0; i < ct3d->dc.num_regions; i++) {
+ ct3d->dc.regions[i].nonvolatile = false;
+ ct3d->dc.regions[i].sharable = false;
+ ct3d->dc.regions[i].hw_managed_coherency = false;
+ ct3d->dc.regions[i].ic_specific_dc_management = false;
+ ct3d->dc.regions[i].rdonly = false;
ct3_build_cdat_entries_for_mr(&(table[cur_ent]),
dsmad_handle++,
ct3d->dc.regions[i].len,
- false, true, region_base);
+ ct3d->dc.regions[i].nonvolatile,
+ true, region_base);
ct3d->dc.regions[i].dsmadhandle = dsmad_handle - 1;
cur_ent += CT3_CDAT_NUM_ENTRIES;
@@ -634,6 +641,8 @@ static bool cxl_create_dc_regions(CXLType3Dev *ct3d, Error **errp)
uint64_t region_len;
uint64_t decode_len;
uint64_t blk_size = 2 * MiB;
+ /* Only 1 block size is supported for now. */
+ uint64_t supported_blk_size_bitmask = blk_size;
CXLDCRegion *region;
MemoryRegion *mr;
uint64_t dc_size;
@@ -679,9 +688,11 @@ static bool cxl_create_dc_regions(CXLType3Dev *ct3d, Error **errp)
.block_size = blk_size,
/* dsmad_handle set when creating CDAT table entries */
.flags = 0,
+ .supported_blk_size_bitmask = supported_blk_size_bitmask,
};
ct3d->dc.total_capacity += region->len;
region->blk_bitmap = bitmap_new(region->len / region->block_size);
+ qemu_mutex_init(&region->bitmap_lock);
}
QTAILQ_INIT(&ct3d->dc.extents);
QTAILQ_INIT(&ct3d->dc.extents_pending);
@@ -1010,6 +1021,7 @@ void ct3_set_region_block_backed(CXLType3Dev *ct3d, uint64_t dpa,
return;
}
+ QEMU_LOCK_GUARD(&region->bitmap_lock);
bitmap_set(region->blk_bitmap, (dpa - region->base) / region->block_size,
len / region->block_size);
}
@@ -1036,6 +1048,7 @@ bool ct3_test_region_block_backed(CXLType3Dev *ct3d, uint64_t dpa,
* if bits between [dpa, dpa + len) are all 1s, meaning the DPA range is
* backed with DC extents, return true; else return false.
*/
+ QEMU_LOCK_GUARD(&region->bitmap_lock);
return find_next_zero_bit(region->blk_bitmap, nr + nbits, nr) == nr + nbits;
}
@@ -1057,6 +1070,7 @@ void ct3_clear_region_block_backed(CXLType3Dev *ct3d, uint64_t dpa,
nr = (dpa - region->base) / region->block_size;
nbits = len / region->block_size;
+ QEMU_LOCK_GUARD(&region->bitmap_lock);
bitmap_clear(region->blk_bitmap, nr, nbits);
}
@@ -1576,9 +1590,9 @@ void qmp_cxl_inject_correctable_error(const char *path, CxlCorErrorType type,
pcie_aer_inject_error(PCI_DEVICE(obj), &err);
}
-static void cxl_assign_event_header(CXLEventRecordHdr *hdr,
- const QemuUUID *uuid, uint32_t flags,
- uint8_t length, uint64_t timestamp)
+void cxl_assign_event_header(CXLEventRecordHdr *hdr,
+ const QemuUUID *uuid, uint32_t flags,
+ uint8_t length, uint64_t timestamp)
{
st24_le_p(&hdr->flags, flags);
hdr->length = length;
@@ -1866,28 +1880,13 @@ void qmp_cxl_inject_memory_module_event(const char *path, CxlEventLog log,
}
}
-/* CXL r3.1 Table 8-50: Dynamic Capacity Event Record */
-static const QemuUUID dynamic_capacity_uuid = {
- .data = UUID(0xca95afa7, 0xf183, 0x4018, 0x8c, 0x2f,
- 0x95, 0x26, 0x8e, 0x10, 0x1a, 0x2a),
-};
-
-typedef enum CXLDCEventType {
- DC_EVENT_ADD_CAPACITY = 0x0,
- DC_EVENT_RELEASE_CAPACITY = 0x1,
- DC_EVENT_FORCED_RELEASE_CAPACITY = 0x2,
- DC_EVENT_REGION_CONFIG_UPDATED = 0x3,
- DC_EVENT_ADD_CAPACITY_RSP = 0x4,
- DC_EVENT_CAPACITY_RELEASED = 0x5,
-} CXLDCEventType;
-
/*
* Check whether the range [dpa, dpa + len - 1] has overlaps with extents in
* the list.
* Return value: return true if has overlaps; otherwise, return false
*/
-static bool cxl_extents_overlaps_dpa_range(CXLDCExtentList *list,
- uint64_t dpa, uint64_t len)
+bool cxl_extents_overlaps_dpa_range(CXLDCExtentList *list,
+ uint64_t dpa, uint64_t len)
{
CXLDCExtent *ent;
Range range1, range2;
@@ -1932,8 +1931,8 @@ bool cxl_extents_contains_dpa_range(CXLDCExtentList *list,
return false;
}
-static bool cxl_extent_groups_overlaps_dpa_range(CXLDCExtentGroupList *list,
- uint64_t dpa, uint64_t len)
+bool cxl_extent_groups_overlaps_dpa_range(CXLDCExtentGroupList *list,
+ uint64_t dpa, uint64_t len)
{
CXLDCExtentGroup *group;
@@ -1958,15 +1957,11 @@ static void qmp_cxl_process_dynamic_capacity_prescriptive(const char *path,
CxlDynamicCapacityExtentList *records, Error **errp)
{
Object *obj;
- CXLEventDynamicCapacity dCap = {};
- CXLEventRecordHdr *hdr = &dCap.hdr;
CXLType3Dev *dcd;
- uint8_t flags = 1 << CXL_EVENT_TYPE_INFO;
uint32_t num_extents = 0;
CxlDynamicCapacityExtentList *list;
CXLDCExtentGroup *group = NULL;
g_autofree CXLDCExtentRaw *extents = NULL;
- uint8_t enc_log = CXL_EVENT_TYPE_DYNAMIC_CAP;
uint64_t dpa, offset, len, block_size;
g_autofree unsigned long *blk_bitmap = NULL;
int i;
@@ -2076,40 +2071,10 @@ static void qmp_cxl_process_dynamic_capacity_prescriptive(const char *path,
}
if (group) {
cxl_extent_group_list_insert_tail(&dcd->dc.extents_pending, group);
+ dcd->dc.total_extent_count += num_extents;
}
- /*
- * CXL r3.1 section 8.2.9.2.1.6: Dynamic Capacity Event Record
- *
- * All Dynamic Capacity event records shall set the Event Record Severity
- * field in the Common Event Record Format to Informational Event. All
- * Dynamic Capacity related events shall be logged in the Dynamic Capacity
- * Event Log.
- */
- cxl_assign_event_header(hdr, &dynamic_capacity_uuid, flags, sizeof(dCap),
- cxl_device_get_timestamp(&dcd->cxl_dstate));
-
- dCap.type = type;
- /* FIXME: for now, validity flag is cleared */
- dCap.validity_flags = 0;
- stw_le_p(&dCap.host_id, hid);
- /* only valid for DC_REGION_CONFIG_UPDATED event */
- dCap.updated_region_id = 0;
- for (i = 0; i < num_extents; i++) {
- memcpy(&dCap.dynamic_capacity_extent, &extents[i],
- sizeof(CXLDCExtentRaw));
-
- dCap.flags = 0;
- if (i < num_extents - 1) {
- /* Set "More" flag */
- dCap.flags |= BIT(0);
- }
-
- if (cxl_event_insert(&dcd->cxl_dstate, enc_log,
- (CXLEventRecordRaw *)&dCap)) {
- cxl_event_irq_assert(dcd);
- }
- }
+ cxl_create_dc_event_records_for_extents(dcd, type, extents, num_extents);
}
void qmp_cxl_add_dynamic_capacity(const char *path, uint16_t host_id,
diff --git a/hw/microblaze/Kconfig b/hw/microblaze/Kconfig
index b0214b2..72d8072 100644
--- a/hw/microblaze/Kconfig
+++ b/hw/microblaze/Kconfig
@@ -1,7 +1,7 @@
config PETALOGIX_S3ADSP1800
bool
default y
- depends on MICROBLAZE
+ depends on MICROBLAZE && FDT
select PFLASH_CFI01
select XILINX
select XILINX_AXI
@@ -11,7 +11,7 @@ config PETALOGIX_S3ADSP1800
config PETALOGIX_ML605
bool
default y
- depends on MICROBLAZE
+ depends on MICROBLAZE && FDT
select PFLASH_CFI01
select SERIAL_MM
select SSI_M25P80
diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig
index b09c89a..f84fffc 100644
--- a/hw/mips/Kconfig
+++ b/hw/mips/Kconfig
@@ -76,7 +76,7 @@ config LOONGSON3V
config MIPS_CPS
bool
- select MIPS_ITU
+ select MIPS_ITU if TCG
config MIPS_BOSTON
bool
diff --git a/hw/mips/cps.c b/hw/mips/cps.c
index 2a3ba3f..e47695e 100644
--- a/hw/mips/cps.c
+++ b/hw/mips/cps.c
@@ -24,7 +24,7 @@
#include "hw/mips/mips.h"
#include "hw/qdev-clock.h"
#include "hw/qdev-properties.h"
-#include "system/kvm.h"
+#include "system/tcg.h"
#include "system/reset.h"
qemu_irq get_cps_irq(MIPSCPSState *s, int pin_number)
@@ -59,7 +59,7 @@ static bool cpu_mips_itu_supported(CPUMIPSState *env)
{
bool is_mt = (env->CP0_Config5 & (1 << CP0C5_VP)) || ase_mt_available(env);
- return is_mt && !kvm_enabled();
+ return is_mt && tcg_enabled();
}
static void mips_cps_realize(DeviceState *dev, Error **errp)
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index c27285b..4e35657 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -119,6 +119,7 @@ config STM32L4X5_RCC
config MIPS_ITU
bool
+ depends on TCG
config MPS2_FPGAIO
bool
diff --git a/hw/net/can/ctucan_core.c b/hw/net/can/ctucan_core.c
index 17131a4..6bd99c4 100644
--- a/hw/net/can/ctucan_core.c
+++ b/hw/net/can/ctucan_core.c
@@ -28,7 +28,6 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
-#include "qemu/bswap.h"
#include "qemu/bitops.h"
#include "hw/irq.h"
#include "migration/vmstate.h"
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
index 6dda1e5..3017e12 100644
--- a/hw/net/lan9118.c
+++ b/hw/net/lan9118.c
@@ -21,6 +21,7 @@
#include "hw/ptimer.h"
#include "hw/qdev-properties.h"
#include "qapi/error.h"
+#include "qemu/bswap.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include <zlib.h> /* for crc32 */
diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c
index 654a087..324fb93 100644
--- a/hw/net/rtl8139.c
+++ b/hw/net/rtl8139.c
@@ -57,6 +57,7 @@
#include "system/dma.h"
#include "qemu/module.h"
#include "qemu/timer.h"
+#include "qemu/bswap.h"
#include "net/net.h"
#include "net/eth.h"
#include "system/system.h"
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 00df5fd..c4c49b0 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -158,7 +158,7 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
virtio_host_has_feature(vdev, VIRTIO_NET_F_RSS) ?
VIRTIO_NET_RSS_MAX_TABLE_LEN : 1);
virtio_stl_p(vdev, &netcfg.supported_hash_types,
- VIRTIO_NET_RSS_SUPPORTED_HASHES);
+ n->rss_data.supported_hash_types);
memcpy(config, &netcfg, n->config_size);
/*
@@ -756,79 +756,6 @@ static void virtio_net_set_queue_pairs(VirtIONet *n)
static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue);
-static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features,
- Error **errp)
-{
- VirtIONet *n = VIRTIO_NET(vdev);
- NetClientState *nc = qemu_get_queue(n->nic);
-
- /* Firstly sync all virtio-net possible supported features */
- features |= n->host_features;
-
- virtio_add_feature(&features, VIRTIO_NET_F_MAC);
-
- if (!peer_has_vnet_hdr(n)) {
- virtio_clear_feature(&features, VIRTIO_NET_F_CSUM);
- virtio_clear_feature(&features, VIRTIO_NET_F_HOST_TSO4);
- virtio_clear_feature(&features, VIRTIO_NET_F_HOST_TSO6);
- virtio_clear_feature(&features, VIRTIO_NET_F_HOST_ECN);
-
- virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_CSUM);
- virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_TSO4);
- virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_TSO6);
- virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_ECN);
-
- virtio_clear_feature(&features, VIRTIO_NET_F_HOST_USO);
- virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_USO4);
- virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_USO6);
-
- virtio_clear_feature(&features, VIRTIO_NET_F_HASH_REPORT);
- }
-
- if (!peer_has_vnet_hdr(n) || !peer_has_ufo(n)) {
- virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_UFO);
- virtio_clear_feature(&features, VIRTIO_NET_F_HOST_UFO);
- }
-
- if (!peer_has_uso(n)) {
- virtio_clear_feature(&features, VIRTIO_NET_F_HOST_USO);
- virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_USO4);
- virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_USO6);
- }
-
- if (!get_vhost_net(nc->peer)) {
- return features;
- }
-
- if (!ebpf_rss_is_loaded(&n->ebpf_rss)) {
- virtio_clear_feature(&features, VIRTIO_NET_F_RSS);
- }
- features = vhost_net_get_features(get_vhost_net(nc->peer), features);
- vdev->backend_features = features;
-
- if (n->mtu_bypass_backend &&
- (n->host_features & 1ULL << VIRTIO_NET_F_MTU)) {
- features |= (1ULL << VIRTIO_NET_F_MTU);
- }
-
- /*
- * Since GUEST_ANNOUNCE is emulated the feature bit could be set without
- * enabled. This happens in the vDPA case.
- *
- * Make sure the feature set is not incoherent, as the driver could refuse
- * to start.
- *
- * TODO: QEMU is able to emulate a CVQ just for guest_announce purposes,
- * helping guest to notify the new location with vDPA devices that does not
- * support it.
- */
- if (!virtio_has_feature(vdev->backend_features, VIRTIO_NET_F_CTRL_VQ)) {
- virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_ANNOUNCE);
- }
-
- return features;
-}
-
static uint64_t virtio_net_bad_features(VirtIODevice *vdev)
{
uint64_t features = 0;
@@ -1255,7 +1182,7 @@ static void rss_data_to_rss_config(struct VirtioNetRssData *data,
{
config->redirect = data->redirect;
config->populate_hash = data->populate_hash;
- config->hash_types = data->hash_types;
+ config->hash_types = data->runtime_hash_types;
config->indirections_len = data->indirections_len;
config->default_queue = data->default_queue;
}
@@ -1290,6 +1217,10 @@ static void virtio_net_detach_ebpf_rss(VirtIONet *n)
static void virtio_net_commit_rss_config(VirtIONet *n)
{
+ if (n->rss_data.peer_hash_available) {
+ return;
+ }
+
if (n->rss_data.enabled) {
n->rss_data.enabled_software_rss = n->rss_data.populate_hash;
if (n->rss_data.populate_hash) {
@@ -1304,7 +1235,7 @@ static void virtio_net_commit_rss_config(VirtIONet *n)
}
trace_virtio_net_rss_enable(n,
- n->rss_data.hash_types,
+ n->rss_data.runtime_hash_types,
n->rss_data.indirections_len,
sizeof(n->rss_data.key));
} else {
@@ -1415,7 +1346,7 @@ static uint16_t virtio_net_handle_rss(VirtIONet *n,
err_value = (uint32_t)s;
goto error;
}
- n->rss_data.hash_types = virtio_ldl_p(vdev, &cfg.hash_types);
+ n->rss_data.runtime_hash_types = virtio_ldl_p(vdev, &cfg.hash_types);
n->rss_data.indirections_len =
virtio_lduw_p(vdev, &cfg.indirection_table_mask);
if (!do_rss) {
@@ -1478,12 +1409,12 @@ static uint16_t virtio_net_handle_rss(VirtIONet *n,
err_value = temp.b;
goto error;
}
- if (!temp.b && n->rss_data.hash_types) {
+ if (!temp.b && n->rss_data.runtime_hash_types) {
err_msg = "No key provided";
err_value = 0;
goto error;
}
- if (!temp.b && !n->rss_data.hash_types) {
+ if (!temp.b && !n->rss_data.runtime_hash_types) {
virtio_net_disable_rss(n);
return queue_pairs;
}
@@ -1885,7 +1816,7 @@ static int virtio_net_process_rss(NetClientState *nc, const uint8_t *buf,
net_rx_pkt_set_protocols(pkt, &iov, 1, n->host_hdr_len);
net_rx_pkt_get_protocols(pkt, &hasip4, &hasip6, &l4hdr_proto);
net_hash_type = virtio_net_get_hash_type(hasip4, hasip6, l4hdr_proto,
- n->rss_data.hash_types);
+ n->rss_data.runtime_hash_types);
if (net_hash_type > NetPktRssIpV6UdpEx) {
if (n->rss_data.populate_hash) {
hdr->hash_value = VIRTIO_NET_HASH_REPORT_NONE;
@@ -3077,6 +3008,103 @@ static int virtio_net_pre_load_queues(VirtIODevice *vdev, uint32_t n)
return 0;
}
+static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features,
+ Error **errp)
+{
+ VirtIONet *n = VIRTIO_NET(vdev);
+ NetClientState *nc = qemu_get_queue(n->nic);
+ uint32_t supported_hash_types = n->rss_data.supported_hash_types;
+ uint32_t peer_hash_types = n->rss_data.peer_hash_types;
+ bool use_own_hash =
+ (supported_hash_types & VIRTIO_NET_RSS_SUPPORTED_HASHES) ==
+ supported_hash_types;
+ bool use_peer_hash =
+ n->rss_data.peer_hash_available &&
+ (supported_hash_types & peer_hash_types) == supported_hash_types;
+
+ /* Firstly sync all virtio-net possible supported features */
+ features |= n->host_features;
+
+ virtio_add_feature(&features, VIRTIO_NET_F_MAC);
+
+ if (!peer_has_vnet_hdr(n)) {
+ virtio_clear_feature(&features, VIRTIO_NET_F_CSUM);
+ virtio_clear_feature(&features, VIRTIO_NET_F_HOST_TSO4);
+ virtio_clear_feature(&features, VIRTIO_NET_F_HOST_TSO6);
+ virtio_clear_feature(&features, VIRTIO_NET_F_HOST_ECN);
+
+ virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_CSUM);
+ virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_TSO4);
+ virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_TSO6);
+ virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_ECN);
+
+ virtio_clear_feature(&features, VIRTIO_NET_F_HOST_USO);
+ virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_USO4);
+ virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_USO6);
+
+ virtio_clear_feature(&features, VIRTIO_NET_F_HASH_REPORT);
+ }
+
+ if (!peer_has_vnet_hdr(n) || !peer_has_ufo(n)) {
+ virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_UFO);
+ virtio_clear_feature(&features, VIRTIO_NET_F_HOST_UFO);
+ }
+
+ if (!peer_has_uso(n)) {
+ virtio_clear_feature(&features, VIRTIO_NET_F_HOST_USO);
+ virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_USO4);
+ virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_USO6);
+ }
+
+ if (!get_vhost_net(nc->peer)) {
+ if (!use_own_hash) {
+ virtio_clear_feature(&features, VIRTIO_NET_F_HASH_REPORT);
+ virtio_clear_feature(&features, VIRTIO_NET_F_RSS);
+ } else if (virtio_has_feature(features, VIRTIO_NET_F_RSS)) {
+ virtio_net_load_ebpf(n, errp);
+ }
+
+ return features;
+ }
+
+ if (!use_peer_hash) {
+ virtio_clear_feature(&features, VIRTIO_NET_F_HASH_REPORT);
+
+ if (!use_own_hash || !virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
+ if (!virtio_net_load_ebpf(n, errp)) {
+ return features;
+ }
+
+ virtio_clear_feature(&features, VIRTIO_NET_F_RSS);
+ }
+ }
+
+ features = vhost_net_get_features(get_vhost_net(nc->peer), features);
+ vdev->backend_features = features;
+
+ if (n->mtu_bypass_backend &&
+ (n->host_features & 1ULL << VIRTIO_NET_F_MTU)) {
+ features |= (1ULL << VIRTIO_NET_F_MTU);
+ }
+
+ /*
+ * Since GUEST_ANNOUNCE is emulated the feature bit could be set without
+ * enabled. This happens in the vDPA case.
+ *
+ * Make sure the feature set is not incoherent, as the driver could refuse
+ * to start.
+ *
+ * TODO: QEMU is able to emulate a CVQ just for guest_announce purposes,
+ * helping guest to notify the new location with vDPA devices that does not
+ * support it.
+ */
+ if (!virtio_has_feature(vdev->backend_features, VIRTIO_NET_F_CTRL_VQ)) {
+ virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_ANNOUNCE);
+ }
+
+ return features;
+}
+
static int virtio_net_post_load_device(void *opaque, int version_id)
{
VirtIONet *n = opaque;
@@ -3315,6 +3343,17 @@ static const VMStateDescription vmstate_virtio_net_has_vnet = {
},
};
+static int virtio_net_rss_post_load(void *opaque, int version_id)
+{
+ VirtIONet *n = VIRTIO_NET(opaque);
+
+ if (version_id == 1) {
+ n->rss_data.supported_hash_types = VIRTIO_NET_RSS_SUPPORTED_HASHES;
+ }
+
+ return 0;
+}
+
static bool virtio_net_rss_needed(void *opaque)
{
return VIRTIO_NET(opaque)->rss_data.enabled;
@@ -3322,14 +3361,16 @@ static bool virtio_net_rss_needed(void *opaque)
static const VMStateDescription vmstate_virtio_net_rss = {
.name = "virtio-net-device/rss",
- .version_id = 1,
+ .version_id = 2,
.minimum_version_id = 1,
+ .post_load = virtio_net_rss_post_load,
.needed = virtio_net_rss_needed,
.fields = (const VMStateField[]) {
VMSTATE_BOOL(rss_data.enabled, VirtIONet),
VMSTATE_BOOL(rss_data.redirect, VirtIONet),
VMSTATE_BOOL(rss_data.populate_hash, VirtIONet),
- VMSTATE_UINT32(rss_data.hash_types, VirtIONet),
+ VMSTATE_UINT32(rss_data.runtime_hash_types, VirtIONet),
+ VMSTATE_UINT32_V(rss_data.supported_hash_types, VirtIONet, 2),
VMSTATE_UINT16(rss_data.indirections_len, VirtIONet),
VMSTATE_UINT16(rss_data.default_queue, VirtIONet),
VMSTATE_UINT8_ARRAY(rss_data.key, VirtIONet,
@@ -3916,8 +3957,17 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
net_rx_pkt_init(&n->rx_pkt);
- if (virtio_has_feature(n->host_features, VIRTIO_NET_F_RSS)) {
- virtio_net_load_ebpf(n, errp);
+ if (qemu_get_vnet_hash_supported_types(qemu_get_queue(n->nic)->peer,
+ &n->rss_data.peer_hash_types)) {
+ n->rss_data.peer_hash_available = true;
+ n->rss_data.supported_hash_types =
+ n->rss_data.specified_hash_types.on_bits |
+ (n->rss_data.specified_hash_types.auto_bits &
+ n->rss_data.peer_hash_types);
+ } else {
+ n->rss_data.supported_hash_types =
+ n->rss_data.specified_hash_types.on_bits |
+ n->rss_data.specified_hash_types.auto_bits;
}
}
@@ -4134,6 +4184,42 @@ static const Property virtio_net_properties[] = {
VIRTIO_NET_F_GUEST_USO6, true),
DEFINE_PROP_BIT64("host_uso", VirtIONet, host_features,
VIRTIO_NET_F_HOST_USO, true),
+ DEFINE_PROP_ON_OFF_AUTO_BIT64("hash-ipv4", VirtIONet,
+ rss_data.specified_hash_types,
+ VIRTIO_NET_HASH_REPORT_IPv4 - 1,
+ ON_OFF_AUTO_AUTO),
+ DEFINE_PROP_ON_OFF_AUTO_BIT64("hash-tcp4", VirtIONet,
+ rss_data.specified_hash_types,
+ VIRTIO_NET_HASH_REPORT_TCPv4 - 1,
+ ON_OFF_AUTO_AUTO),
+ DEFINE_PROP_ON_OFF_AUTO_BIT64("hash-udp4", VirtIONet,
+ rss_data.specified_hash_types,
+ VIRTIO_NET_HASH_REPORT_UDPv4 - 1,
+ ON_OFF_AUTO_AUTO),
+ DEFINE_PROP_ON_OFF_AUTO_BIT64("hash-ipv6", VirtIONet,
+ rss_data.specified_hash_types,
+ VIRTIO_NET_HASH_REPORT_IPv6 - 1,
+ ON_OFF_AUTO_AUTO),
+ DEFINE_PROP_ON_OFF_AUTO_BIT64("hash-tcp6", VirtIONet,
+ rss_data.specified_hash_types,
+ VIRTIO_NET_HASH_REPORT_TCPv6 - 1,
+ ON_OFF_AUTO_AUTO),
+ DEFINE_PROP_ON_OFF_AUTO_BIT64("hash-udp6", VirtIONet,
+ rss_data.specified_hash_types,
+ VIRTIO_NET_HASH_REPORT_UDPv6 - 1,
+ ON_OFF_AUTO_AUTO),
+ DEFINE_PROP_ON_OFF_AUTO_BIT64("hash-ipv6ex", VirtIONet,
+ rss_data.specified_hash_types,
+ VIRTIO_NET_HASH_REPORT_IPv6_EX - 1,
+ ON_OFF_AUTO_AUTO),
+ DEFINE_PROP_ON_OFF_AUTO_BIT64("hash-tcp6ex", VirtIONet,
+ rss_data.specified_hash_types,
+ VIRTIO_NET_HASH_REPORT_TCPv6_EX - 1,
+ ON_OFF_AUTO_AUTO),
+ DEFINE_PROP_ON_OFF_AUTO_BIT64("hash-udp6ex", VirtIONet,
+ rss_data.specified_hash_types,
+ VIRTIO_NET_HASH_REPORT_UDPv6_EX - 1,
+ ON_OFF_AUTO_AUTO),
};
static void virtio_net_class_init(ObjectClass *klass, const void *data)
diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c
index 7c0ca56..af73aa8 100644
--- a/hw/net/vmxnet3.c
+++ b/hw/net/vmxnet3.c
@@ -22,7 +22,6 @@
#include "net/tap.h"
#include "net/checksum.h"
#include "system/system.h"
-#include "qemu/bswap.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "hw/pci/msix.h"
diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig
index 35c0415..9824fa1 100644
--- a/hw/pci-host/Kconfig
+++ b/hw/pci-host/Kconfig
@@ -54,6 +54,7 @@ config PCI_EXPRESS_Q35
config PCI_EXPRESS_GENERIC_BRIDGE
bool
select PCI_EXPRESS
+ imply ACPI_PCI
config PCI_EXPRESS_XILINX
bool
diff --git a/hw/pci-host/gpex-acpi.c b/hw/pci-host/gpex-acpi.c
index 0aba47c..952a0ac 100644
--- a/hw/pci-host/gpex-acpi.c
+++ b/hw/pci-host/gpex-acpi.c
@@ -1,5 +1,6 @@
#include "qemu/osdep.h"
#include "hw/acpi/aml-build.h"
+#include "hw/acpi/pci.h"
#include "hw/pci-host/gpex.h"
#include "hw/arm/virt.h"
#include "hw/pci/pci_bus.h"
@@ -50,61 +51,10 @@ static void acpi_dsdt_add_pci_route_table(Aml *dev, uint32_t irq,
}
}
-static void acpi_dsdt_add_pci_osc(Aml *dev)
+static Aml *build_pci_host_bridge_dsm_method(void)
{
- Aml *method, *UUID, *ifctx, *ifctx1, *elsectx, *buf;
-
- /* Declare an _OSC (OS Control Handoff) method */
- aml_append(dev, aml_name_decl("SUPP", aml_int(0)));
- aml_append(dev, aml_name_decl("CTRL", aml_int(0)));
- method = aml_method("_OSC", 4, AML_NOTSERIALIZED);
- aml_append(method,
- aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1"));
-
- /* PCI Firmware Specification 3.0
- * 4.5.1. _OSC Interface for PCI Host Bridge Devices
- * The _OSC interface for a PCI/PCI-X/PCI Express hierarchy is
- * identified by the Universal Unique IDentifier (UUID)
- * 33DB4D5B-1FF7-401C-9657-7441C03DD766
- */
- UUID = aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766");
- ifctx = aml_if(aml_equal(aml_arg(0), UUID));
- aml_append(ifctx,
- aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2"));
- aml_append(ifctx,
- aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3"));
- aml_append(ifctx, aml_store(aml_name("CDW2"), aml_name("SUPP")));
- aml_append(ifctx, aml_store(aml_name("CDW3"), aml_name("CTRL")));
-
- /*
- * Allow OS control for all 5 features:
- * PCIeHotplug SHPCHotplug PME AER PCIeCapability.
- */
- aml_append(ifctx, aml_and(aml_name("CTRL"), aml_int(0x1F),
- aml_name("CTRL")));
-
- ifctx1 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(0x1))));
- aml_append(ifctx1, aml_or(aml_name("CDW1"), aml_int(0x08),
- aml_name("CDW1")));
- aml_append(ifctx, ifctx1);
-
- ifctx1 = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), aml_name("CTRL"))));
- aml_append(ifctx1, aml_or(aml_name("CDW1"), aml_int(0x10),
- aml_name("CDW1")));
- aml_append(ifctx, ifctx1);
-
- aml_append(ifctx, aml_store(aml_name("CTRL"), aml_name("CDW3")));
- aml_append(ifctx, aml_return(aml_arg(3)));
- aml_append(method, ifctx);
-
- elsectx = aml_else();
- aml_append(elsectx, aml_or(aml_name("CDW1"), aml_int(4),
- aml_name("CDW1")));
- aml_append(elsectx, aml_return(aml_arg(3)));
- aml_append(method, elsectx);
- aml_append(dev, method);
-
- method = aml_method("_DSM", 4, AML_NOTSERIALIZED);
+ Aml *method = aml_method("_DSM", 4, AML_NOTSERIALIZED);
+ Aml *UUID, *ifctx, *ifctx1, *buf;
/* PCI Firmware Specification 3.0
* 4.6.1. _DSM for PCI Express Slot Information
@@ -123,7 +73,16 @@ static void acpi_dsdt_add_pci_osc(Aml *dev)
byte_list[0] = 0;
buf = aml_buffer(1, byte_list);
aml_append(method, aml_return(buf));
- aml_append(dev, method);
+ return method;
+}
+
+static void acpi_dsdt_add_host_bridge_methods(Aml *dev,
+ bool enable_native_pcie_hotplug)
+{
+ /* Declare an _OSC (OS Control Handoff) method */
+ aml_append(dev,
+ build_pci_host_bridge_osc_method(enable_native_pcie_hotplug));
+ aml_append(dev, build_pci_host_bridge_dsm_method());
}
void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg)
@@ -192,7 +151,8 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg)
if (is_cxl) {
build_cxl_osc_method(dev);
} else {
- acpi_dsdt_add_pci_osc(dev);
+ /* pxb bridges do not have ACPI PCI Hot-plug enabled */
+ acpi_dsdt_add_host_bridge_methods(dev, true);
}
aml_append(scope, dev);
@@ -267,7 +227,7 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg)
}
aml_append(dev, aml_name_decl("_CRS", rbuf));
- acpi_dsdt_add_pci_osc(dev);
+ acpi_dsdt_add_host_bridge_methods(dev, cfg->pci_native_hotplug);
Aml *dev_res0 = aml_device("%s", "RES0");
aml_append(dev_res0, aml_name_decl("_HID", aml_string("PNP0C02")));
diff --git a/hw/pci-host/gt64120.c b/hw/pci-host/gt64120.c
index b12a256..b1d96f6 100644
--- a/hw/pci-host/gt64120.c
+++ b/hw/pci-host/gt64120.c
@@ -28,6 +28,7 @@
#include "qapi/error.h"
#include "qemu/units.h"
#include "qemu/log.h"
+#include "qemu/bswap.h"
#include "hw/qdev-properties.h"
#include "hw/registerfields.h"
#include "hw/pci/pci_device.h"
diff --git a/hw/pci-host/pnv_phb3.c b/hw/pci-host/pnv_phb3.c
index a4335f4..5d8383f 100644
--- a/hw/pci-host/pnv_phb3.c
+++ b/hw/pci-host/pnv_phb3.c
@@ -8,6 +8,7 @@
*/
#include "qemu/osdep.h"
#include "qemu/log.h"
+#include "qemu/bswap.h"
#include "qapi/visitor.h"
#include "qapi/error.h"
#include "hw/pci-host/pnv_phb3_regs.h"
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index 77ea352..1899205 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -8,6 +8,7 @@
*/
#include "qemu/osdep.h"
#include "qemu/log.h"
+#include "qemu/bswap.h"
#include "qapi/visitor.h"
#include "qapi/error.h"
#include "target/ppc/cpu.h"
diff --git a/hw/pci-host/ppce500.c b/hw/pci-host/ppce500.c
index 52269b0..975d191 100644
--- a/hw/pci-host/ppce500.c
+++ b/hw/pci-host/ppce500.c
@@ -20,7 +20,6 @@
#include "migration/vmstate.h"
#include "hw/pci/pci_device.h"
#include "hw/pci/pci_host.h"
-#include "qemu/bswap.h"
#include "hw/pci-host/ppce500.h"
#include "qom/object.h"
diff --git a/hw/pci-host/sh_pci.c b/hw/pci-host/sh_pci.c
index de8f6a8..62fb945 100644
--- a/hw/pci-host/sh_pci.c
+++ b/hw/pci-host/sh_pci.c
@@ -28,7 +28,6 @@
#include "hw/irq.h"
#include "hw/pci/pci_device.h"
#include "hw/pci/pci_host.h"
-#include "qemu/bswap.h"
#include "qemu/module.h"
#include "qom/object.h"
diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c
index 8b5683d..ee1416d 100644
--- a/hw/riscv/virt-acpi-build.c
+++ b/hw/riscv/virt-acpi-build.c
@@ -894,7 +894,10 @@ static void virt_acpi_build(RISCVVirtState *s, AcpiBuildTables *tables)
}
acpi_add_table(table_offsets, tables_blob);
- spcr_setup(tables_blob, tables->linker, s);
+
+ if (ms->acpi_spcr_enabled) {
+ spcr_setup(tables_blob, tables->linker, s);
+ }
acpi_add_table(table_offsets, tables_blob);
{
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
index b5dddb2..a3bb5aa 100644
--- a/hw/s390x/s390-pci-inst.c
+++ b/hw/s390x/s390-pci-inst.c
@@ -16,6 +16,7 @@
#include "exec/target_page.h"
#include "system/memory.h"
#include "qemu/error-report.h"
+#include "qemu/bswap.h"
#include "system/hw_accel.h"
#include "hw/boards.h"
#include "hw/pci/pci_device.h"
diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index f24991f..1d264c4 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -275,6 +275,7 @@ static int esp_select(ESPState *s)
if (!s->current_dev) {
/* No such drive */
s->rregs[ESP_RSTAT] = 0;
+ s->asc_mode = ESP_ASC_MODE_DIS;
s->rregs[ESP_RINTR] = INTR_DC;
esp_raise_irq(s);
return -1;
@@ -284,6 +285,7 @@ static int esp_select(ESPState *s)
* Note that we deliberately don't raise the IRQ here: this will be done
* either in esp_transfer_data() or esp_command_complete()
*/
+ s->asc_mode = ESP_ASC_MODE_INI;
return 0;
}
@@ -308,6 +310,7 @@ static void do_command_phase(ESPState *s)
if (!current_lun) {
/* No such drive */
s->rregs[ESP_RSTAT] = 0;
+ s->asc_mode = ESP_ASC_MODE_DIS;
s->rregs[ESP_RINTR] = INTR_DC;
s->rregs[ESP_RSEQ] = SEQ_0;
esp_raise_irq(s);
@@ -487,8 +490,10 @@ static void esp_do_dma(ESPState *s)
case STAT_MO:
if (s->dma_memory_read) {
len = MIN(len, fifo8_num_free(&s->cmdfifo));
- s->dma_memory_read(s->dma_opaque, buf, len);
- esp_set_tc(s, esp_get_tc(s) - len);
+ if (len) {
+ s->dma_memory_read(s->dma_opaque, buf, len);
+ esp_set_tc(s, esp_get_tc(s) - len);
+ }
} else {
len = esp_fifo_pop_buf(s, buf, fifo8_num_used(&s->fifo));
len = MIN(fifo8_num_free(&s->cmdfifo), len);
@@ -541,9 +546,11 @@ static void esp_do_dma(ESPState *s)
trace_esp_do_dma(cmdlen, len);
if (s->dma_memory_read) {
len = MIN(len, fifo8_num_free(&s->cmdfifo));
- s->dma_memory_read(s->dma_opaque, buf, len);
- fifo8_push_all(&s->cmdfifo, buf, len);
- esp_set_tc(s, esp_get_tc(s) - len);
+ if (len) {
+ s->dma_memory_read(s->dma_opaque, buf, len);
+ fifo8_push_all(&s->cmdfifo, buf, len);
+ esp_set_tc(s, esp_get_tc(s) - len);
+ }
} else {
len = esp_fifo_pop_buf(s, buf, fifo8_num_used(&s->fifo));
len = MIN(fifo8_num_free(&s->cmdfifo), len);
@@ -572,8 +579,10 @@ static void esp_do_dma(ESPState *s)
switch (s->rregs[ESP_CMD]) {
case CMD_TI | CMD_DMA:
if (s->dma_memory_read) {
- s->dma_memory_read(s->dma_opaque, s->async_buf, len);
- esp_set_tc(s, esp_get_tc(s) - len);
+ if (len) {
+ s->dma_memory_read(s->dma_opaque, s->async_buf, len);
+ esp_set_tc(s, esp_get_tc(s) - len);
+ }
} else {
/* Copy FIFO data to device */
len = MIN(s->async_len, ESP_FIFO_SZ);
@@ -625,7 +634,9 @@ static void esp_do_dma(ESPState *s)
switch (s->rregs[ESP_CMD]) {
case CMD_TI | CMD_DMA:
if (s->dma_memory_write) {
- s->dma_memory_write(s->dma_opaque, s->async_buf, len);
+ if (len) {
+ s->dma_memory_write(s->dma_opaque, s->async_buf, len);
+ }
} else {
/* Copy device data to FIFO */
len = MIN(len, fifo8_num_free(&s->fifo));
@@ -675,6 +686,7 @@ static void esp_do_dma(ESPState *s)
buf[0] = s->status;
if (s->dma_memory_write) {
+ /* Length already non-zero */
s->dma_memory_write(s->dma_opaque, buf, len);
} else {
esp_fifo_push_buf(s, buf, len);
@@ -709,6 +721,7 @@ static void esp_do_dma(ESPState *s)
buf[0] = 0;
if (s->dma_memory_write) {
+ /* Length already non-zero */
s->dma_memory_write(s->dma_opaque, buf, len);
} else {
esp_fifo_push_buf(s, buf, len);
@@ -1012,6 +1025,7 @@ void esp_transfer_data(SCSIRequest *req, uint32_t len)
*/
s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
s->rregs[ESP_RSEQ] = SEQ_CD;
+ esp_raise_irq(s);
break;
case CMD_SELATNS | CMD_DMA:
@@ -1022,20 +1036,21 @@ void esp_transfer_data(SCSIRequest *req, uint32_t len)
*/
s->rregs[ESP_RINTR] |= INTR_BS;
s->rregs[ESP_RSEQ] = SEQ_MO;
+ esp_raise_irq(s);
break;
case CMD_TI | CMD_DMA:
case CMD_TI:
/*
- * Bus service interrupt raised because of initial change to
- * DATA phase
+ * If the final COMMAND phase data was transferred using a TI
+ * command, clear ESP_CMD to terminate the TI command and raise
+ * the completion interrupt
*/
s->rregs[ESP_CMD] = 0;
s->rregs[ESP_RINTR] |= INTR_BS;
+ esp_raise_irq(s);
break;
}
-
- esp_raise_irq(s);
}
/*
@@ -1090,6 +1105,7 @@ void esp_hard_reset(ESPState *s)
fifo8_reset(&s->cmdfifo);
s->dma = 0;
s->dma_cb = NULL;
+ s->asc_mode = ESP_ASC_MODE_DIS;
s->rregs[ESP_CFG1] = 7;
}
@@ -1113,6 +1129,38 @@ static void parent_esp_reset(ESPState *s, int irq, int level)
}
}
+static bool esp_cmd_is_valid(ESPState *s, uint8_t cmd)
+{
+ uint8_t cmd_group = (cmd & CMD_GRP_MASK) >> 4;
+
+ /* Always allow misc commands */
+ if (cmd_group == CMD_GRP_MISC) {
+ return true;
+ }
+
+ switch (s->asc_mode) {
+ case ESP_ASC_MODE_DIS:
+ /* Disconnected mode: only allow disconnected commands */
+ if (cmd_group == CMD_GRP_DISC) {
+ return true;
+ }
+ break;
+
+ case ESP_ASC_MODE_INI:
+ /* Initiator mode: allow initiator commands */
+ if (cmd_group == CMD_GRP_INIT) {
+ return true;
+ }
+ break;
+
+ default:
+ g_assert_not_reached();
+ }
+
+ trace_esp_invalid_cmd(cmd, s->asc_mode);
+ return false;
+}
+
static void esp_run_cmd(ESPState *s)
{
uint8_t cmd = s->rregs[ESP_CMD];
@@ -1158,6 +1206,7 @@ static void esp_run_cmd(ESPState *s)
break;
case CMD_MSGACC:
trace_esp_mem_writeb_cmd_msgacc(cmd);
+ s->asc_mode = ESP_ASC_MODE_DIS;
s->rregs[ESP_RINTR] |= INTR_DC;
s->rregs[ESP_RSEQ] = 0;
s->rregs[ESP_RFLAGS] = 0;
@@ -1268,6 +1317,11 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
break;
case ESP_CMD:
s->rregs[saddr] = val;
+ if (!esp_cmd_is_valid(s, s->rregs[saddr])) {
+ s->rregs[ESP_RSTAT] |= INTR_IL;
+ esp_raise_irq(s);
+ break;
+ }
esp_run_cmd(s);
break;
case ESP_WBUSID ... ESP_WSYNO:
@@ -1325,6 +1379,14 @@ static bool esp_is_between_version_5_and_6(void *opaque, int version_id)
return version_id >= 5 && version_id <= 6;
}
+static bool esp_is_version_8(void *opaque, int version_id)
+{
+ ESPState *s = ESP(opaque);
+
+ version_id = MIN(version_id, s->mig_version_id);
+ return version_id >= 8;
+}
+
int esp_pre_save(void *opaque)
{
ESPState *s = ESP(object_resolve_path_component(
@@ -1356,13 +1418,18 @@ static int esp_post_load(void *opaque, int version_id)
}
}
+ if (version_id < 8) {
+ /* Assume initiator mode to allow all commands to continue */
+ s->asc_mode = ESP_ASC_MODE_INI;
+ }
+
s->mig_version_id = vmstate_esp.version_id;
return 0;
}
const VMStateDescription vmstate_esp = {
.name = "esp",
- .version_id = 7,
+ .version_id = 8,
.minimum_version_id = 3,
.post_load = esp_post_load,
.fields = (const VMStateField[]) {
@@ -1394,6 +1461,7 @@ const VMStateDescription vmstate_esp = {
esp_is_between_version_5_and_6),
VMSTATE_UINT8_TEST(lun, ESPState, esp_is_version_6),
VMSTATE_BOOL(drq_state, ESPState),
+ VMSTATE_UINT8_TEST(asc_mode, ESPState, esp_is_version_8),
VMSTATE_END_OF_LIST()
},
};
diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events
index f0f2a98..6c2788e 100644
--- a/hw/scsi/trace-events
+++ b/hw/scsi/trace-events
@@ -198,6 +198,7 @@ esp_mem_writeb_cmd_ensel(uint32_t val) "Enable selection (0x%2.2x)"
esp_mem_writeb_cmd_dissel(uint32_t val) "Disable selection (0x%2.2x)"
esp_mem_writeb_cmd_ti(uint32_t val) "Transfer Information (0x%2.2x)"
esp_set_phase(const char *phase) "setting bus phase to %s"
+esp_invalid_cmd(uint8_t cmd, uint8_t asc_mode) "command 0x%x asc_mode 0x%x"
# esp-pci.c
esp_pci_error_invalid_dma_direction(void) "invalid DMA transfer direction"
diff --git a/hw/sensor/lsm303dlhc_mag.c b/hw/sensor/lsm303dlhc_mag.c
index f9e501d..cd5773a 100644
--- a/hw/sensor/lsm303dlhc_mag.c
+++ b/hw/sensor/lsm303dlhc_mag.c
@@ -28,7 +28,6 @@
#include "qapi/visitor.h"
#include "qemu/module.h"
#include "qemu/log.h"
-#include "qemu/bswap.h"
enum LSM303DLHCMagReg {
LSM303DLHC_MAG_REG_CRA = 0x00,
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
index ad4cd67..1ac063c 100644
--- a/hw/smbios/smbios.c
+++ b/hw/smbios/smbios.c
@@ -17,6 +17,7 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
+#include "qemu/bswap.h"
#include "qapi/error.h"
#include "qemu/config-file.h"
#include "qemu/module.h"
diff --git a/hw/vfio-user/container.c b/hw/vfio-user/container.c
index d318e6a..d589dd9 100644
--- a/hw/vfio-user/container.c
+++ b/hw/vfio-user/container.c
@@ -64,8 +64,6 @@ static int vfio_user_dma_unmap(const VFIOContainerBase *bcontainer,
0, &local_err)) {
error_report_err(local_err);
ret = -EFAULT;
- } else {
- ret = 0;
}
} else {
if (!vfio_user_send_wait(container->proxy, &msgp->hdr, NULL,
@@ -92,7 +90,7 @@ static int vfio_user_dma_map(const VFIOContainerBase *bcontainer, hwaddr iova,
bcontainer);
int fd = memory_region_get_fd(mrp);
Error *local_err = NULL;
- int ret;
+ int ret = 0;
VFIOUserFDs *fds = NULL;
VFIOUserDMAMap *msgp = g_malloc0(sizeof(*msgp));
@@ -135,8 +133,6 @@ static int vfio_user_dma_map(const VFIOContainerBase *bcontainer, hwaddr iova,
0, &local_err)) {
error_report_err(local_err);
ret = -EFAULT;
- } else {
- ret = 0;
}
} else {
VFIOUserFDs local_fds = { 1, 0, &fd };
diff --git a/hw/vfio-user/proxy.c b/hw/vfio-user/proxy.c
index c418954..2275d3f 100644
--- a/hw/vfio-user/proxy.c
+++ b/hw/vfio-user/proxy.c
@@ -32,7 +32,6 @@ static void vfio_user_recycle(VFIOUserProxy *proxy, VFIOUserMsg *msg);
static void vfio_user_recv(void *opaque);
static void vfio_user_send(void *opaque);
-static void vfio_user_cb(void *opaque);
static void vfio_user_request(void *opaque);
@@ -492,7 +491,7 @@ static void vfio_user_send(void *opaque)
}
}
-static void vfio_user_cb(void *opaque)
+static void vfio_user_close_cb(void *opaque)
{
VFIOUserProxy *proxy = opaque;
@@ -984,8 +983,11 @@ void vfio_user_disconnect(VFIOUserProxy *proxy)
* handler to run after the proxy fd handlers were
* deleted above.
*/
- aio_bh_schedule_oneshot(proxy->ctx, vfio_user_cb, proxy);
- qemu_cond_wait(&proxy->close_cv, &proxy->lock);
+ aio_bh_schedule_oneshot(proxy->ctx, vfio_user_close_cb, proxy);
+
+ while (proxy->state != VFIO_PROXY_CLOSED) {
+ qemu_cond_wait(&proxy->close_cv, &proxy->lock);
+ }
/* we now hold the only ref to proxy */
qemu_mutex_unlock(&proxy->lock);
diff --git a/hw/vfio/device.c b/hw/vfio/device.c
index 96cf214..52a1996 100644
--- a/hw/vfio/device.c
+++ b/hw/vfio/device.c
@@ -463,6 +463,8 @@ void vfio_device_detach(VFIODevice *vbasedev)
void vfio_device_prepare(VFIODevice *vbasedev, VFIOContainerBase *bcontainer,
struct vfio_device_info *info)
{
+ int i;
+
vbasedev->num_irqs = info->num_irqs;
vbasedev->num_regions = info->num_regions;
vbasedev->flags = info->flags;
@@ -477,6 +479,9 @@ void vfio_device_prepare(VFIODevice *vbasedev, VFIOContainerBase *bcontainer,
vbasedev->num_regions);
if (vbasedev->use_region_fds) {
vbasedev->region_fds = g_new0(int, vbasedev->num_regions);
+ for (i = 0; i < vbasedev->num_regions; i++) {
+ vbasedev->region_fds[i] = -1;
+ }
}
}
@@ -489,7 +494,6 @@ void vfio_device_unprepare(VFIODevice *vbasedev)
if (vbasedev->region_fds != NULL && vbasedev->region_fds[i] != -1) {
close(vbasedev->region_fds[i]);
}
-
}
g_clear_pointer(&vbasedev->reginfo, g_free);
diff --git a/hw/vfio/helpers.c b/hw/vfio/helpers.c
index 9a5f621..23d13e5 100644
--- a/hw/vfio/helpers.c
+++ b/hw/vfio/helpers.c
@@ -209,3 +209,20 @@ retry:
return info;
}
+
+bool vfio_arch_wants_loading_config_after_iter(void)
+{
+ /*
+ * Starting the config load only after all iterables were loaded (during
+ * non-iterables loading phase) is required for ARM64 due to this platform
+ * VFIO dependency on interrupt controller being loaded first.
+ *
+ * See commit d329f5032e17 ("vfio: Move the saving of the config space to
+ * the right place in VFIO migration").
+ */
+#if defined(TARGET_ARM)
+ return true;
+#else
+ return false;
+#endif
+}
diff --git a/hw/vfio/migration-multifd.c b/hw/vfio/migration-multifd.c
index 5563548..e478503 100644
--- a/hw/vfio/migration-multifd.c
+++ b/hw/vfio/migration-multifd.c
@@ -13,7 +13,6 @@
#include "hw/vfio/vfio-device.h"
#include "migration/misc.h"
#include "qapi/error.h"
-#include "qemu/bswap.h"
#include "qemu/error-report.h"
#include "qemu/lockable.h"
#include "qemu/main-loop.h"
@@ -23,6 +22,7 @@
#include "migration-multifd.h"
#include "vfio-migration-internal.h"
#include "trace.h"
+#include "vfio-helpers.h"
#define VFIO_DEVICE_STATE_CONFIG_STATE (1)
@@ -35,6 +35,18 @@ typedef struct VFIODeviceStatePacket {
uint8_t data[0];
} QEMU_PACKED VFIODeviceStatePacket;
+bool vfio_load_config_after_iter(VFIODevice *vbasedev)
+{
+ if (vbasedev->migration_load_config_after_iter == ON_OFF_AUTO_ON) {
+ return true;
+ } else if (vbasedev->migration_load_config_after_iter == ON_OFF_AUTO_OFF) {
+ return false;
+ }
+
+ assert(vbasedev->migration_load_config_after_iter == ON_OFF_AUTO_AUTO);
+ return vfio_arch_wants_loading_config_after_iter();
+}
+
/* type safety */
typedef struct VFIOStateBuffers {
GArray *array;
@@ -50,12 +62,16 @@ typedef struct VFIOMultifd {
bool load_bufs_thread_running;
bool load_bufs_thread_want_exit;
+ bool load_bufs_iter_done;
+ QemuCond load_bufs_iter_done_cond;
+
VFIOStateBuffers load_bufs;
QemuCond load_bufs_buffer_ready_cond;
QemuCond load_bufs_thread_finished_cond;
QemuMutex load_bufs_mutex; /* Lock order: this lock -> BQL */
uint32_t load_buf_idx;
uint32_t load_buf_idx_last;
+ size_t load_buf_queued_pending_buffers_size;
} VFIOMultifd;
static void vfio_state_buffer_clear(gpointer data)
@@ -112,6 +128,7 @@ static bool vfio_load_state_buffer_insert(VFIODevice *vbasedev,
VFIOMigration *migration = vbasedev->migration;
VFIOMultifd *multifd = migration->multifd;
VFIOStateBuffer *lb;
+ size_t data_size = packet_total_size - sizeof(*packet);
vfio_state_buffers_assert_init(&multifd->load_bufs);
if (packet->idx >= vfio_state_buffers_size_get(&multifd->load_bufs)) {
@@ -127,8 +144,19 @@ static bool vfio_load_state_buffer_insert(VFIODevice *vbasedev,
assert(packet->idx >= multifd->load_buf_idx);
- lb->data = g_memdup2(&packet->data, packet_total_size - sizeof(*packet));
- lb->len = packet_total_size - sizeof(*packet);
+ multifd->load_buf_queued_pending_buffers_size += data_size;
+ if (multifd->load_buf_queued_pending_buffers_size >
+ vbasedev->migration_max_queued_buffers_size) {
+ error_setg(errp,
+ "%s: queuing state buffer %" PRIu32
+ " would exceed the size max of %" PRIu64,
+ vbasedev->name, packet->idx,
+ vbasedev->migration_max_queued_buffers_size);
+ return false;
+ }
+
+ lb->data = g_memdup2(&packet->data, data_size);
+ lb->len = data_size;
lb->is_present = true;
return true;
@@ -312,6 +340,9 @@ static bool vfio_load_state_buffer_write(VFIODevice *vbasedev,
assert(wr_ret <= buf_len);
buf_len -= wr_ret;
buf_cur += wr_ret;
+
+ assert(multifd->load_buf_queued_pending_buffers_size >= wr_ret);
+ multifd->load_buf_queued_pending_buffers_size -= wr_ret;
}
trace_vfio_load_state_device_buffer_load_end(vbasedev->name,
@@ -394,6 +425,22 @@ static bool vfio_load_bufs_thread(void *opaque, bool *should_quit, Error **errp)
multifd->load_buf_idx++;
}
+ if (vfio_load_config_after_iter(vbasedev)) {
+ while (!multifd->load_bufs_iter_done) {
+ qemu_cond_wait(&multifd->load_bufs_iter_done_cond,
+ &multifd->load_bufs_mutex);
+
+ /*
+ * Need to re-check cancellation immediately after wait in case
+ * cond was signalled by vfio_load_cleanup_load_bufs_thread().
+ */
+ if (vfio_load_bufs_thread_want_exit(multifd, should_quit)) {
+ error_setg(errp, "operation cancelled");
+ goto thread_exit;
+ }
+ }
+ }
+
if (!vfio_load_bufs_thread_load_config(vbasedev, errp)) {
goto thread_exit;
}
@@ -413,6 +460,48 @@ thread_exit:
return ret;
}
+int vfio_load_state_config_load_ready(VFIODevice *vbasedev)
+{
+ VFIOMigration *migration = vbasedev->migration;
+ VFIOMultifd *multifd = migration->multifd;
+ int ret = 0;
+
+ if (!vfio_multifd_transfer_enabled(vbasedev)) {
+ error_report("%s: got DEV_CONFIG_LOAD_READY outside multifd transfer",
+ vbasedev->name);
+ return -EINVAL;
+ }
+
+ if (!vfio_load_config_after_iter(vbasedev)) {
+ error_report("%s: got DEV_CONFIG_LOAD_READY but was disabled",
+ vbasedev->name);
+ return -EINVAL;
+ }
+
+ assert(multifd);
+
+ /* The lock order is load_bufs_mutex -> BQL so unlock BQL here first */
+ bql_unlock();
+ WITH_QEMU_LOCK_GUARD(&multifd->load_bufs_mutex) {
+ if (multifd->load_bufs_iter_done) {
+ /* Can't print error here as we're outside BQL */
+ ret = -EINVAL;
+ break;
+ }
+
+ multifd->load_bufs_iter_done = true;
+ qemu_cond_signal(&multifd->load_bufs_iter_done_cond);
+ }
+ bql_lock();
+
+ if (ret) {
+ error_report("%s: duplicate DEV_CONFIG_LOAD_READY",
+ vbasedev->name);
+ }
+
+ return ret;
+}
+
static VFIOMultifd *vfio_multifd_new(void)
{
VFIOMultifd *multifd = g_new(VFIOMultifd, 1);
@@ -423,8 +512,12 @@ static VFIOMultifd *vfio_multifd_new(void)
multifd->load_buf_idx = 0;
multifd->load_buf_idx_last = UINT32_MAX;
+ multifd->load_buf_queued_pending_buffers_size = 0;
qemu_cond_init(&multifd->load_bufs_buffer_ready_cond);
+ multifd->load_bufs_iter_done = false;
+ qemu_cond_init(&multifd->load_bufs_iter_done_cond);
+
multifd->load_bufs_thread_running = false;
multifd->load_bufs_thread_want_exit = false;
qemu_cond_init(&multifd->load_bufs_thread_finished_cond);
@@ -448,6 +541,7 @@ static void vfio_load_cleanup_load_bufs_thread(VFIOMultifd *multifd)
multifd->load_bufs_thread_want_exit = true;
qemu_cond_signal(&multifd->load_bufs_buffer_ready_cond);
+ qemu_cond_signal(&multifd->load_bufs_iter_done_cond);
qemu_cond_wait(&multifd->load_bufs_thread_finished_cond,
&multifd->load_bufs_mutex);
}
@@ -460,6 +554,7 @@ static void vfio_multifd_free(VFIOMultifd *multifd)
vfio_load_cleanup_load_bufs_thread(multifd);
qemu_cond_destroy(&multifd->load_bufs_thread_finished_cond);
+ qemu_cond_destroy(&multifd->load_bufs_iter_done_cond);
vfio_state_buffers_destroy(&multifd->load_bufs);
qemu_cond_destroy(&multifd->load_bufs_buffer_ready_cond);
qemu_mutex_destroy(&multifd->load_bufs_mutex);
diff --git a/hw/vfio/migration-multifd.h b/hw/vfio/migration-multifd.h
index ebf22a7..82d2d3a 100644
--- a/hw/vfio/migration-multifd.h
+++ b/hw/vfio/migration-multifd.h
@@ -20,9 +20,12 @@ void vfio_multifd_cleanup(VFIODevice *vbasedev);
bool vfio_multifd_transfer_supported(void);
bool vfio_multifd_transfer_enabled(VFIODevice *vbasedev);
+bool vfio_load_config_after_iter(VFIODevice *vbasedev);
bool vfio_multifd_load_state_buffer(void *opaque, char *data, size_t data_size,
Error **errp);
+int vfio_load_state_config_load_ready(VFIODevice *vbasedev);
+
void vfio_multifd_emit_dummy_eos(VFIODevice *vbasedev, QEMUFile *f);
bool
diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c
index c329578..4c06e3d 100644
--- a/hw/vfio/migration.c
+++ b/hw/vfio/migration.c
@@ -675,7 +675,11 @@ static void vfio_save_state(QEMUFile *f, void *opaque)
int ret;
if (vfio_multifd_transfer_enabled(vbasedev)) {
- vfio_multifd_emit_dummy_eos(vbasedev, f);
+ if (vfio_load_config_after_iter(vbasedev)) {
+ qemu_put_be64(f, VFIO_MIG_FLAG_DEV_CONFIG_LOAD_READY);
+ } else {
+ vfio_multifd_emit_dummy_eos(vbasedev, f);
+ }
return;
}
@@ -784,6 +788,10 @@ static int vfio_load_state(QEMUFile *f, void *opaque, int version_id)
return ret;
}
+ case VFIO_MIG_FLAG_DEV_CONFIG_LOAD_READY:
+ {
+ return vfio_load_state_config_load_ready(vbasedev);
+ }
default:
error_report("%s: Unknown tag 0x%"PRIx64, vbasedev->name, data);
return -EINVAL;
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 1093b28..be05002 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -2893,10 +2893,6 @@ bool vfio_populate_vga(VFIOPCIDevice *vdev, Error **errp)
"vfio-vga-io@0x3c0",
QEMU_PCI_VGA_IO_HI_SIZE);
- pci_register_vga(&vdev->pdev, &vdev->vga->region[QEMU_PCI_VGA_MEM].mem,
- &vdev->vga->region[QEMU_PCI_VGA_IO_LO].mem,
- &vdev->vga->region[QEMU_PCI_VGA_IO_HI].mem);
-
return true;
}
@@ -3228,6 +3224,23 @@ bool vfio_pci_config_setup(VFIOPCIDevice *vdev, Error **errp)
vdev->sub_device_id);
}
+ /*
+ * Class code is a 24-bit value at config space 0x09. Allow overriding it
+ * with any 24-bit value.
+ */
+ if (vdev->class_code != PCI_ANY_ID) {
+ if (vdev->class_code > 0xffffff) {
+ error_setg(errp, "invalid PCI class code provided");
+ return false;
+ }
+ /* Higher 24 bits of PCI_CLASS_REVISION are class code */
+ vfio_add_emulated_long(vdev, PCI_CLASS_REVISION,
+ vdev->class_code << 8, ~0xff);
+ trace_vfio_pci_emulated_class_code(vbasedev->name, vdev->class_code);
+ } else {
+ vdev->class_code = pci_get_long(pdev->config + PCI_CLASS_REVISION) >> 8;
+ }
+
/* QEMU can change multi-function devices to single function, or reverse */
vdev->emulated_config_bits[PCI_HEADER_TYPE] =
PCI_HEADER_TYPE_MULTI_FUNCTION;
@@ -3257,6 +3270,12 @@ bool vfio_pci_config_setup(VFIOPCIDevice *vdev, Error **errp)
vfio_bars_register(vdev);
+ if (vdev->vga && vfio_is_vga(vdev)) {
+ pci_register_vga(&vdev->pdev, &vdev->vga->region[QEMU_PCI_VGA_MEM].mem,
+ &vdev->vga->region[QEMU_PCI_VGA_IO_LO].mem,
+ &vdev->vga->region[QEMU_PCI_VGA_IO_HI].mem);
+ }
+
return true;
}
@@ -3623,6 +3642,11 @@ static const Property vfio_pci_dev_properties[] = {
vbasedev.migration_multifd_transfer,
vfio_pci_migration_multifd_transfer_prop, OnOffAuto,
.set_default = true, .defval.i = ON_OFF_AUTO_AUTO),
+ DEFINE_PROP_ON_OFF_AUTO("x-migration-load-config-after-iter", VFIOPCIDevice,
+ vbasedev.migration_load_config_after_iter,
+ ON_OFF_AUTO_AUTO),
+ DEFINE_PROP_SIZE("x-migration-max-queued-buffers-size", VFIOPCIDevice,
+ vbasedev.migration_max_queued_buffers_size, UINT64_MAX),
DEFINE_PROP_BOOL("migration-events", VFIOPCIDevice,
vbasedev.migration_events, false),
DEFINE_PROP_BOOL("x-no-mmap", VFIOPCIDevice, vbasedev.no_mmap, false),
@@ -3643,6 +3667,8 @@ static const Property vfio_pci_dev_properties[] = {
sub_vendor_id, PCI_ANY_ID),
DEFINE_PROP_UINT32("x-pci-sub-device-id", VFIOPCIDevice,
sub_device_id, PCI_ANY_ID),
+ DEFINE_PROP_UINT32("x-pci-class-code", VFIOPCIDevice,
+ class_code, PCI_ANY_ID),
DEFINE_PROP_UINT32("x-igd-gms", VFIOPCIDevice, igd_gms, 0),
DEFINE_PROP_UNSIGNED_NODEFAULT("x-nv-gpudirect-clique", VFIOPCIDevice,
nv_gpudirect_clique,
@@ -3797,6 +3823,20 @@ static void vfio_pci_dev_class_init(ObjectClass *klass, const void *data)
"x-migration-multifd-transfer",
"Transfer this device state via "
"multifd channels when live migrating it");
+ object_class_property_set_description(klass, /* 10.1 */
+ "x-migration-load-config-after-iter",
+ "Start the config load only after "
+ "all iterables were loaded (during "
+ "non-iterables loading phase) when "
+ "doing live migration of device state "
+ "via multifd channels");
+ object_class_property_set_description(klass, /* 10.1 */
+ "x-migration-max-queued-buffers-size",
+ "Maximum size of in-flight VFIO "
+ "device state buffers queued at the "
+ "destination when doing live "
+ "migration of device state via "
+ "multifd channels");
}
static const TypeInfo vfio_pci_dev_info = {
diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h
index 495fae7..4aa6461 100644
--- a/hw/vfio/pci.h
+++ b/hw/vfio/pci.h
@@ -157,6 +157,7 @@ struct VFIOPCIDevice {
uint32_t device_id;
uint32_t sub_vendor_id;
uint32_t sub_device_id;
+ uint32_t class_code;
uint32_t features;
#define VFIO_FEATURE_ENABLE_VGA_BIT 0
#define VFIO_FEATURE_ENABLE_VGA (1 << VFIO_FEATURE_ENABLE_VGA_BIT)
@@ -205,10 +206,7 @@ static inline bool vfio_pci_is(VFIOPCIDevice *vdev, uint32_t vendor, uint32_t de
static inline bool vfio_is_vga(VFIOPCIDevice *vdev)
{
- PCIDevice *pdev = &vdev->pdev;
- uint16_t class = pci_get_word(pdev->config + PCI_CLASS_DEVICE);
-
- return class == PCI_CLASS_DISPLAY_VGA;
+ return (vdev->class_code >> 8) == PCI_CLASS_DISPLAY_VGA;
}
/* MSI/MSI-X/INTx */
diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events
index 8ec0ad0..fc6ed23 100644
--- a/hw/vfio/trace-events
+++ b/hw/vfio/trace-events
@@ -48,6 +48,7 @@ vfio_pci_emulated_vendor_id(const char *name, uint16_t val) "%s 0x%04x"
vfio_pci_emulated_device_id(const char *name, uint16_t val) "%s 0x%04x"
vfio_pci_emulated_sub_vendor_id(const char *name, uint16_t val) "%s 0x%04x"
vfio_pci_emulated_sub_device_id(const char *name, uint16_t val) "%s 0x%04x"
+vfio_pci_emulated_class_code(const char *name, uint32_t val) "%s 0x%06x"
# pci-quirks.c
vfio_quirk_rom_in_denylist(const char *name, uint16_t vid, uint16_t did) "%s %04x:%04x"
diff --git a/hw/vfio/vfio-helpers.h b/hw/vfio/vfio-helpers.h
index 54a327f..ce31758 100644
--- a/hw/vfio/vfio-helpers.h
+++ b/hw/vfio/vfio-helpers.h
@@ -32,4 +32,6 @@ struct vfio_device_info *vfio_get_device_info(int fd);
int vfio_kvm_device_add_fd(int fd, Error **errp);
int vfio_kvm_device_del_fd(int fd, Error **errp);
+bool vfio_arch_wants_loading_config_after_iter(void);
+
#endif /* HW_VFIO_VFIO_HELPERS_H */
diff --git a/hw/vfio/vfio-migration-internal.h b/hw/vfio/vfio-migration-internal.h
index a8b456b..54141e2 100644
--- a/hw/vfio/vfio-migration-internal.h
+++ b/hw/vfio/vfio-migration-internal.h
@@ -32,6 +32,7 @@
#define VFIO_MIG_FLAG_DEV_SETUP_STATE (0xffffffffef100003ULL)
#define VFIO_MIG_FLAG_DEV_DATA_STATE (0xffffffffef100004ULL)
#define VFIO_MIG_FLAG_DEV_INIT_DATA_SENT (0xffffffffef100005ULL)
+#define VFIO_MIG_FLAG_DEV_CONFIG_LOAD_READY (0xffffffffef100006ULL)
typedef struct VFIODevice VFIODevice;
typedef struct VFIOMultifd VFIOMultifd;
diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build
index 164f6fd..3ea7b3c 100644
--- a/hw/virtio/meson.build
+++ b/hw/virtio/meson.build
@@ -1,6 +1,7 @@
system_virtio_ss = ss.source_set()
system_virtio_ss.add(files('virtio-bus.c'))
system_virtio_ss.add(files('iothread-vq-mapping.c'))
+system_virtio_ss.add(files('virtio-config-io.c'))
system_virtio_ss.add(when: 'CONFIG_VIRTIO_PCI', if_true: files('virtio-pci.c'))
system_virtio_ss.add(when: 'CONFIG_VIRTIO_MMIO', if_true: files('virtio-mmio.c'))
system_virtio_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('virtio-crypto.c'))
@@ -10,11 +11,11 @@ system_virtio_ss.add(when: 'CONFIG_VHOST_VDPA_DEV', if_true: files('vdpa-dev.c')
specific_virtio_ss = ss.source_set()
specific_virtio_ss.add(files('virtio.c'))
-specific_virtio_ss.add(files('virtio-config-io.c', 'virtio-qmp.c'))
+specific_virtio_ss.add(files('virtio-qmp.c'))
if have_vhost
system_virtio_ss.add(files('vhost.c'))
- specific_virtio_ss.add(files('vhost-backend.c', 'vhost-iova-tree.c'))
+ system_virtio_ss.add(files('vhost-backend.c', 'vhost-iova-tree.c'))
if have_vhost_user
# fixme - this really should be generic
specific_virtio_ss.add(files('vhost-user.c'))
@@ -43,22 +44,22 @@ if have_vhost
endif
if have_vhost_vdpa
system_virtio_ss.add(files('vhost-vdpa.c'))
- specific_virtio_ss.add(files('vhost-shadow-virtqueue.c'))
+ system_virtio_ss.add(files('vhost-shadow-virtqueue.c'))
endif
else
system_virtio_ss.add(files('vhost-stub.c'))
endif
+system_virtio_ss.add(when: 'CONFIG_VHOST_USER_VSOCK', if_true: files('vhost-user-vsock.c'))
+system_virtio_ss.add(when: 'CONFIG_VIRTIO_RNG', if_true: files('virtio-rng.c'))
specific_virtio_ss.add(when: 'CONFIG_VIRTIO_BALLOON', if_true: files('virtio-balloon.c'))
specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_FS', if_true: files('vhost-user-fs.c'))
specific_virtio_ss.add(when: 'CONFIG_VIRTIO_PMEM', if_true: files('virtio-pmem.c'))
specific_virtio_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock.c'))
-specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_VSOCK', if_true: files('vhost-user-vsock.c'))
-specific_virtio_ss.add(when: 'CONFIG_VIRTIO_RNG', if_true: files('virtio-rng.c'))
-specific_virtio_ss.add(when: 'CONFIG_VIRTIO_NSM', if_true: [files('virtio-nsm.c', 'cbor-helpers.c'), libcbor])
specific_virtio_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: files('virtio-mem.c'))
-specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_SCMI', if_true: files('vhost-user-scmi.c'))
-specific_virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_SCMI'], if_true: files('vhost-user-scmi-pci.c'))
+system_virtio_ss.add(when: 'CONFIG_VIRTIO_NSM', if_true: files('virtio-nsm.c'))
+system_virtio_ss.add(when: 'CONFIG_VIRTIO_NSM', if_true: [files('cbor-helpers.c'), libcbor])
+system_virtio_ss.add(when: 'CONFIG_VHOST_USER_SCMI', if_true: files('vhost-user-scmi.c'))
virtio_pci_ss = ss.source_set()
virtio_pci_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock-pci.c'))
@@ -67,6 +68,7 @@ virtio_pci_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk-
virtio_pci_ss.add(when: 'CONFIG_VHOST_USER_SCSI', if_true: files('vhost-user-scsi-pci.c'))
virtio_pci_ss.add(when: 'CONFIG_VHOST_SCSI', if_true: files('vhost-scsi-pci.c'))
virtio_pci_ss.add(when: 'CONFIG_VHOST_USER_FS', if_true: files('vhost-user-fs-pci.c'))
+virtio_pci_ss.add(when: 'CONFIG_VHOST_USER_SCMI', if_true: files('vhost-user-scmi-pci.c'))
virtio_pci_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('virtio-crypto-pci.c'))
virtio_pci_ss.add(when: 'CONFIG_VIRTIO_INPUT_HOST', if_true: files('virtio-input-host-pci.c'))
@@ -85,7 +87,7 @@ virtio_pci_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: files('virtio-mem-pci.c'))
virtio_pci_ss.add(when: 'CONFIG_VHOST_VDPA_DEV', if_true: files('vdpa-dev-pci.c'))
virtio_pci_ss.add(when: 'CONFIG_VIRTIO_MD', if_true: files('virtio-md-pci.c'))
-specific_virtio_ss.add_all(when: 'CONFIG_VIRTIO_PCI', if_true: virtio_pci_ss)
+system_virtio_ss.add_all(when: 'CONFIG_VIRTIO_PCI', if_true: virtio_pci_ss)
system_ss.add_all(when: 'CONFIG_VIRTIO', if_true: system_virtio_ss)
system_ss.add(when: 'CONFIG_VIRTIO', if_false: files('vhost-stub.c'))
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index fc43853..c30ea11 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -47,12 +47,6 @@ static struct vhost_log *vhost_log[VHOST_BACKEND_TYPE_MAX];
static struct vhost_log *vhost_log_shm[VHOST_BACKEND_TYPE_MAX];
static QLIST_HEAD(, vhost_dev) vhost_log_devs[VHOST_BACKEND_TYPE_MAX];
-/* Memslots used by backends that support private memslots (without an fd). */
-static unsigned int used_memslots;
-
-/* Memslots used by backends that only support shared memslots (with an fd). */
-static unsigned int used_shared_memslots;
-
static QLIST_HEAD(, vhost_dev) vhost_devices =
QLIST_HEAD_INITIALIZER(vhost_devices);
@@ -74,15 +68,15 @@ unsigned int vhost_get_free_memslots(void)
QLIST_FOREACH(hdev, &vhost_devices, entry) {
unsigned int r = hdev->vhost_ops->vhost_backend_memslots_limit(hdev);
- unsigned int cur_free;
+ unsigned int cur_free = r - hdev->mem->nregions;
- if (hdev->vhost_ops->vhost_backend_no_private_memslots &&
- hdev->vhost_ops->vhost_backend_no_private_memslots(hdev)) {
- cur_free = r - used_shared_memslots;
+ if (unlikely(r < hdev->mem->nregions)) {
+ warn_report_once("used (%u) vhost backend memory slots exceed"
+ " the device limit (%u).", hdev->mem->nregions, r);
+ free = 0;
} else {
- cur_free = r - used_memslots;
+ free = MIN(free, cur_free);
}
- free = MIN(free, cur_free);
}
return free;
}
@@ -666,13 +660,6 @@ static void vhost_commit(MemoryListener *listener)
dev->mem = g_realloc(dev->mem, regions_size);
dev->mem->nregions = dev->n_mem_sections;
- if (dev->vhost_ops->vhost_backend_no_private_memslots &&
- dev->vhost_ops->vhost_backend_no_private_memslots(dev)) {
- used_shared_memslots = dev->mem->nregions;
- } else {
- used_memslots = dev->mem->nregions;
- }
-
for (i = 0; i < dev->n_mem_sections; i++) {
struct vhost_memory_region *cur_vmr = dev->mem->regions + i;
struct MemoryRegionSection *mrs = dev->mem_sections + i;
@@ -1367,25 +1354,30 @@ fail_alloc_desc:
return r;
}
-int vhost_virtqueue_stop(struct vhost_dev *dev,
- struct VirtIODevice *vdev,
- struct vhost_virtqueue *vq,
- unsigned idx)
+static int do_vhost_virtqueue_stop(struct vhost_dev *dev,
+ struct VirtIODevice *vdev,
+ struct vhost_virtqueue *vq,
+ unsigned idx, bool force)
{
int vhost_vq_index = dev->vhost_ops->vhost_get_vq_index(dev, idx);
struct vhost_vring_state state = {
.index = vhost_vq_index,
};
- int r;
+ int r = 0;
if (virtio_queue_get_desc_addr(vdev, idx) == 0) {
/* Don't stop the virtqueue which might have not been started */
return 0;
}
- r = dev->vhost_ops->vhost_get_vring_base(dev, &state);
- if (r < 0) {
- VHOST_OPS_DEBUG(r, "vhost VQ %u ring restore failed: %d", idx, r);
+ if (!force) {
+ r = dev->vhost_ops->vhost_get_vring_base(dev, &state);
+ if (r < 0) {
+ VHOST_OPS_DEBUG(r, "vhost VQ %u ring restore failed: %d", idx, r);
+ }
+ }
+
+ if (r < 0 || force) {
/* Connection to the backend is broken, so let's sync internal
* last avail idx to the device used idx.
*/
@@ -1414,6 +1406,14 @@ int vhost_virtqueue_stop(struct vhost_dev *dev,
return r;
}
+int vhost_virtqueue_stop(struct vhost_dev *dev,
+ struct VirtIODevice *vdev,
+ struct vhost_virtqueue *vq,
+ unsigned idx)
+{
+ return do_vhost_virtqueue_stop(dev, vdev, vq, idx, false);
+}
+
static int vhost_virtqueue_set_busyloop_timeout(struct vhost_dev *dev,
int n, uint32_t timeout)
{
@@ -1619,15 +1619,11 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
QLIST_INSERT_HEAD(&vhost_devices, hdev, entry);
/*
- * The listener we registered properly updated the corresponding counter.
- * So we can trust that these values are accurate.
+ * The listener we registered properly setup the number of required
+ * memslots in vhost_commit().
*/
- if (hdev->vhost_ops->vhost_backend_no_private_memslots &&
- hdev->vhost_ops->vhost_backend_no_private_memslots(hdev)) {
- used = used_shared_memslots;
- } else {
- used = used_memslots;
- }
+ used = hdev->mem->nregions;
+
/*
* We assume that all reserved memslots actually require a real memslot
* in our vhost backend. This might not be true, for example, if the
@@ -2136,7 +2132,8 @@ fail_features:
}
/* Host notifiers must be enabled at this point. */
-int vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings)
+static int do_vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev,
+ bool vrings, bool force)
{
int i;
int rc = 0;
@@ -2158,10 +2155,11 @@ int vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings)
vhost_dev_set_vring_enable(hdev, false);
}
for (i = 0; i < hdev->nvqs; ++i) {
- rc |= vhost_virtqueue_stop(hdev,
- vdev,
- hdev->vqs + i,
- hdev->vq_index + i);
+ rc |= do_vhost_virtqueue_stop(hdev,
+ vdev,
+ hdev->vqs + i,
+ hdev->vq_index + i,
+ force);
}
if (hdev->vhost_ops->vhost_reset_status) {
hdev->vhost_ops->vhost_reset_status(hdev);
@@ -2181,6 +2179,17 @@ int vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings)
return rc;
}
+int vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings)
+{
+ return do_vhost_dev_stop(hdev, vdev, vrings, false);
+}
+
+int vhost_dev_force_stop(struct vhost_dev *hdev, VirtIODevice *vdev,
+ bool vrings)
+{
+ return do_vhost_dev_stop(hdev, vdev, vrings, true);
+}
+
int vhost_net_set_backend(struct vhost_dev *hdev,
struct vhost_vring_file *file)
{
diff --git a/hw/virtio/virtio-config-io.c b/hw/virtio/virtio-config-io.c
index ad78e0b..f58d90b 100644
--- a/hw/virtio/virtio-config-io.c
+++ b/hw/virtio/virtio-config-io.c
@@ -11,7 +11,6 @@
#include "qemu/osdep.h"
#include "hw/virtio/virtio.h"
-#include "cpu.h"
uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr)
{
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index fba2372..767216d 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -30,6 +30,7 @@
#include "qemu/error-report.h"
#include "qemu/log.h"
#include "qemu/module.h"
+#include "qemu/bswap.h"
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
#include "hw/loader.h"
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 7e38b1c..2ab1d20 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -20,7 +20,7 @@
#include "qemu/log.h"
#include "qemu/main-loop.h"
#include "qemu/module.h"
-#include "exec/tswap.h"
+#include "qemu/target-info.h"
#include "qom/object_interfaces.h"
#include "hw/core/cpu.h"
#include "hw/virtio/virtio.h"
diff --git a/hw/vmapple/virtio-blk.c b/hw/vmapple/virtio-blk.c
index 532b564..9de9aaa 100644
--- a/hw/vmapple/virtio-blk.c
+++ b/hw/vmapple/virtio-blk.c
@@ -19,7 +19,6 @@
#include "hw/vmapple/vmapple.h"
#include "hw/virtio/virtio-blk.h"
#include "hw/virtio/virtio-pci.h"
-#include "qemu/bswap.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "qapi/error.h"
diff --git a/include/system/accel-ops.h b/include/accel/accel-cpu-ops.h
index bf73835..0674764 100644
--- a/include/system/accel-ops.h
+++ b/include/accel/accel-cpu-ops.h
@@ -1,5 +1,5 @@
/*
- * Accelerator OPS, used for cpus.c module
+ * Accelerator per-vCPU handlers
*
* Copyright 2021 SUSE LLC
*
@@ -7,8 +7,8 @@
* See the COPYING file in the top-level directory.
*/
-#ifndef ACCEL_OPS_H
-#define ACCEL_OPS_H
+#ifndef QEMU_ACCEL_CPU_OPS_H
+#define QEMU_ACCEL_CPU_OPS_H
#include "qemu/accel.h"
#include "exec/vaddr.h"
@@ -65,6 +65,9 @@ struct AccelOpsClass {
/* handle_interrupt is mandatory. */
void (*handle_interrupt)(CPUState *cpu, int mask);
+ /* get_vcpu_stats: Append statistics of this @cpu to @buf */
+ void (*get_vcpu_stats)(CPUState *cpu, GString *buf);
+
/**
* @get_virtual_clock: fetch virtual clock
* @set_virtual_clock: set virtual clock
@@ -89,4 +92,4 @@ struct AccelOpsClass {
void generic_handle_interrupt(CPUState *cpu, int mask);
-#endif /* ACCEL_OPS_H */
+#endif /* QEMU_ACCEL_CPU_OPS_H */
diff --git a/include/accel/accel-ops.h b/include/accel/accel-ops.h
new file mode 100644
index 0000000..23a8c24
--- /dev/null
+++ b/include/accel/accel-ops.h
@@ -0,0 +1,51 @@
+/*
+ * Accelerator handlers
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef ACCEL_OPS_H
+#define ACCEL_OPS_H
+
+#include "exec/hwaddr.h"
+#include "qemu/accel.h"
+#include "qom/object.h"
+
+struct AccelState {
+ Object parent_obj;
+};
+
+struct AccelClass {
+ ObjectClass parent_class;
+
+ const char *name;
+ /* Cached by accel_init_ops_interfaces() when created */
+ AccelOpsClass *ops;
+
+ int (*init_machine)(AccelState *as, MachineState *ms);
+ bool (*cpu_common_realize)(CPUState *cpu, Error **errp);
+ void (*cpu_common_unrealize)(CPUState *cpu);
+ /* get_stats: Append statistics to @buf */
+ void (*get_stats)(AccelState *as, GString *buf);
+
+ /* system related hooks */
+ void (*setup_post)(AccelState *as);
+ void (*pre_resume_vm)(AccelState *as, bool step_pending);
+ bool (*has_memory)(AccelState *accel, AddressSpace *as,
+ hwaddr start_addr, hwaddr size);
+
+ /* gdbstub related hooks */
+ int (*gdbstub_supported_sstep_flags)(AccelState *as);
+
+ bool *allowed;
+ /*
+ * Array of global properties that would be applied when specific
+ * accelerator is chosen. It works like MachineClass.compat_props
+ * but it's for accelerators not machines. Accelerator-provided
+ * global properties may be overridden by machine-type
+ * compat_props or user-provided global properties.
+ */
+ GPtrArray *compat_props;
+};
+
+#endif /* ACCEL_OPS_H */
diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h
index 84a2a4e..62da83c 100644
--- a/include/block/block-global-state.h
+++ b/include/block/block-global-state.h
@@ -74,13 +74,14 @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
int GRAPH_WRLOCK
bdrv_replace_node(BlockDriverState *from, BlockDriverState *to, Error **errp);
-int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs,
- Error **errp);
-BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *node_options,
- int flags, Error **errp);
+int GRAPH_UNLOCKED
+bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs, Error **errp);
+BlockDriverState * GRAPH_UNLOCKED
+bdrv_insert_node(BlockDriverState *bs, QDict *node_options, int flags,
+ Error **errp);
int bdrv_drop_filter(BlockDriverState *bs, Error **errp);
-BdrvChild * no_coroutine_fn
+BdrvChild * no_coroutine_fn GRAPH_UNLOCKED
bdrv_open_child(const char *filename, QDict *options, const char *bdref_key,
BlockDriverState *parent, const BdrvChildClass *child_class,
BdrvChildRole child_role, bool allow_none, Error **errp);
@@ -90,9 +91,10 @@ bdrv_co_open_child(const char *filename, QDict *options, const char *bdref_key,
BlockDriverState *parent, const BdrvChildClass *child_class,
BdrvChildRole child_role, bool allow_none, Error **errp);
-int bdrv_open_file_child(const char *filename,
- QDict *options, const char *bdref_key,
- BlockDriverState *parent, Error **errp);
+int GRAPH_UNLOCKED
+bdrv_open_file_child(const char *filename, QDict *options,
+ const char *bdref_key, BlockDriverState *parent,
+ Error **errp);
BlockDriverState * no_coroutine_fn
bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp);
@@ -100,11 +102,9 @@ bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp);
BlockDriverState * coroutine_fn no_co_wrapper
bdrv_co_open_blockdev_ref(BlockdevRef *ref, Error **errp);
-int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
- Error **errp);
int GRAPH_WRLOCK
-bdrv_set_backing_hd_drained(BlockDriverState *bs, BlockDriverState *backing_hd,
- Error **errp);
+bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
+ Error **errp);
int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
const char *bdref_key, Error **errp);
@@ -123,11 +123,12 @@ BlockDriverState *bdrv_new_open_driver_opts(BlockDriver *drv,
Error **errp);
BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name,
int flags, Error **errp);
-BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
- BlockDriverState *bs, QDict *options,
- bool keep_old_opts);
+BlockReopenQueue * GRAPH_UNLOCKED
+bdrv_reopen_queue(BlockReopenQueue *bs_queue, BlockDriverState *bs,
+ QDict *options, bool keep_old_opts);
void bdrv_reopen_queue_free(BlockReopenQueue *bs_queue);
-int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp);
+int GRAPH_UNLOCKED
+bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp);
int bdrv_reopen(BlockDriverState *bs, QDict *opts, bool keep_old_opts,
Error **errp);
int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
@@ -143,9 +144,10 @@ int bdrv_commit(BlockDriverState *bs);
int GRAPH_RDLOCK bdrv_make_empty(BdrvChild *c, Error **errp);
void bdrv_register(BlockDriver *bdrv);
-int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
- const char *backing_file_str,
- bool backing_mask_protocol);
+int GRAPH_UNLOCKED
+bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
+ const char *backing_file_str,
+ bool backing_mask_protocol);
BlockDriverState * GRAPH_RDLOCK
bdrv_find_overlay(BlockDriverState *active, BlockDriverState *bs);
@@ -184,14 +186,14 @@ bdrv_activate(BlockDriverState *bs, Error **errp);
int coroutine_fn no_co_wrapper_bdrv_rdlock
bdrv_co_activate(BlockDriverState *bs, Error **errp);
-int no_coroutine_fn
+int no_coroutine_fn GRAPH_RDLOCK
bdrv_inactivate(BlockDriverState *bs, Error **errp);
void bdrv_activate_all(Error **errp);
-int bdrv_inactivate_all(void);
+int GRAPH_UNLOCKED bdrv_inactivate_all(void);
int bdrv_flush_all(void);
-void bdrv_close_all(void);
+void GRAPH_UNLOCKED bdrv_close_all(void);
void GRAPH_UNLOCKED bdrv_drain_all_begin(void);
void bdrv_drain_all_begin_nopoll(void);
void bdrv_drain_all_end(void);
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
index 925a3e7..034c063 100644
--- a/include/block/block_int-common.h
+++ b/include/block/block_int-common.h
@@ -248,7 +248,7 @@ struct BlockDriver {
int GRAPH_UNLOCKED_PTR (*bdrv_open)(
BlockDriverState *bs, QDict *options, int flags, Error **errp);
- void (*bdrv_close)(BlockDriverState *bs);
+ void GRAPH_UNLOCKED_PTR (*bdrv_close)(BlockDriverState *bs);
int coroutine_fn GRAPH_UNLOCKED_PTR (*bdrv_co_create)(
BlockdevCreateOptions *opts, Error **errp);
@@ -1253,7 +1253,7 @@ struct BlockDriverState {
/* do we need to tell the quest if we have a volatile write cache? */
int enable_write_cache;
- /* Accessed with atomic ops. */
+ /* Accessed only in the main thread. */
int quiesce_counter;
unsigned int write_gen; /* Current data generation */
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
index 990f3e1..85284cb 100644
--- a/include/block/blockjob.h
+++ b/include/block/blockjob.h
@@ -151,7 +151,7 @@ block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs,
* Remove all BlockDriverStates from the list of nodes that are involved in the
* job. This removes the blockers added with block_job_add_bdrv().
*/
-void block_job_remove_all_bdrv(BlockJob *job);
+void GRAPH_UNLOCKED block_job_remove_all_bdrv(BlockJob *job);
/**
* block_job_has_bdrv:
diff --git a/include/block/graph-lock.h b/include/block/graph-lock.h
index 2c26c72..95bf5ed 100644
--- a/include/block/graph-lock.h
+++ b/include/block/graph-lock.h
@@ -113,9 +113,20 @@ void no_coroutine_fn TSA_ACQUIRE(graph_lock) TSA_NO_TSA
bdrv_graph_wrlock(void);
/*
+ * bdrv_graph_wrlock_drained:
+ * Similar to bdrv_graph_wrlock, but will begin a drained section before
+ * locking.
+ */
+void no_coroutine_fn TSA_ACQUIRE(graph_lock) TSA_NO_TSA
+bdrv_graph_wrlock_drained(void);
+
+/*
* bdrv_graph_wrunlock:
* Write finished, reset global has_writer to 0 and restart
* all readers that are waiting.
+ *
+ * Also ends the drained section if bdrv_graph_wrlock_drained() was used to lock
+ * the graph.
*/
void no_coroutine_fn TSA_RELEASE(graph_lock) TSA_NO_TSA
bdrv_graph_wrunlock(void);
diff --git a/include/block/snapshot.h b/include/block/snapshot.h
index 304cc6e..2316a43 100644
--- a/include/block/snapshot.h
+++ b/include/block/snapshot.h
@@ -90,9 +90,9 @@ int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs,
bool bdrv_all_can_snapshot(bool has_devices, strList *devices,
Error **errp);
-int bdrv_all_delete_snapshot(const char *name,
- bool has_devices, strList *devices,
- Error **errp);
+int GRAPH_UNLOCKED
+bdrv_all_delete_snapshot(const char *name, bool has_devices, strList *devices,
+ Error **errp);
int bdrv_all_goto_snapshot(const char *name,
bool has_devices, strList *devices,
Error **errp);
diff --git a/include/exec/memattrs.h b/include/exec/memattrs.h
index 8db1d30..52ee955 100644
--- a/include/exec/memattrs.h
+++ b/include/exec/memattrs.h
@@ -54,6 +54,9 @@ typedef struct MemTxAttrs {
*/
unsigned int pid:8;
+ /* PCI - IOMMU operations, see PCIAddressType */
+ unsigned int address_type:1;
+
/*
* Bus masters which don't specify any attributes will get this
* (via the MEMTXATTRS_UNSPECIFIED constant), so that we can
diff --git a/include/exec/tswap.h b/include/exec/tswap.h
index 49511f2..72219e2 100644
--- a/include/exec/tswap.h
+++ b/include/exec/tswap.h
@@ -9,18 +9,7 @@
#define TSWAP_H
#include "qemu/bswap.h"
-
-/**
- * target_big_endian:
- * Returns true if the (default) endianness of the target is big endian,
- * false otherwise. Common code should normally never need to know about the
- * endianness of the target, so please do *not* use this function unless you
- * know very well what you are doing!
- */
-bool target_big_endian(void);
-#ifdef COMPILING_PER_TARGET
-#define target_big_endian() TARGET_BIG_ENDIAN
-#endif
+#include "qemu/target-info.h"
/*
* If we're in target-specific code, we can hard-code the swapping
@@ -80,74 +69,4 @@ static inline void tswap64s(uint64_t *s)
}
}
-/* Return ld{word}_{le,be}_p following target endianness. */
-#define LOAD_IMPL(word, args...) \
-do { \
- if (target_big_endian()) { \
- return glue(glue(ld, word), _be_p)(args); \
- } else { \
- return glue(glue(ld, word), _le_p)(args); \
- } \
-} while (0)
-
-static inline int lduw_p(const void *ptr)
-{
- LOAD_IMPL(uw, ptr);
-}
-
-static inline int ldsw_p(const void *ptr)
-{
- LOAD_IMPL(sw, ptr);
-}
-
-static inline int ldl_p(const void *ptr)
-{
- LOAD_IMPL(l, ptr);
-}
-
-static inline uint64_t ldq_p(const void *ptr)
-{
- LOAD_IMPL(q, ptr);
-}
-
-static inline uint64_t ldn_p(const void *ptr, int sz)
-{
- LOAD_IMPL(n, ptr, sz);
-}
-
-#undef LOAD_IMPL
-
-/* Call st{word}_{le,be}_p following target endianness. */
-#define STORE_IMPL(word, args...) \
-do { \
- if (target_big_endian()) { \
- glue(glue(st, word), _be_p)(args); \
- } else { \
- glue(glue(st, word), _le_p)(args); \
- } \
-} while (0)
-
-
-static inline void stw_p(void *ptr, uint16_t v)
-{
- STORE_IMPL(w, ptr, v);
-}
-
-static inline void stl_p(void *ptr, uint32_t v)
-{
- STORE_IMPL(l, ptr, v);
-}
-
-static inline void stq_p(void *ptr, uint64_t v)
-{
- STORE_IMPL(q, ptr, v);
-}
-
-static inline void stn_p(void *ptr, int sz, uint64_t v)
-{
- STORE_IMPL(n, ptr, sz, v);
-}
-
-#undef STORE_IMPL
-
#endif /* TSWAP_H */
diff --git a/include/gdbstub/helpers.h b/include/gdbstub/helpers.h
index 6f7cc48..b685afa 100644
--- a/include/gdbstub/helpers.h
+++ b/include/gdbstub/helpers.h
@@ -16,7 +16,8 @@
#error "gdbstub helpers should only be included by target specific code"
#endif
-#include "exec/tswap.h"
+#include "qemu/bswap.h"
+#include "qemu/target-info.h"
#include "cpu-param.h"
/*
@@ -33,40 +34,49 @@ static inline int gdb_get_reg8(GByteArray *buf, uint8_t val)
static inline int gdb_get_reg16(GByteArray *buf, uint16_t val)
{
- uint16_t to_word = tswap16(val);
- g_byte_array_append(buf, (uint8_t *) &to_word, 2);
+ if (target_big_endian()) {
+ cpu_to_be16s(&val);
+ } else {
+ cpu_to_le16s(&val);
+ }
+ g_byte_array_append(buf, (uint8_t *) &val, 2);
return 2;
}
static inline int gdb_get_reg32(GByteArray *buf, uint32_t val)
{
- uint32_t to_long = tswap32(val);
- g_byte_array_append(buf, (uint8_t *) &to_long, 4);
+ if (target_big_endian()) {
+ cpu_to_be32s(&val);
+ } else {
+ cpu_to_le32s(&val);
+ }
+ g_byte_array_append(buf, (uint8_t *) &val, 4);
return 4;
}
static inline int gdb_get_reg64(GByteArray *buf, uint64_t val)
{
- uint64_t to_quad = tswap64(val);
- g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
+ if (target_big_endian()) {
+ cpu_to_be64s(&val);
+ } else {
+ cpu_to_le64s(&val);
+ }
+ g_byte_array_append(buf, (uint8_t *) &val, 8);
return 8;
}
static inline int gdb_get_reg128(GByteArray *buf, uint64_t val_hi,
uint64_t val_lo)
{
- uint64_t to_quad;
-#if TARGET_BIG_ENDIAN
- to_quad = tswap64(val_hi);
- g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
- to_quad = tswap64(val_lo);
- g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
-#else
- to_quad = tswap64(val_lo);
- g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
- to_quad = tswap64(val_hi);
- g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
-#endif
+ uint64_t tmp[2];
+ if (target_big_endian()) {
+ tmp[0] = cpu_to_be64(val_hi);
+ tmp[1] = cpu_to_be64(val_lo);
+ } else {
+ tmp[0] = cpu_to_le64(val_lo);
+ tmp[1] = cpu_to_le64(val_hi);
+ }
+ g_byte_array_append(buf, (uint8_t *)&tmp, 16);
return 16;
}
diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h
index d2dac87..2c5b055 100644
--- a/include/hw/acpi/generic_event_device.h
+++ b/include/hw/acpi/generic_event_device.h
@@ -63,12 +63,13 @@
#include "hw/acpi/memory_hotplug.h"
#include "hw/acpi/ghes.h"
#include "hw/acpi/cpu.h"
+#include "hw/acpi/pcihp.h"
#include "qom/object.h"
#define ACPI_POWER_BUTTON_DEVICE "PWRB"
#define TYPE_ACPI_GED "acpi-ged"
-OBJECT_DECLARE_SIMPLE_TYPE(AcpiGedState, ACPI_GED)
+OBJECT_DECLARE_TYPE(AcpiGedState, AcpiGedClass, ACPI_GED)
#define ACPI_GED_EVT_SEL_OFFSET 0x0
#define ACPI_GED_EVT_SEL_LEN 0x4
@@ -101,6 +102,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(AcpiGedState, ACPI_GED)
#define ACPI_GED_PWR_DOWN_EVT 0x2
#define ACPI_GED_NVDIMM_HOTPLUG_EVT 0x4
#define ACPI_GED_CPU_HOTPLUG_EVT 0x8
+#define ACPI_GED_PCI_HOTPLUG_EVT 0x10
typedef struct GEDState {
MemoryRegion evt;
@@ -108,18 +110,31 @@ typedef struct GEDState {
uint32_t sel;
} GEDState;
+#define ACPI_PCIHP_REGION_NAME "pcihp container"
+#define ACPI_MEMHP_REGION_NAME "memhp container"
+
struct AcpiGedState {
SysBusDevice parent_obj;
MemHotplugState memhp_state;
MemoryRegion container_memhp;
CPUHotplugState cpuhp_state;
MemoryRegion container_cpuhp;
+ AcpiPciHpState pcihp_state;
+ MemoryRegion container_pcihp;
GEDState ged_state;
uint32_t ged_event_bitmap;
qemu_irq irq;
AcpiGhesState ghes_state;
};
+typedef struct AcpiGedClass {
+ /* <private> */
+ SysBusDeviceClass parent_class;
+
+ /*< public >*/
+ ResettablePhases parent_phases;
+} AcpiGedClass;
+
void build_ged_aml(Aml *table, const char* name, HotplugHandler *hotplug_dev,
uint32_t ged_irq, AmlRegionSpace rs, hwaddr ged_base);
void acpi_dsdt_add_power_button(Aml *scope);
diff --git a/include/hw/acpi/pci.h b/include/hw/acpi/pci.h
index 6359d57..20b6725 100644
--- a/include/hw/acpi/pci.h
+++ b/include/hw/acpi/pci.h
@@ -36,11 +36,12 @@ typedef struct AcpiMcfgInfo {
void build_mcfg(GArray *table_data, BIOSLinker *linker, AcpiMcfgInfo *info,
const char *oem_id, const char *oem_table_id);
-Aml *aml_pci_device_dsm(void);
-void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus);
void build_pci_bridge_aml(AcpiDevAmlIf *adev, Aml *scope);
void build_srat_generic_affinity_structures(GArray *table_data);
+Aml *build_pci_host_bridge_osc_method(bool enable_native_pcie_hotplug);
+Aml *build_pci_bridge_edsm(void);
+
#endif
diff --git a/include/hw/acpi/pcihp.h b/include/hw/acpi/pcihp.h
index cdc0cb8..ca6a258 100644
--- a/include/hw/acpi/pcihp.h
+++ b/include/hw/acpi/pcihp.h
@@ -28,11 +28,18 @@
#define HW_ACPI_PCIHP_H
#include "hw/acpi/acpi.h"
+#include "hw/acpi/aml-build.h"
#include "hw/hotplug.h"
#define ACPI_PCIHP_IO_BASE_PROP "acpi-pcihp-io-base"
#define ACPI_PCIHP_IO_LEN_PROP "acpi-pcihp-io-len"
+/* PCI Hot-plug registers bases. See docs/specs/acpi_pci_hotplug.rst */
+#define ACPI_PCIHP_SEJ_BASE 0x8
+#define ACPI_PCIHP_BNMR_BASE 0x10
+
+#define ACPI_PCIHP_SIZE 0x0018
+
typedef struct AcpiPciHpPciStatus {
uint32_t up;
uint32_t down;
@@ -55,7 +62,7 @@ typedef struct AcpiPciHpState {
bool use_acpi_root_pci_hotplug;
} AcpiPciHpState;
-void acpi_pcihp_init(Object *owner, AcpiPciHpState *, PCIBus *root,
+void acpi_pcihp_init(Object *owner, AcpiPciHpState *,
MemoryRegion *io, uint16_t io_base);
bool acpi_pcihp_is_hotpluggable_bus(AcpiPciHpState *s, BusState *bus);
@@ -69,6 +76,14 @@ void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev,
AcpiPciHpState *s, DeviceState *dev,
Error **errp);
+void build_acpi_pci_hotplug(Aml *table, AmlRegionSpace rs, uint64_t pcihp_addr);
+void build_append_pci_dsm_func0_common(Aml *ctx, Aml *retvar);
+void build_append_pcihp_resources(Aml *table,
+ uint64_t io_addr, uint64_t io_len);
+bool build_append_notification_callback(Aml *parent_scope, const PCIBus *bus);
+
+void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus);
+
/* Called on reset */
void acpi_pcihp_reset(AcpiPciHpState *s);
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 4375819..365a28b 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -80,6 +80,7 @@ enum {
VIRT_ACPI_GED,
VIRT_NVDIMM_ACPI,
VIRT_PVTIME,
+ VIRT_ACPI_PCIHP,
VIRT_LOWMEMMAP_LAST,
};
diff --git a/include/hw/arm/xen_arch_hvm.h b/include/hw/arm/xen_arch_hvm.h
deleted file mode 100644
index 8fd645e..0000000
--- a/include/hw/arm/xen_arch_hvm.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef HW_XEN_ARCH_ARM_HVM_H
-#define HW_XEN_ARCH_ARM_HVM_H
-
-#include <xen/hvm/ioreq.h>
-void arch_handle_ioreq(XenIOState *state, ioreq_t *req);
-void arch_xen_set_memory(XenIOState *state,
- MemoryRegionSection *section,
- bool add);
-#endif
diff --git a/include/hw/boards.h b/include/hw/boards.h
index f424b2b..f94713e 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -443,6 +443,7 @@ struct MachineState {
SmpCache smp_cache;
struct NVDIMMState *nvdimms_state;
struct NumaState *numa_state;
+ bool acpi_spcr_enabled;
};
/*
diff --git a/include/hw/cxl/cxl.h b/include/hw/cxl/cxl.h
index de66ab8..998f495 100644
--- a/include/hw/cxl/cxl.h
+++ b/include/hw/cxl/cxl.h
@@ -23,6 +23,7 @@
#define CXL_DEVICE_REG_BAR_IDX 2
#define CXL_WINDOW_MAX 10
+#define CXL_NUM_EXTENTS_SUPPORTED 512
typedef struct PXBCXLDev PXBCXLDev;
diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h
index ed6cd50..89411c8 100644
--- a/include/hw/cxl/cxl_device.h
+++ b/include/hw/cxl/cxl_device.h
@@ -133,6 +133,15 @@ typedef enum {
CXL_MBOX_MAX = 0x20
} CXLRetCode;
+/* r3.2 Section 7.6.7.6.2: Table 7-66: DSMAS Flags Bits */
+typedef enum {
+ CXL_DSMAS_FLAGS_NONVOLATILE = 2,
+ CXL_DSMAS_FLAGS_SHARABLE = 3,
+ CXL_DSMAS_FLAGS_HW_MANAGED_COHERENCY = 4,
+ CXL_DSMAS_FLAGS_IC_SPECIFIC_DC_MANAGEMENT = 5,
+ CXL_DSMAS_FLAGS_RDONLY = 6,
+} CXLDSMASFlags;
+
typedef struct CXLCCI CXLCCI;
typedef struct cxl_device_state CXLDeviceState;
struct cxl_cmd;
@@ -530,6 +539,14 @@ typedef struct CXLDCRegion {
uint32_t dsmadhandle;
uint8_t flags;
unsigned long *blk_bitmap;
+ uint64_t supported_blk_size_bitmask;
+ QemuMutex bitmap_lock;
+ /* Following bools make up dsmas flags, as defined in the CDAT */
+ bool nonvolatile;
+ bool sharable;
+ bool hw_managed_coherency;
+ bool ic_specific_dc_management;
+ bool rdonly;
} CXLDCRegion;
typedef struct CXLSetFeatureInfo {
@@ -618,6 +635,7 @@ struct CXLType3Dev {
CXLDCExtentList extents;
CXLDCExtentGroupList extents_pending;
uint32_t total_extent_count;
+ uint32_t nr_extents_accepted;
uint32_t ext_list_gen_seq;
uint8_t num_regions; /* 0-8 regions */
@@ -696,11 +714,22 @@ CXLDCExtentGroup *cxl_insert_extent_to_extent_group(CXLDCExtentGroup *group,
uint16_t shared_seq);
void cxl_extent_group_list_insert_tail(CXLDCExtentGroupList *list,
CXLDCExtentGroup *group);
-void cxl_extent_group_list_delete_front(CXLDCExtentGroupList *list);
+uint32_t cxl_extent_group_list_delete_front(CXLDCExtentGroupList *list);
void ct3_set_region_block_backed(CXLType3Dev *ct3d, uint64_t dpa,
uint64_t len);
void ct3_clear_region_block_backed(CXLType3Dev *ct3d, uint64_t dpa,
uint64_t len);
bool ct3_test_region_block_backed(CXLType3Dev *ct3d, uint64_t dpa,
uint64_t len);
+void cxl_assign_event_header(CXLEventRecordHdr *hdr,
+ const QemuUUID *uuid, uint32_t flags,
+ uint8_t length, uint64_t timestamp);
+void cxl_create_dc_event_records_for_extents(CXLType3Dev *ct3d,
+ CXLDCEventType type,
+ CXLDCExtentRaw extents[],
+ uint32_t ext_count);
+bool cxl_extents_overlaps_dpa_range(CXLDCExtentList *list,
+ uint64_t dpa, uint64_t len);
+bool cxl_extent_groups_overlaps_dpa_range(CXLDCExtentGroupList *list,
+ uint64_t dpa, uint64_t len);
#endif
diff --git a/include/hw/cxl/cxl_events.h b/include/hw/cxl/cxl_events.h
index 38cadaa..758b075 100644
--- a/include/hw/cxl/cxl_events.h
+++ b/include/hw/cxl/cxl_events.h
@@ -184,4 +184,19 @@ typedef struct CXLEventDynamicCapacity {
uint32_t tags_avail;
} QEMU_PACKED CXLEventDynamicCapacity;
+/* CXL r3.1 Table 8-50: Dynamic Capacity Event Record */
+static const QemuUUID dynamic_capacity_uuid = {
+ .data = UUID(0xca95afa7, 0xf183, 0x4018, 0x8c, 0x2f,
+ 0x95, 0x26, 0x8e, 0x10, 0x1a, 0x2a),
+};
+
+typedef enum CXLDCEventType {
+ DC_EVENT_ADD_CAPACITY = 0x0,
+ DC_EVENT_RELEASE_CAPACITY = 0x1,
+ DC_EVENT_FORCED_RELEASE_CAPACITY = 0x2,
+ DC_EVENT_REGION_CONFIG_UPDATED = 0x3,
+ DC_EVENT_ADD_CAPACITY_RSP = 0x4,
+ DC_EVENT_CAPACITY_RELEASED = 0x5,
+} CXLDCEventType;
+
#endif /* CXL_EVENTS_H */
diff --git a/include/hw/cxl/cxl_mailbox.h b/include/hw/cxl/cxl_mailbox.h
index 9008402..a05d7cb 100644
--- a/include/hw/cxl/cxl_mailbox.h
+++ b/include/hw/cxl/cxl_mailbox.h
@@ -8,6 +8,7 @@
#ifndef CXL_MAILBOX_H
#define CXL_MAILBOX_H
+#define CXL_MBOX_CONFIG_CHANGE_COLD_RESET (1)
#define CXL_MBOX_IMMEDIATE_CONFIG_CHANGE (1 << 1)
#define CXL_MBOX_IMMEDIATE_DATA_CHANGE (1 << 2)
#define CXL_MBOX_IMMEDIATE_POLICY_CHANGE (1 << 3)
@@ -15,5 +16,10 @@
#define CXL_MBOX_SECURITY_STATE_CHANGE (1 << 5)
#define CXL_MBOX_BACKGROUND_OPERATION (1 << 6)
#define CXL_MBOX_BACKGROUND_OPERATION_ABORT (1 << 7)
+#define CXL_MBOX_SECONDARY_MBOX_SUPPORTED (1 << 8)
+#define CXL_MBOX_REQUEST_ABORT_BACKGROUND_OP_SUPPORTED (1 << 9)
+#define CXL_MBOX_CEL_10_TO_11_VALID (1 << 10)
+#define CXL_MBOX_CONFIG_CHANGE_CONV_RESET (1 << 11)
+#define CXL_MBOX_CONFIG_CHANGE_CXL_RESET (1 << 12)
#endif
diff --git a/include/hw/display/edid.h b/include/hw/display/edid.h
index 520f8ec..91c0a42 100644
--- a/include/hw/display/edid.h
+++ b/include/hw/display/edid.h
@@ -1,6 +1,8 @@
#ifndef EDID_H
#define EDID_H
+#define EDID_NAME_MAX_LENGTH 12
+
typedef struct qemu_edid_info {
const char *vendor; /* http://www.uefi.org/pnp_id_list */
const char *name;
diff --git a/include/hw/i386/xen_arch_hvm.h b/include/hw/i386/xen_arch_hvm.h
deleted file mode 100644
index 1000f8f..0000000
--- a/include/hw/i386/xen_arch_hvm.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef HW_XEN_ARCH_I386_HVM_H
-#define HW_XEN_ARCH_I386_HVM_H
-
-#include <xen/hvm/ioreq.h>
-#include "hw/xen/xen-hvm-common.h"
-
-void arch_handle_ioreq(XenIOState *state, ioreq_t *req);
-void arch_xen_set_memory(XenIOState *state,
- MemoryRegionSection *section,
- bool add);
-#endif
diff --git a/include/hw/pci-host/gpex.h b/include/hw/pci-host/gpex.h
index 8447153..feaf827 100644
--- a/include/hw/pci-host/gpex.h
+++ b/include/hw/pci-host/gpex.h
@@ -45,6 +45,7 @@ struct GPEXConfig {
MemMapEntry pio;
int irq;
PCIBus *bus;
+ bool pci_native_hotplug;
};
typedef struct GPEXIrq GPEXIrq;
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index df3cc7b..6b7d3ac 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -134,6 +134,15 @@ struct PCIHostDeviceAddress {
unsigned int function;
};
+/*
+ * Represents the Address Type (AT) field in a PCI request,
+ * see MemTxAttrs.address_type
+ */
+typedef enum PCIAddressType {
+ PCI_AT_UNTRANSLATED = 0, /* Default when no attribute is set */
+ PCI_AT_TRANSLATED = 1,
+} PCIAddressType;
+
typedef void PCIConfigWriteFunc(PCIDevice *pci_dev,
uint32_t address, uint32_t data, int len);
typedef uint32_t PCIConfigReadFunc(PCIDevice *pci_dev,
diff --git a/include/hw/qdev-properties-system.h b/include/hw/qdev-properties-system.h
index b921392..9601a11 100644
--- a/include/hw/qdev-properties-system.h
+++ b/include/hw/qdev-properties-system.h
@@ -32,6 +32,7 @@ extern const PropertyInfo qdev_prop_cpus390entitlement;
extern const PropertyInfo qdev_prop_iothread_vq_mapping_list;
extern const PropertyInfo qdev_prop_endian_mode;
extern const PropertyInfo qdev_prop_vmapple_virtio_blk_variant;
+extern const PropertyInfo qdev_prop_virtio_gpu_output_list;
#define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d) \
DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_pci_devfn, int32_t)
@@ -110,4 +111,8 @@ extern const PropertyInfo qdev_prop_vmapple_virtio_blk_variant;
qdev_prop_vmapple_virtio_blk_variant, \
VMAppleVirtioBlkVariant)
+#define DEFINE_PROP_VIRTIO_GPU_OUTPUT_LIST(_name, _state, _field) \
+ DEFINE_PROP(_name, _state, _field, qdev_prop_virtio_gpu_output_list, \
+ VirtIOGPUOutputList *)
+
#endif
diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
index 2c99856..0197aa4 100644
--- a/include/hw/qdev-properties.h
+++ b/include/hw/qdev-properties.h
@@ -43,11 +43,22 @@ struct PropertyInfo {
ObjectPropertyRelease *release;
};
+/**
+ * struct OnOffAutoBit64 - OnOffAuto storage with 64 elements.
+ * @on_bits: Bitmap of elements with "on".
+ * @auto_bits: Bitmap of elements with "auto".
+ */
+typedef struct OnOffAutoBit64 {
+ uint64_t on_bits;
+ uint64_t auto_bits;
+} OnOffAutoBit64;
+
/*** qdev-properties.c ***/
extern const PropertyInfo qdev_prop_bit;
extern const PropertyInfo qdev_prop_bit64;
+extern const PropertyInfo qdev_prop_on_off_auto_bit64;
extern const PropertyInfo qdev_prop_bool;
extern const PropertyInfo qdev_prop_uint8;
extern const PropertyInfo qdev_prop_uint16;
@@ -100,6 +111,13 @@ extern const PropertyInfo qdev_prop_link;
.set_default = true, \
.defval.u = (bool)_defval)
+#define DEFINE_PROP_ON_OFF_AUTO_BIT64(_name, _state, _field, _bit, _defval) \
+ DEFINE_PROP(_name, _state, _field, qdev_prop_on_off_auto_bit64, \
+ OnOffAutoBit64, \
+ .bitnr = (_bit), \
+ .set_default = true, \
+ .defval.i = (OnOffAuto)_defval)
+
#define DEFINE_PROP_BOOL(_name, _state, _field, _defval) \
DEFINE_PROP(_name, _state, _field, qdev_prop_bool, bool, \
.set_default = true, \
diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
index 533d856..3526bad 100644
--- a/include/hw/scsi/esp.h
+++ b/include/hw/scsi/esp.h
@@ -14,7 +14,11 @@ typedef void (*ESPDMAMemoryReadWriteFunc)(void *opaque, uint8_t *buf, int len);
#define ESP_FIFO_SZ 16
#define ESP_CMDFIFO_SZ 32
-typedef struct ESPState ESPState;
+enum ESPASCMode {
+ ESP_ASC_MODE_DIS = 0, /* Disconnected */
+ ESP_ASC_MODE_INI = 1, /* Initiator */
+ ESP_ASC_MODE_TGT = 2 /* Target */
+};
#define TYPE_ESP "esp"
OBJECT_DECLARE_SIMPLE_TYPE(ESPState, ESP)
@@ -40,6 +44,7 @@ struct ESPState {
uint8_t cmdfifo_cdb_offset;
uint8_t lun;
uint32_t do_cmd;
+ uint8_t asc_mode;
bool data_ready;
int dma_enabled;
@@ -106,6 +111,13 @@ struct SysBusESPState {
#define CMD_DMA 0x80
#define CMD_CMD 0x7f
+#define CMD_GRP_MASK 0x70
+
+#define CMD_GRP_MISC 0x00
+#define CMD_GRP_INIT 0x01
+#define CMD_GRP_TRGT 0x02
+#define CMD_GRP_DISC 0x04
+
#define CMD_NOP 0x00
#define CMD_FLUSH 0x01
#define CMD_RESET 0x02
@@ -140,6 +152,7 @@ struct SysBusESPState {
#define INTR_FC 0x08
#define INTR_BS 0x10
#define INTR_DC 0x20
+#define INTR_IL 0x40
#define INTR_RST 0x80
#define SEQ_0 0x0
diff --git a/include/hw/sysbus.h b/include/hw/sysbus.h
index 7dc88aa..18fde8a 100644
--- a/include/hw/sysbus.h
+++ b/include/hw/sysbus.h
@@ -82,6 +82,7 @@ void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq);
bool sysbus_is_irq_connected(SysBusDevice *dev, int n);
qemu_irq sysbus_get_connected_irq(SysBusDevice *dev, int n);
void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr);
+int sysbus_mmio_map_name(SysBusDevice *dev, const char*name, hwaddr addr);
void sysbus_mmio_map_overlap(SysBusDevice *dev, int n, hwaddr addr,
int priority);
diff --git a/include/hw/vfio/vfio-device.h b/include/hw/vfio/vfio-device.h
index 1901a35..6e4d5cc 100644
--- a/include/hw/vfio/vfio-device.h
+++ b/include/hw/vfio/vfio-device.h
@@ -67,6 +67,8 @@ typedef struct VFIODevice {
bool ram_block_discard_allowed;
OnOffAuto enable_migration;
OnOffAuto migration_multifd_transfer;
+ OnOffAuto migration_load_config_after_iter;
+ uint64_t migration_max_queued_buffers_size;
bool migration_events;
bool use_region_fds;
VFIODeviceOps *ops;
diff --git a/include/hw/virtio/vhost-user-blk.h b/include/hw/virtio/vhost-user-blk.h
index ea085ee..a10f785 100644
--- a/include/hw/virtio/vhost-user-blk.h
+++ b/include/hw/virtio/vhost-user-blk.h
@@ -50,6 +50,8 @@ struct VHostUserBlk {
bool connected;
/* vhost_user_blk_start/vhost_user_blk_stop */
bool started_vu;
+
+ bool skip_get_vring_base_on_force_shutdown;
};
#endif
diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h
index f178cf9..66be6af 100644
--- a/include/hw/virtio/vhost.h
+++ b/include/hw/virtio/vhost.h
@@ -243,6 +243,21 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings);
int vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings);
/**
+ * vhost_dev_force_stop() - force stop the vhost device
+ * @hdev: common vhost_dev structure
+ * @vdev: the VirtIODevice structure
+ * @vrings: true to have vrings disabled in this call
+ *
+ * Force stop the vhost device. After the device is stopped the notifiers
+ * can be disabled (@vhost_dev_disable_notifiers) and the device can
+ * be torn down (@vhost_dev_cleanup). Unlike @vhost_dev_stop, this doesn't
+ * attempt to flush in-flight backend requests by skipping GET_VRING_BASE
+ * entirely.
+ */
+int vhost_dev_force_stop(struct vhost_dev *hdev, VirtIODevice *vdev,
+ bool vrings);
+
+/**
* DOC: vhost device configuration handling
*
* The VirtIO device configuration space is used for rarely changing
diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h
index a42957c..9f16f89 100644
--- a/include/hw/virtio/virtio-gpu.h
+++ b/include/hw/virtio/virtio-gpu.h
@@ -20,6 +20,7 @@
#include "hw/virtio/virtio.h"
#include "qemu/log.h"
#include "system/vhost-user-backend.h"
+#include "qapi/qapi-types-virtio.h"
#include "standard-headers/linux/virtio_gpu.h"
#include "standard-headers/linux/virtio_ids.h"
@@ -128,6 +129,7 @@ struct virtio_gpu_base_conf {
uint32_t xres;
uint32_t yres;
uint64_t hostmem;
+ VirtIOGPUOutputList *outputs;
};
struct virtio_gpu_ctrl_command {
@@ -167,6 +169,7 @@ struct VirtIOGPUBaseClass {
#define VIRTIO_GPU_BASE_PROPERTIES(_state, _conf) \
DEFINE_PROP_UINT32("max_outputs", _state, _conf.max_outputs, 1), \
+ DEFINE_PROP_VIRTIO_GPU_OUTPUT_LIST("outputs", _state, _conf.outputs), \
DEFINE_PROP_BIT("edid", _state, _conf.flags, \
VIRTIO_GPU_FLAG_EDID_ENABLED, true), \
DEFINE_PROP_UINT32("xres", _state, _conf.xres, 1280), \
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
index b9ea9e8..73fdefc 100644
--- a/include/hw/virtio/virtio-net.h
+++ b/include/hw/virtio/virtio-net.h
@@ -144,7 +144,11 @@ typedef struct VirtioNetRssData {
bool enabled_software_rss;
bool redirect;
bool populate_hash;
- uint32_t hash_types;
+ bool peer_hash_available;
+ uint32_t runtime_hash_types;
+ uint32_t supported_hash_types;
+ uint32_t peer_hash_types;
+ OnOffAutoBit64 specified_hash_types;
uint8_t key[VIRTIO_NET_RSS_MAX_KEY_SIZE];
uint16_t indirections_len;
uint16_t *indirections_table;
diff --git a/include/hw/xen/arch_hvm.h b/include/hw/xen/arch_hvm.h
index df39c81..8bacaa4 100644
--- a/include/hw/xen/arch_hvm.h
+++ b/include/hw/xen/arch_hvm.h
@@ -1,5 +1,11 @@
-#if defined(TARGET_I386) || defined(TARGET_X86_64)
-#include "hw/i386/xen_arch_hvm.h"
-#elif defined(TARGET_ARM) || defined(TARGET_AARCH64)
-#include "hw/arm/xen_arch_hvm.h"
+#ifndef HW_XEN_ARCH_HVM_H
+#define HW_XEN_ARCH_HVM_H
+
+#include <xen/hvm/ioreq.h>
+#include "hw/xen/xen-hvm-common.h"
+
+void arch_handle_ioreq(XenIOState *state, ioreq_t *req);
+void arch_xen_set_memory(XenIOState *state,
+ MemoryRegionSection *section,
+ bool add);
#endif
diff --git a/include/net/net.h b/include/net/net.h
index e67b375..84ee18e 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -60,6 +60,7 @@ typedef bool (HasVnetHdrLen)(NetClientState *, int);
typedef void (SetOffload)(NetClientState *, int, int, int, int, int, int, int);
typedef int (GetVnetHdrLen)(NetClientState *);
typedef void (SetVnetHdrLen)(NetClientState *, int);
+typedef bool (GetVnetHashSupportedTypes)(NetClientState *, uint32_t *);
typedef int (SetVnetLE)(NetClientState *, bool);
typedef int (SetVnetBE)(NetClientState *, bool);
typedef struct SocketReadState SocketReadState;
@@ -90,6 +91,7 @@ typedef struct NetClientInfo {
SetVnetHdrLen *set_vnet_hdr_len;
SetVnetLE *set_vnet_le;
SetVnetBE *set_vnet_be;
+ GetVnetHashSupportedTypes *get_vnet_hash_supported_types;
NetAnnounce *announce;
SetSteeringEBPF *set_steering_ebpf;
NetCheckPeerType *check_peer_type;
@@ -191,6 +193,7 @@ void qemu_set_offload(NetClientState *nc, int csum, int tso4, int tso6,
int ecn, int ufo, int uso4, int uso6);
int qemu_get_vnet_hdr_len(NetClientState *nc);
void qemu_set_vnet_hdr_len(NetClientState *nc, int len);
+bool qemu_get_vnet_hash_supported_types(NetClientState *nc, uint32_t *types);
int qemu_set_vnet_le(NetClientState *nc, bool is_le);
int qemu_set_vnet_be(NetClientState *nc, bool is_be);
void qemu_macaddr_default_if_unset(MACAddr *macaddr);
diff --git a/include/qemu/accel.h b/include/qemu/accel.h
index 9e821d0..d3638c7 100644
--- a/include/qemu/accel.h
+++ b/include/qemu/accel.h
@@ -26,43 +26,8 @@
#include "qom/object.h"
#include "exec/hwaddr.h"
-struct AccelState {
- /*< private >*/
- Object parent_obj;
-};
-
-typedef struct AccelClass {
- /*< private >*/
- ObjectClass parent_class;
- /*< public >*/
-
- const char *name;
- /* Cached by accel_init_ops_interfaces() when created */
- AccelOpsClass *ops;
-
- int (*init_machine)(AccelState *as, MachineState *ms);
- bool (*cpu_common_realize)(CPUState *cpu, Error **errp);
- void (*cpu_common_unrealize)(CPUState *cpu);
-
- /* system related hooks */
- void (*setup_post)(AccelState *as);
- void (*pre_resume_vm)(AccelState *as, bool step_pending);
- bool (*has_memory)(AccelState *accel, AddressSpace *as,
- hwaddr start_addr, hwaddr size);
-
- /* gdbstub related hooks */
- int (*gdbstub_supported_sstep_flags)(AccelState *as);
-
- bool *allowed;
- /*
- * Array of global properties that would be applied when specific
- * accelerator is chosen. It works like MachineClass.compat_props
- * but it's for accelerators not machines. Accelerator-provided
- * global properties may be overridden by machine-type
- * compat_props or user-provided global properties.
- */
- GPtrArray *compat_props;
-} AccelClass;
+typedef struct AccelState AccelState;
+typedef struct AccelClass AccelClass;
#define TYPE_ACCEL "accel"
diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h
index 9a11764..39ba640 100644
--- a/include/qemu/bswap.h
+++ b/include/qemu/bswap.h
@@ -1,6 +1,8 @@
#ifndef BSWAP_H
#define BSWAP_H
+#include "qemu/target-info.h"
+
#undef bswap16
#define bswap16(_x) __builtin_bswap16(_x)
#undef bswap32
@@ -432,4 +434,75 @@ DO_STN_LDN_P(be)
#undef le_bswaps
#undef be_bswaps
+
+/* Return ld{word}_{le,be}_p following target endianness. */
+#define LOAD_IMPL(word, args...) \
+do { \
+ if (target_big_endian()) { \
+ return glue(glue(ld, word), _be_p)(args); \
+ } else { \
+ return glue(glue(ld, word), _le_p)(args); \
+ } \
+} while (0)
+
+static inline int lduw_p(const void *ptr)
+{
+ LOAD_IMPL(uw, ptr);
+}
+
+static inline int ldsw_p(const void *ptr)
+{
+ LOAD_IMPL(sw, ptr);
+}
+
+static inline int ldl_p(const void *ptr)
+{
+ LOAD_IMPL(l, ptr);
+}
+
+static inline uint64_t ldq_p(const void *ptr)
+{
+ LOAD_IMPL(q, ptr);
+}
+
+static inline uint64_t ldn_p(const void *ptr, int sz)
+{
+ LOAD_IMPL(n, ptr, sz);
+}
+
+#undef LOAD_IMPL
+
+/* Call st{word}_{le,be}_p following target endianness. */
+#define STORE_IMPL(word, args...) \
+do { \
+ if (target_big_endian()) { \
+ glue(glue(st, word), _be_p)(args); \
+ } else { \
+ glue(glue(st, word), _le_p)(args); \
+ } \
+} while (0)
+
+
+static inline void stw_p(void *ptr, uint16_t v)
+{
+ STORE_IMPL(w, ptr, v);
+}
+
+static inline void stl_p(void *ptr, uint32_t v)
+{
+ STORE_IMPL(l, ptr, v);
+}
+
+static inline void stq_p(void *ptr, uint64_t v)
+{
+ STORE_IMPL(q, ptr, v);
+}
+
+static inline void stn_p(void *ptr, int sz, uint64_t v)
+{
+ STORE_IMPL(n, ptr, sz, v);
+}
+
+#undef STORE_IMPL
+
#endif /* BSWAP_H */
diff --git a/include/qemu/job.h b/include/qemu/job.h
index a5a0415..ead3157 100644
--- a/include/qemu/job.h
+++ b/include/qemu/job.h
@@ -263,7 +263,7 @@ struct JobDriver {
* 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);
+ int GRAPH_UNLOCKED_PTR (*prepare)(Job *job);
/**
* If the callback is not NULL, it will be invoked when all the jobs
@@ -283,7 +283,7 @@ struct JobDriver {
* All jobs will complete with a call to either .commit() or .abort() but
* never both.
*/
- void (*abort)(Job *job);
+ void GRAPH_UNLOCKED_PTR (*abort)(Job *job);
/**
* If the callback is not NULL, it will be invoked after a call to either
diff --git a/include/qemu/target-info-impl.h b/include/qemu/target-info-impl.h
index 1b51cbc..17887f6 100644
--- a/include/qemu/target-info-impl.h
+++ b/include/qemu/target-info-impl.h
@@ -9,17 +9,21 @@
#ifndef QEMU_TARGET_INFO_IMPL_H
#define QEMU_TARGET_INFO_IMPL_H
-#include "qemu/target-info.h"
+#include "qapi/qapi-types-machine.h"
typedef struct TargetInfo {
/* runtime equivalent of TARGET_NAME definition */
const char *target_name;
+ /* related to TARGET_ARCH definition */
+ SysEmuTarget target_arch;
/* runtime equivalent of TARGET_LONG_BITS definition */
unsigned long_bits;
/* runtime equivalent of CPU_RESOLVING_TYPE definition */
const char *cpu_type;
/* QOM typename machines for this binary must implement */
const char *machine_typename;
+ /* related to TARGET_BIG_ENDIAN definition */
+ EndianMode endianness;
} TargetInfo;
/**
diff --git a/include/qemu/target-info-qapi.h b/include/qemu/target-info-qapi.h
new file mode 100644
index 0000000..d5ce052
--- /dev/null
+++ b/include/qemu/target-info-qapi.h
@@ -0,0 +1,29 @@
+/*
+ * QEMU target info API (returning QAPI types)
+ *
+ * Copyright (c) Linaro
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef QEMU_TARGET_INFO_EXTRA_H
+#define QEMU_TARGET_INFO_EXTRA_H
+
+#include "qapi/qapi-types-common.h"
+#include "qapi/qapi-types-machine.h"
+
+/**
+ * target_arch:
+ *
+ * Returns: QAPI SysEmuTarget enum (e.g. SYS_EMU_TARGET_X86_64).
+ */
+SysEmuTarget target_arch(void);
+
+/**
+ * target_endian_mode:
+ *
+ * Returns: QAPI EndianMode enum (e.g. ENDIAN_MODE_LITTLE).
+ */
+EndianMode target_endian_mode(void);
+
+#endif
diff --git a/include/qemu/target-info.h b/include/qemu/target-info.h
index 850a295..abcf25d 100644
--- a/include/qemu/target-info.h
+++ b/include/qemu/target-info.h
@@ -1,5 +1,5 @@
/*
- * QEMU target info API
+ * QEMU target info API (returning native types)
*
* Copyright (c) Linaro
*
@@ -38,4 +38,16 @@ const char *target_machine_typename(void);
*/
const char *target_cpu_type(void);
+/**
+ * target_big_endian:
+ *
+ * Returns: %true if the (default) endianness of the target is big endian,
+ * %false otherwise.
+ *
+ * Common code should normally never need to know about the endianness of
+ * the target, so please do *not* use this function unless you know very
+ * well what you are doing!
+ */
+bool target_big_endian(void);
+
#endif
diff --git a/include/system/block-backend-global-state.h b/include/system/block-backend-global-state.h
index 35b5e83..c384964 100644
--- a/include/system/block-backend-global-state.h
+++ b/include/system/block-backend-global-state.h
@@ -55,7 +55,7 @@ void monitor_remove_blk(BlockBackend *blk);
BlockBackendPublic *blk_get_public(BlockBackend *blk);
-void blk_remove_bs(BlockBackend *blk);
+void GRAPH_UNLOCKED blk_remove_bs(BlockBackend *blk);
int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp);
int blk_replace_bs(BlockBackend *blk, BlockDriverState *new_bs, Error **errp);
bool GRAPH_RDLOCK bdrv_has_blk(BlockDriverState *bs);
@@ -78,8 +78,8 @@ int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags);
void blk_aio_cancel(BlockAIOCB *acb);
int blk_commit_all(void);
bool blk_in_drain(BlockBackend *blk);
-void blk_drain(BlockBackend *blk);
-void blk_drain_all(void);
+void GRAPH_UNLOCKED blk_drain(BlockBackend *blk);
+void GRAPH_UNLOCKED blk_drain_all(void);
void blk_set_on_error(BlockBackend *blk, BlockdevOnError on_read_error,
BlockdevOnError on_write_error);
bool blk_supports_write_perm(BlockBackend *blk);
@@ -109,7 +109,7 @@ int blk_probe_blocksizes(BlockBackend *blk, BlockSizes *bsz);
int blk_probe_geometry(BlockBackend *blk, HDGeometry *geo);
void blk_set_io_limits(BlockBackend *blk, ThrottleConfig *cfg);
-void blk_io_limits_disable(BlockBackend *blk);
+void GRAPH_UNLOCKED blk_io_limits_disable(BlockBackend *blk);
void blk_io_limits_enable(BlockBackend *blk, const char *group);
void blk_io_limits_update_group(BlockBackend *blk, const char *group);
void blk_set_force_allow_inactivate(BlockBackend *blk);
diff --git a/include/system/hvf_int.h b/include/system/hvf_int.h
index 5150c7d..a3b06a3 100644
--- a/include/system/hvf_int.h
+++ b/include/system/hvf_int.h
@@ -14,6 +14,7 @@
#include "qemu/queue.h"
#include "exec/vaddr.h"
#include "qom/object.h"
+#include "accel/accel-ops.h"
#ifdef __aarch64__
#include <Hypervisor/Hypervisor.h>
@@ -45,7 +46,7 @@ typedef struct hvf_vcpu_caps {
} hvf_vcpu_caps;
struct HVFState {
- AccelState parent;
+ AccelState parent_obj;
hvf_slot slots[32];
int num_slots;
diff --git a/include/system/kvm_int.h b/include/system/kvm_int.h
index 756a3c0..9247493 100644
--- a/include/system/kvm_int.h
+++ b/include/system/kvm_int.h
@@ -14,6 +14,7 @@
#include "qemu/accel.h"
#include "qemu/queue.h"
#include "system/kvm.h"
+#include "accel/accel-ops.h"
#include "hw/boards.h"
#include "hw/i386/topology.h"
#include "io/channel-socket.h"
diff --git a/include/system/memory.h b/include/system/memory.h
index 46248d4..e2cd6ed 100644
--- a/include/system/memory.h
+++ b/include/system/memory.h
@@ -19,7 +19,6 @@
#include "exec/memattrs.h"
#include "exec/memop.h"
#include "exec/ramlist.h"
-#include "exec/tswap.h"
#include "qemu/bswap.h"
#include "qemu/queue.h"
#include "qemu/int128.h"
@@ -109,15 +108,34 @@ struct MemoryRegionSection {
typedef struct IOMMUTLBEntry IOMMUTLBEntry;
-/* See address_space_translate: bit 0 is read, bit 1 is write. */
+/*
+ * See address_space_translate:
+ * - bit 0 : read
+ * - bit 1 : write
+ * - bit 2 : exec
+ * - bit 3 : priv
+ * - bit 4 : global
+ * - bit 5 : untranslated only
+ */
typedef enum {
IOMMU_NONE = 0,
IOMMU_RO = 1,
IOMMU_WO = 2,
IOMMU_RW = 3,
+ IOMMU_EXEC = 4,
+ IOMMU_PRIV = 8,
+ IOMMU_GLOBAL = 16,
+ IOMMU_UNTRANSLATED_ONLY = 32,
} IOMMUAccessFlags;
-#define IOMMU_ACCESS_FLAG(r, w) (((r) ? IOMMU_RO : 0) | ((w) ? IOMMU_WO : 0))
+#define IOMMU_ACCESS_FLAG(r, w) (((r) ? IOMMU_RO : 0) | \
+ ((w) ? IOMMU_WO : 0))
+#define IOMMU_ACCESS_FLAG_FULL(r, w, x, p, g, uo) \
+ (IOMMU_ACCESS_FLAG(r, w) | \
+ ((x) ? IOMMU_EXEC : 0) | \
+ ((p) ? IOMMU_PRIV : 0) | \
+ ((g) ? IOMMU_GLOBAL : 0) | \
+ ((uo) ? IOMMU_UNTRANSLATED_ONLY : 0))
struct IOMMUTLBEntry {
AddressSpace *target_as;
@@ -125,6 +143,7 @@ struct IOMMUTLBEntry {
hwaddr translated_addr;
hwaddr addr_mask; /* 0xfff = 4k translation */
IOMMUAccessFlags perm;
+ uint32_t pasid;
};
/*
diff --git a/include/system/runstate.h b/include/system/runstate.h
index fdd5c4a..929379a 100644
--- a/include/system/runstate.h
+++ b/include/system/runstate.h
@@ -14,11 +14,51 @@ void runstate_replay_enable(void);
typedef void VMChangeStateHandler(void *opaque, bool running, RunState state);
typedef int VMChangeStateHandlerWithRet(void *opaque, bool running, RunState state);
+/**
+ * qemu_add_vm_change_state_handler:
+ * @cb: the callback to invoke
+ * @opaque: user data passed to the callback
+ *
+ * Register a callback function that is invoked when the vm starts or stops
+ * running.
+ *
+ * Returns: an entry to be freed using qemu_del_vm_change_state_handler()
+ */
VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb,
void *opaque);
+/**
+ * qemu_add_vm_change_state_handler_prio:
+ * @cb: the callback to invoke
+ * @opaque: user data passed to the callback
+ * @priority: low priorities execute first when the vm runs and the reverse is
+ * true when the vm stops
+ *
+ * Register a callback function that is invoked when the vm starts or stops
+ * running.
+ *
+ * Returns: an entry to be freed using qemu_del_vm_change_state_handler()
+ */
VMChangeStateEntry *qemu_add_vm_change_state_handler_prio(
VMChangeStateHandler *cb, void *opaque, int priority);
VMChangeStateEntry *
+/**
+ * qemu_add_vm_change_state_handler_prio_full:
+ * @cb: the main callback to invoke
+ * @prepare_cb: a callback to invoke before the main callback
+ * @cb_ret: the main callback to invoke with return value
+ * @opaque: user data passed to the callbacks
+ * @priority: low priorities execute first when the vm runs and the reverse is
+ * true when the vm stops
+ *
+ * Register a main callback function and an optional prepare callback function
+ * that are invoked when the vm starts or stops running. The main callback and
+ * the prepare callback are called in two separate phases: First all prepare
+ * callbacks are called and only then all main callbacks are called. As its
+ * name suggests, the prepare callback can be used to do some preparatory work
+ * before invoking the main callback.
+ *
+ * Returns: an entry to be freed using qemu_del_vm_change_state_handler()
+ */
qemu_add_vm_change_state_handler_prio_full(VMChangeStateHandler *cb,
VMChangeStateHandler *prepare_cb,
VMChangeStateHandlerWithRet *cb_ret,
@@ -107,6 +147,7 @@ void qemu_system_vmstop_request(RunState reason);
void qemu_system_vmstop_request_prepare(void);
bool qemu_vmstop_requested(RunState *r);
ShutdownCause qemu_shutdown_requested_get(void);
+bool qemu_force_shutdown_requested(void);
ShutdownCause qemu_reset_requested_get(void);
void qemu_system_killed(int signal, pid_t pid);
void qemu_system_reset(ShutdownCause reason);
diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
index 0c2a319..a6d9aa5 100644
--- a/include/tcg/tcg.h
+++ b/include/tcg/tcg.h
@@ -1005,5 +1005,7 @@ static inline const TCGOpcode *tcg_swap_vecop_list(const TCGOpcode *n)
bool tcg_can_emit_vecop_list(const TCGOpcode *, TCGType, unsigned);
void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs);
+/* tcg_dump_stats: Append TCG statistics to @buf */
+void tcg_dump_stats(GString *buf);
#endif /* TCG_H */
diff --git a/include/ui/console.h b/include/ui/console.h
index 46b3128..98feaa5 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -422,6 +422,9 @@ bool console_gl_check_format(DisplayChangeListener *dcl,
pixman_format_code_t format);
void surface_gl_create_texture(QemuGLShader *gls,
DisplaySurface *surface);
+bool surface_gl_create_texture_from_fd(DisplaySurface *surface,
+ int fd, GLuint *texture,
+ GLuint *mem_obj);
void surface_gl_update_texture(QemuGLShader *gls,
DisplaySurface *surface,
int x, int y, int w, int h);
diff --git a/include/ui/gtk.h b/include/ui/gtk.h
index d394404..3e6ce3c 100644
--- a/include/ui/gtk.h
+++ b/include/ui/gtk.h
@@ -41,6 +41,7 @@ typedef struct VirtualGfxConsole {
DisplaySurface *ds;
pixman_image_t *convert;
cairo_surface_t *surface;
+ double preferred_scale;
double scale_x;
double scale_y;
#if defined(CONFIG_OPENGL)
@@ -140,6 +141,7 @@ struct GtkDisplayState {
GdkCursor *null_cursor;
Notifier mouse_mode_notifier;
gboolean free_scale;
+ gboolean keep_aspect_ratio;
bool external_pause_update;
diff --git a/include/ui/spice-display.h b/include/ui/spice-display.h
index e1a9b36..690ece7 100644
--- a/include/ui/spice-display.h
+++ b/include/ui/spice-display.h
@@ -132,6 +132,9 @@ struct SimpleSpiceDisplay {
egl_fb guest_fb;
egl_fb blit_fb;
egl_fb cursor_fb;
+ bool backing_y_0_top;
+ bool blit_scanout_texture;
+ bool new_scanout_texture;
bool have_hot;
#endif
};
@@ -151,6 +154,8 @@ struct SimpleSpiceCursor {
};
extern bool spice_opengl;
+extern bool spice_remote_client;
+extern int spice_max_refresh_rate;
int qemu_spice_rect_is_empty(const QXLRect* r);
void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r);
diff --git a/include/ui/surface.h b/include/ui/surface.h
index f16f7be..006b198 100644
--- a/include/ui/surface.h
+++ b/include/ui/surface.h
@@ -22,6 +22,7 @@ typedef struct DisplaySurface {
GLenum glformat;
GLenum gltype;
GLuint texture;
+ GLuint mem_obj;
#endif
qemu_pixman_shareable share_handle;
uint32_t share_handle_offset;
diff --git a/include/user/abitypes.h b/include/user/abitypes.h
index 7528124..be7a876 100644
--- a/include/user/abitypes.h
+++ b/include/user/abitypes.h
@@ -6,7 +6,6 @@
#endif
#include "exec/cpu-defs.h"
-#include "exec/tswap.h"
#include "user/tswap-target.h"
#ifdef TARGET_ABI32
diff --git a/linux-user/main.c b/linux-user/main.c
index f4f2007..68972f0 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -42,6 +42,7 @@
#include "user/page-protection.h"
#include "exec/gdbstub.h"
#include "gdbstub/user.h"
+#include "accel/accel-ops.h"
#include "tcg/startup.h"
#include "qemu/timer.h"
#include "qemu/envlist.h"
diff --git a/linux-user/meson.build b/linux-user/meson.build
index f47a213..efca843 100644
--- a/linux-user/meson.build
+++ b/linux-user/meson.build
@@ -27,7 +27,10 @@ linux_user_ss.add(libdw)
linux_user_ss.add(when: 'TARGET_HAS_BFLT', if_true: files('flatload.c'))
linux_user_ss.add(when: 'TARGET_I386', if_true: files('vm86.c'))
linux_user_ss.add(when: 'CONFIG_ARM_COMPATIBLE_SEMIHOSTING', if_true: files('semihost.c'))
-linux_user_ss.add(when: 'CONFIG_TCG_PLUGINS', if_true: files('plugin-api.c'))
+
+if get_option('plugins')
+ linux_user_ss.add(files('plugin-api.c'))
+endif
syscall_nr_generators = {}
diff --git a/linux-user/plugin-api.c b/linux-user/plugin-api.c
index 66755df..8d6fbb6 100644
--- a/linux-user/plugin-api.c
+++ b/linux-user/plugin-api.c
@@ -12,4 +12,5 @@
#include "qemu/osdep.h"
#include "qemu.h"
+#include "loader.h"
#include "common-user/plugin-api.c.inc"
diff --git a/net/af-xdp.c b/net/af-xdp.c
index d022534..14f302e 100644
--- a/net/af-xdp.c
+++ b/net/af-xdp.c
@@ -49,9 +49,12 @@ typedef struct AFXDPState {
char *buffer;
struct xsk_umem *umem;
- uint32_t n_queues;
uint32_t xdp_flags;
bool inhibit;
+
+ char *map_path;
+ int map_fd;
+ uint32_t map_start_index;
} AFXDPState;
#define AF_XDP_BATCH_SIZE 64
@@ -261,6 +264,7 @@ static void af_xdp_send(void *opaque)
static void af_xdp_cleanup(NetClientState *nc)
{
AFXDPState *s = DO_UPCAST(AFXDPState, nc, nc);
+ int idx;
qemu_purge_queued_packets(nc);
@@ -275,13 +279,17 @@ static void af_xdp_cleanup(NetClientState *nc)
qemu_vfree(s->buffer);
s->buffer = NULL;
- /* Remove the program if it's the last open queue. */
- if (!s->inhibit && nc->queue_index == s->n_queues - 1 && s->xdp_flags
- && bpf_xdp_detach(s->ifindex, s->xdp_flags, NULL) != 0) {
- fprintf(stderr,
- "af-xdp: unable to remove XDP program from '%s', ifindex: %d\n",
- s->ifname, s->ifindex);
+ if (s->map_fd >= 0) {
+ idx = nc->queue_index + s->map_start_index;
+ if (bpf_map_delete_elem(s->map_fd, &idx)) {
+ fprintf(stderr, "af-xdp: unable to remove AF_XDP socket from map"
+ " %s\n", s->map_path);
+ }
+ close(s->map_fd);
+ s->map_fd = -1;
}
+ g_free(s->map_path);
+ s->map_path = NULL;
}
static int af_xdp_umem_create(AFXDPState *s, int sock_fd, Error **errp)
@@ -345,7 +353,6 @@ static int af_xdp_socket_create(AFXDPState *s,
};
int queue_id, error = 0;
- s->inhibit = opts->has_inhibit && opts->inhibit;
if (s->inhibit) {
cfg.libxdp_flags |= XSK_LIBXDP_FLAGS__INHIBIT_PROG_LOAD;
}
@@ -396,6 +403,35 @@ static int af_xdp_socket_create(AFXDPState *s,
return 0;
}
+static int af_xdp_update_xsk_map(AFXDPState *s, Error **errp)
+{
+ int xsk_fd, idx, error = 0;
+
+ if (!s->map_path) {
+ return 0;
+ }
+
+ s->map_fd = bpf_obj_get(s->map_path);
+ if (s->map_fd < 0) {
+ error = errno;
+ } else {
+ xsk_fd = xsk_socket__fd(s->xsk);
+ idx = s->nc.queue_index + s->map_start_index;
+ if (bpf_map_update_elem(s->map_fd, &idx, &xsk_fd, 0)) {
+ error = errno;
+ }
+ }
+
+ if (error) {
+ error_setg_errno(errp, error,
+ "failed to insert AF_XDP socket into map %s",
+ s->map_path);
+ return -1;
+ }
+
+ return 0;
+}
+
/* NetClientInfo methods. */
static NetClientInfo net_af_xdp_info = {
.type = NET_CLIENT_DRIVER_AF_XDP,
@@ -444,12 +480,14 @@ int net_init_af_xdp(const Netdev *netdev,
{
const NetdevAFXDPOptions *opts = &netdev->u.af_xdp;
NetClientState *nc, *nc0 = NULL;
+ int32_t map_start_index;
unsigned int ifindex;
uint32_t prog_id = 0;
g_autofree int *sock_fds = NULL;
int64_t i, queues;
Error *err = NULL;
AFXDPState *s;
+ bool inhibit;
ifindex = if_nametoindex(opts->ifname);
if (!ifindex) {
@@ -465,8 +503,28 @@ int net_init_af_xdp(const Netdev *netdev,
return -1;
}
- if ((opts->has_inhibit && opts->inhibit) != !!opts->sock_fds) {
- error_setg(errp, "'inhibit=on' requires 'sock-fds' and vice versa");
+ inhibit = opts->has_inhibit && opts->inhibit;
+ if (inhibit && !opts->sock_fds && !opts->map_path) {
+ error_setg(errp, "'inhibit=on' requires 'sock-fds' or 'map-path'");
+ return -1;
+ }
+ if (!inhibit && (opts->sock_fds || opts->map_path)) {
+ error_setg(errp, "'sock-fds' and 'map-path' require 'inhibit=on'");
+ return -1;
+ }
+ if (opts->sock_fds && opts->map_path) {
+ error_setg(errp, "'sock-fds' and 'map-path' are mutually exclusive");
+ return -1;
+ }
+ if (!opts->map_path && opts->has_map_start_index) {
+ error_setg(errp, "'map-start-index' requires 'map-path'");
+ return -1;
+ }
+
+ map_start_index = opts->has_map_start_index ? opts->map_start_index : 0;
+ if (map_start_index < 0) {
+ error_setg(errp, "'map-start-index' cannot be negative (%d)",
+ map_start_index);
return -1;
}
@@ -490,21 +548,23 @@ int net_init_af_xdp(const Netdev *netdev,
pstrcpy(s->ifname, sizeof(s->ifname), opts->ifname);
s->ifindex = ifindex;
- s->n_queues = queues;
+ s->inhibit = inhibit;
+
+ s->map_path = g_strdup(opts->map_path);
+ s->map_start_index = map_start_index;
+ s->map_fd = -1;
- if (af_xdp_umem_create(s, sock_fds ? sock_fds[i] : -1, errp)
- || af_xdp_socket_create(s, opts, errp)) {
- /* Make sure the XDP program will be removed. */
- s->n_queues = i;
- error_propagate(errp, err);
+ if (af_xdp_umem_create(s, sock_fds ? sock_fds[i] : -1, &err) ||
+ af_xdp_socket_create(s, opts, &err) ||
+ af_xdp_update_xsk_map(s, &err)) {
goto err;
}
}
- if (nc0) {
+ if (nc0 && !inhibit) {
s = DO_UPCAST(AFXDPState, nc, nc0);
if (bpf_xdp_query_id(s->ifindex, s->xdp_flags, &prog_id) || !prog_id) {
- error_setg_errno(errp, errno,
+ error_setg_errno(&err, errno,
"no XDP program loaded on '%s', ifindex: %d",
s->ifname, s->ifindex);
goto err;
@@ -518,6 +578,7 @@ int net_init_af_xdp(const Netdev *netdev,
err:
if (nc0) {
qemu_del_net_client(nc0);
+ error_propagate(errp, err);
}
return -1;
diff --git a/net/net.c b/net/net.c
index 90f69fd..da275db 100644
--- a/net/net.c
+++ b/net/net.c
@@ -573,6 +573,15 @@ void qemu_set_vnet_hdr_len(NetClientState *nc, int len)
nc->info->set_vnet_hdr_len(nc, len);
}
+bool qemu_get_vnet_hash_supported_types(NetClientState *nc, uint32_t *types)
+{
+ if (!nc || !nc->info->get_vnet_hash_supported_types) {
+ return false;
+ }
+
+ return nc->info->get_vnet_hash_supported_types(nc, types);
+}
+
int qemu_set_vnet_le(NetClientState *nc, bool is_le)
{
#if HOST_BIG_ENDIAN
diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
index 943e9c5..6a30a44 100644
--- a/net/vhost-vdpa.c
+++ b/net/vhost-vdpa.c
@@ -244,15 +244,35 @@ static void vhost_vdpa_cleanup(NetClientState *nc)
g_free(s->vhost_vdpa.shared);
}
-/** Dummy SetSteeringEBPF to support RSS for vhost-vdpa backend */
-static bool vhost_vdpa_set_steering_ebpf(NetClientState *nc, int prog_fd)
+static bool vhost_vdpa_has_vnet_hdr(NetClientState *nc)
{
+ assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA);
+
return true;
}
-static bool vhost_vdpa_has_vnet_hdr(NetClientState *nc)
+static bool vhost_vdpa_get_vnet_hash_supported_types(NetClientState *nc,
+ uint32_t *types)
{
assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA);
+ VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc);
+ uint64_t features = s->vhost_vdpa.dev->features;
+ int fd = s->vhost_vdpa.shared->device_fd;
+ struct {
+ struct vhost_vdpa_config hdr;
+ uint32_t supported_hash_types;
+ } config;
+
+ if (!virtio_has_feature(features, VIRTIO_NET_F_HASH_REPORT) &&
+ !virtio_has_feature(features, VIRTIO_NET_F_RSS)) {
+ return false;
+ }
+
+ config.hdr.off = offsetof(struct virtio_net_config, supported_hash_types);
+ config.hdr.len = sizeof(config.supported_hash_types);
+
+ assert(!ioctl(fd, VHOST_VDPA_GET_CONFIG, &config));
+ *types = le32_to_cpu(config.supported_hash_types);
return true;
}
@@ -433,10 +453,10 @@ static NetClientInfo net_vhost_vdpa_info = {
.stop = vhost_vdpa_net_client_stop,
.cleanup = vhost_vdpa_cleanup,
.has_vnet_hdr = vhost_vdpa_has_vnet_hdr,
+ .get_vnet_hash_supported_types = vhost_vdpa_get_vnet_hash_supported_types,
.has_ufo = vhost_vdpa_has_ufo,
.set_vnet_le = vhost_vdpa_set_vnet_le,
.check_peer_type = vhost_vdpa_check_peer_type,
- .set_steering_ebpf = vhost_vdpa_set_steering_ebpf,
.get_vhost_net = vhost_vdpa_get_vhost_net,
};
@@ -844,13 +864,13 @@ static int vhost_vdpa_net_load_rss(VhostVDPAState *s, const VirtIONet *n,
* configuration only at live migration.
*/
if (!n->rss_data.enabled ||
- n->rss_data.hash_types == VIRTIO_NET_HASH_REPORT_NONE) {
+ n->rss_data.runtime_hash_types == VIRTIO_NET_HASH_REPORT_NONE) {
return 0;
}
table = g_malloc_n(n->rss_data.indirections_len,
sizeof(n->rss_data.indirections_table[0]));
- cfg.hash_types = cpu_to_le32(n->rss_data.hash_types);
+ cfg.hash_types = cpu_to_le32(n->rss_data.runtime_hash_types);
if (do_rss) {
/*
@@ -1290,9 +1310,9 @@ static NetClientInfo net_vhost_vdpa_cvq_info = {
.stop = vhost_vdpa_net_cvq_stop,
.cleanup = vhost_vdpa_cleanup,
.has_vnet_hdr = vhost_vdpa_has_vnet_hdr,
+ .get_vnet_hash_supported_types = vhost_vdpa_get_vnet_hash_supported_types,
.has_ufo = vhost_vdpa_has_ufo,
.check_peer_type = vhost_vdpa_check_peer_type,
- .set_steering_ebpf = vhost_vdpa_set_steering_ebpf,
.get_vhost_net = vhost_vdpa_get_vhost_net,
};
diff --git a/pc-bios/hppa-firmware.img b/pc-bios/hppa-firmware.img
index d5f6f2f..d5f6f2f 100755..100644
--- a/pc-bios/hppa-firmware.img
+++ b/pc-bios/hppa-firmware.img
Binary files differ
diff --git a/pc-bios/hppa-firmware64.img b/pc-bios/hppa-firmware64.img
index 577b0a1..577b0a1 100755..100644
--- a/pc-bios/hppa-firmware64.img
+++ b/pc-bios/hppa-firmware64.img
Binary files differ
diff --git a/python/tests/qapi-isort.sh b/python/tests/qapi-isort.sh
index 78dd947..067c16d 100755
--- a/python/tests/qapi-isort.sh
+++ b/python/tests/qapi-isort.sh
@@ -3,6 +3,6 @@
python3 -m isort --sp . -c ../scripts/qapi/
# Force isort to recognize "compat" as a local module and not third-party
-python3 -m isort --sp . -c -p compat -p qapidoc_legacy \
+python3 -m isort --sp . -c -p compat \
../docs/sphinx/qapi_domain.py \
../docs/sphinx/qapidoc.py
diff --git a/qapi/accelerator.json b/qapi/accelerator.json
new file mode 100644
index 0000000..28d5ff4
--- /dev/null
+++ b/qapi/accelerator.json
@@ -0,0 +1,54 @@
+# -*- Mode: Python -*-
+# vim: filetype=python
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+##
+# = Accelerators
+##
+
+{ 'include': 'common.json' }
+
+##
+# @KvmInfo:
+#
+# Information about support for KVM acceleration
+#
+# @enabled: true if KVM acceleration is active
+#
+# @present: true if KVM acceleration is built into this executable
+#
+# Since: 0.14
+##
+{ 'struct': 'KvmInfo', 'data': {'enabled': 'bool', 'present': 'bool'} }
+
+##
+# @query-kvm:
+#
+# Return information about KVM acceleration
+#
+# Since: 0.14
+#
+# .. qmp-example::
+#
+# -> { "execute": "query-kvm" }
+# <- { "return": { "enabled": true, "present": true } }
+##
+{ 'command': 'query-kvm', 'returns': 'KvmInfo' }
+
+##
+# @x-accel-stats:
+#
+# Query accelerator statistics
+#
+# Features:
+#
+# @unstable: This command is meant for debugging.
+#
+# Returns: accelerator statistics
+#
+# Since: 10.1
+##
+{ 'command': 'x-accel-stats',
+ 'returns': 'HumanReadableText',
+ 'features': [ 'unstable' ] }
diff --git a/qapi/acpi.json b/qapi/acpi.json
index 2d53b82..906b368 100644
--- a/qapi/acpi.json
+++ b/qapi/acpi.json
@@ -6,7 +6,9 @@
# SPDX-License-Identifier: GPL-2.0-or-later
##
-# = ACPI
+# ****
+# ACPI
+# ****
##
##
@@ -106,7 +108,7 @@
##
# @query-acpi-ospm-status:
#
-# Return a list of ACPIOSTInfo for devices that support status
+# Return a list of `ACPIOSTInfo` for devices that support status
# reporting via ACPI _OST method.
#
# Since: 2.1
diff --git a/qapi/audio.json b/qapi/audio.json
index 16de231..5314208 100644
--- a/qapi/audio.json
+++ b/qapi/audio.json
@@ -7,7 +7,9 @@
# See the COPYING file in the top-level directory.
##
-# = Audio
+# *****
+# Audio
+# *****
##
##
@@ -535,8 +537,6 @@
#
# Return information about audiodev configuration
#
-# Returns: array of @Audiodev
-#
# Since: 8.0
##
{ 'command': 'query-audiodevs',
diff --git a/qapi/authz.json b/qapi/authz.json
index 7fc6e30..bc1123c 100644
--- a/qapi/authz.json
+++ b/qapi/authz.json
@@ -2,7 +2,9 @@
# vim: filetype=python
##
-# = User authorization
+# ******************
+# User authorization
+# ******************
##
##
@@ -75,7 +77,7 @@
# Properties for authz-listfile objects.
#
# @filename: File name to load the configuration from. The file must
-# contain valid JSON for AuthZListProperties.
+# contain valid JSON for `AuthZListProperties`.
#
# @refresh: If true, inotify is used to monitor the file,
# automatically reloading changes. If an error occurs during
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 1df6644..ebbe95b 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -2,7 +2,8 @@
# vim: filetype=python
##
-# == Block core (VM unrelated)
+# Block core (VM unrelated)
+# =========================
##
{ 'include': 'common.json' }
@@ -31,7 +32,7 @@
# @icount: Current instruction count. Appears when execution
# record/replay is enabled. Used for "time-traveling" to match
# the moment in the recorded execution with the snapshots. This
-# counter may be obtained through @query-replay command
+# counter may be obtained through `query-replay` command
# (since 5.2)
#
# Since: 1.3
@@ -223,7 +224,7 @@
{ 'struct': 'ImageInfoSpecificLUKSWrapper',
'data': { 'data': 'QCryptoBlockInfoLUKS' } }
# If we need to add block driver specific parameters for
-# LUKS in future, then we'll subclass QCryptoBlockInfoLUKS
+# LUKS in future, then we'll subclass `QCryptoBlockInfoLUKS`
# to define a ImageInfoSpecificLUKS
##
@@ -332,7 +333,7 @@
# node, annotated with information about that node in relation to its
# parent.
#
-# @name: Child name of the root node in the BlockGraphInfo struct, in
+# @name: Child name of the root node in the `BlockGraphInfo` struct, in
# its role as the child of some undescribed parent node
#
# @info: Block graph information starting at this node
@@ -349,7 +350,7 @@
# @BlockGraphInfo:
#
# Information about all nodes in a block (sub)graph in the form of
-# BlockNodeInfo data. The base BlockNodeInfo struct contains the
+# `BlockNodeInfo` data. The base `BlockNodeInfo` struct contains the
# information for the (sub)graph's root node.
#
# @children: Array of links to this node's child nodes' information
@@ -462,6 +463,19 @@
'no-flush': 'bool' } }
##
+# @BlockdevChild:
+#
+# @child: The name of the child, for example 'file' or 'backing'.
+#
+# @node-name: The name of the child's block driver node.
+#
+# Since: 10.1
+##
+{ 'struct': 'BlockdevChild',
+ 'data': { 'child': 'str',
+ 'node-name': 'str' } }
+
+##
# @BlockDeviceInfo:
#
# Information about the backing device for a block device.
@@ -486,6 +500,8 @@
# @backing_file_depth: number of files in the backing file chain
# (since: 1.2)
#
+# @children: Information about child block nodes. (since: 10.1)
+#
# @active: true if the backend is active; typical cases for inactive backends
# are on the migration source instance after migration completes and on the
# destination before it completes. (since: 10.0)
@@ -558,8 +574,9 @@
# Since: 0.14
##
{ 'struct': 'BlockDeviceInfo',
- 'data': { 'file': 'str', '*node-name': 'str', 'ro': 'bool', 'drv': 'str',
+ 'data': { 'file': 'str', 'node-name': 'str', 'ro': 'bool', 'drv': 'str',
'*backing_file': 'str', 'backing_file_depth': 'int',
+ 'children': ['BlockdevChild'],
'active': 'bool', 'encrypted': 'bool',
'detect_zeroes': 'BlockdevDetectZeroesOptions',
'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
@@ -614,7 +631,7 @@
# @inconsistent: true if this is a persistent bitmap that was
# improperly stored. Implies @persistent to be true; @recording
# and @busy to be false. This bitmap cannot be used. To remove
-# it, use @block-dirty-bitmap-remove. (Since 4.0)
+# it, use `block-dirty-bitmap-remove`. (Since 4.0)
#
# Since: 1.3
##
@@ -709,12 +726,12 @@
# @tray_open: True if the device's tray is open (only present if it
# has a tray)
#
-# @io-status: @BlockDeviceIoStatus. Only present if the device
+# @io-status: `BlockDeviceIoStatus`. Only present if the device
# supports it and the VM is configured to stop on errors
# (supported device models: virtio-blk, IDE, SCSI except
# scsi-generic)
#
-# @inserted: @BlockDeviceInfo describing the device if media is
+# @inserted: `BlockDeviceInfo` describing the device if media is
# present
#
# Since: 0.14
@@ -761,9 +778,9 @@
##
# @query-block:
#
-# Get a list of BlockInfo for all virtual block devices.
+# Get a list of `BlockInfo` for all virtual block devices.
#
-# Returns: a list of @BlockInfo describing each virtual block device.
+# Returns: a list describing each virtual block device.
# Filter nodes that were created implicitly are skipped over.
#
# Since: 0.14
@@ -1026,14 +1043,14 @@
# @timed_stats: Statistics specific to the set of previously defined
# intervals of time (Since 2.5)
#
-# @rd_latency_histogram: @BlockLatencyHistogramInfo. (Since 4.0)
+# @rd_latency_histogram: `BlockLatencyHistogramInfo`. (Since 4.0)
#
-# @wr_latency_histogram: @BlockLatencyHistogramInfo. (Since 4.0)
+# @wr_latency_histogram: `BlockLatencyHistogramInfo`. (Since 4.0)
#
-# @zone_append_latency_histogram: @BlockLatencyHistogramInfo.
+# @zone_append_latency_histogram: `BlockLatencyHistogramInfo`.
# (since 8.1)
#
-# @flush_latency_histogram: @BlockLatencyHistogramInfo. (Since 4.0)
+# @flush_latency_histogram: `BlockLatencyHistogramInfo`. (Since 4.0)
#
# Since: 0.14
##
@@ -1134,7 +1151,7 @@
# @qdev: The qdev ID, or if no ID is assigned, the QOM path of the
# block device. (since 3.0)
#
-# @stats: A @BlockDeviceStats for the device.
+# @stats: A `BlockDeviceStats` for the device.
#
# @driver-specific: Optional driver-specific stats. (Since 4.2)
#
@@ -1158,7 +1175,7 @@
##
# @query-blockstats:
#
-# Query the @BlockStats for all virtual block devices.
+# Query the `BlockStats` for all virtual block devices.
#
# @query-nodes: If true, the command will query all the block nodes
# that have a node name, in a list which will include "parent"
@@ -1168,7 +1185,7 @@
# nodes that were created implicitly are skipped over in this
# mode. (Since 2.3)
#
-# Returns: A list of @BlockStats for each virtual block devices.
+# Returns: A list of statistics for each virtual block device.
#
# Since: 0.14
#
@@ -1289,8 +1306,8 @@
# @report: for guest operations, report the error to the guest; for
# jobs, cancel the job
#
-# @ignore: ignore the error, only report a QMP event (BLOCK_IO_ERROR
-# or BLOCK_JOB_ERROR). The backup, mirror and commit block jobs
+# @ignore: ignore the error, only report a QMP event (`BLOCK_IO_ERROR`
+# or `BLOCK_JOB_ERROR`). The backup, mirror and commit block jobs
# retry the failing request later and may still complete
# successfully. The stream block job continues to stream and will
# complete with an error.
@@ -1323,7 +1340,7 @@
# (since: 2.4)
#
# @bitmap: only copy data described by the dirty bitmap. Behavior on
-# completion is determined by the BitmapSyncMode. (since: 4.2)
+# completion is determined by the `BitmapSyncMode`. (since: 4.2)
#
# Since: 1.3
##
@@ -1440,7 +1457,7 @@
#
# Return information about long-running block device operations.
#
-# Returns: a list of @BlockJobInfo for each active block job
+# Returns: a list of job info for each active block job
#
# Since: 1.1
##
@@ -1530,7 +1547,7 @@
# @overlay: reference to the existing block device that will become
# the overlay of @node, as part of taking the snapshot. It must
# not have a current backing file (this can be achieved by passing
-# "backing": null to blockdev-add).
+# "backing": null to `blockdev-add`).
#
# Since: 2.5
##
@@ -1585,7 +1602,7 @@
# @bitmap: The name of a dirty bitmap to use. Must be present if sync
# is "bitmap" or "incremental". Can be present if sync is "full"
# or "top". Must not be present otherwise.
-# (Since 2.4 (drive-backup), 3.1 (blockdev-backup))
+# (Since 2.4 (`drive-backup`), 3.1 (`blockdev-backup`))
#
# @bitmap-mode: Specifies the type of data the bitmap should contain
# after the operation concludes. Must be present if a bitmap was
@@ -1596,7 +1613,7 @@
#
# @on-source-error: the action to take on an error on the source,
# default 'report'. 'stop' and 'enospc' can only be used if the
-# block device supports io-status (see BlockInfo).
+# block device supports io-status (see `BlockInfo`).
#
# @on-target-error: the action to take on an error on the target,
# default 'report' (no limitations, since this applies to a
@@ -1606,14 +1623,14 @@
# copy-before-write jobs; defaults to break-guest-write. (Since 10.1)
#
# @auto-finalize: When false, this job will wait in a PENDING state
-# after it has finished its work, waiting for @job-finalize before
+# after it has finished its work, waiting for `job-finalize` before
# making any block graph changes. When true, this job will
# automatically perform its abort or commit actions. Defaults to
# true. (Since 2.12)
#
# @auto-dismiss: When false, this job will wait in a CONCLUDED state
# after it has completely ceased all work, and awaits
-# @job-dismiss. When true, this job will automatically disappear
+# `job-dismiss`. When true, this job will automatically disappear
# without user intervention. Defaults to true. (Since 2.12)
#
# @filter-node-name: the node name that should be assigned to the
@@ -1719,7 +1736,7 @@
#
# @allow-write-only-overlay: If present, the check whether this
# operation is safe was relaxed so that it can be used to change
-# backing file of a destination of a blockdev-mirror. (since 5.0)
+# backing file of a destination of a `blockdev-mirror`. (since 5.0)
#
# Since: 2.5
#
@@ -1784,7 +1801,7 @@
# If top == base, that is an error. If top has no overlays on top of
# it, or if it is in use by a writer, the job will not be completed by
# itself. The user needs to complete the job with the
-# job-complete command after getting the ready event. (Since 2.0)
+# `job-complete` command after getting the ready event. (Since 2.0)
#
# If the base image is smaller than top, then the base image will be
# resized to be the same size as top. If top is smaller than the base
@@ -1846,14 +1863,14 @@
# autogenerated. (Since: 2.9)
#
# @auto-finalize: When false, this job will wait in a PENDING state
-# after it has finished its work, waiting for @job-finalize before
+# after it has finished its work, waiting for `job-finalize` before
# making any block graph changes. When true, this job will
# automatically perform its abort or commit actions. Defaults to
# true. (Since 3.1)
#
# @auto-dismiss: When false, this job will wait in a CONCLUDED state
# after it has completely ceased all work, and awaits
-# @job-dismiss. When true, this job will automatically disappear
+# `job-dismiss`. When true, this job will automatically disappear
# without user intervention. Defaults to true. (Since 3.1)
#
# Features:
@@ -1889,14 +1906,14 @@
# @drive-backup:
#
# Start a point-in-time copy of a block device to a new destination.
-# The status of ongoing drive-backup operations can be checked with
-# query-block-jobs where the BlockJobInfo.type field has the value
+# The status of ongoing `drive-backup` operations can be checked with
+# `query-block-jobs` where the `BlockJobInfo`.type field has the value
# 'backup'. The operation can be stopped before it has completed
-# using the job-cancel or block-job-cancel command.
+# using the `job-cancel` or `block-job-cancel` command.
#
# Features:
#
-# @deprecated: This command is deprecated. Use @blockdev-backup
+# @deprecated: This command is deprecated. Use `blockdev-backup`
# instead.
#
# Errors:
@@ -1920,10 +1937,10 @@
# @blockdev-backup:
#
# Start a point-in-time copy of a block device to a new destination.
-# The status of ongoing blockdev-backup operations can be checked with
-# query-block-jobs where the BlockJobInfo.type field has the value
+# The status of ongoing `blockdev-backup` operations can be checked with
+# `query-block-jobs` where the `BlockJobInfo`.type field has the value
# 'backup'. The operation can be stopped before it has completed
-# using the job-cancel or block-job-cancel command.
+# using the `job-cancel` or `block-job-cancel` command.
#
# Errors:
# - If @device is not a valid block device, DeviceNotFound
@@ -1950,8 +1967,6 @@
# @flat: Omit the nested data about backing image ("backing-image"
# key) if true. Default is false (Since 5.0)
#
-# Returns: the list of BlockDeviceInfo
-#
# Since: 2.0
#
# .. qmp-example::
@@ -2026,7 +2041,7 @@
# @XDbgBlockGraphNode:
#
# @id: Block graph node identifier. This @id is generated only for
-# x-debug-query-block-graph and does not relate to any other
+# `x-debug-query-block-graph` and does not relate to any other
# identifiers in QEMU.
#
# @type: Type of graph node. Can be one of block-backend, block-job
@@ -2075,7 +2090,7 @@
##
# @XDbgBlockGraphEdge:
#
-# Block Graph edge description for x-debug-query-block-graph.
+# Block Graph edge description for `x-debug-query-block-graph`.
#
# @parent: parent id
#
@@ -2193,7 +2208,7 @@
#
# @on-source-error: the action to take on an error on the source,
# default 'report'. 'stop' and 'enospc' can only be used if the
-# block device supports io-status (see BlockInfo).
+# block device supports io-status (see `BlockInfo`).
#
# @on-target-error: the action to take on an error on the target,
# default 'report' (no limitations, since this applies to a
@@ -2209,14 +2224,14 @@
# 'background' (Since: 3.0)
#
# @auto-finalize: When false, this job will wait in a PENDING state
-# after it has finished its work, waiting for @job-finalize before
+# after it has finished its work, waiting for `job-finalize` before
# making any block graph changes. When true, this job will
# automatically perform its abort or commit actions. Defaults to
# true. (Since 3.1)
#
# @auto-dismiss: When false, this job will wait in a CONCLUDED state
# after it has completely ceased all work, and awaits
-# @job-dismiss. When true, this job will automatically disappear
+# `job-dismiss`. When true, this job will automatically disappear
# without user intervention. Defaults to true. (Since 3.1)
#
# Since: 1.3
@@ -2251,16 +2266,16 @@
# @name: name of the dirty bitmap (must be less than 1024 bytes)
#
# @granularity: the bitmap granularity, default is 64k for
-# block-dirty-bitmap-add
+# `block-dirty-bitmap-add`
#
# @persistent: the bitmap is persistent, i.e. it will be saved to the
# corresponding block device image file on its close. For now
# only Qcow2 disks support persistent bitmaps. Default is false
-# for block-dirty-bitmap-add. (Since: 2.10)
+# for `block-dirty-bitmap-add`. (Since: 2.10)
#
# @disabled: the bitmap is created in the disabled state, which means
# that it will not track drive changes. The bitmap may be enabled
-# with block-dirty-bitmap-enable. Default is false. (Since: 4.0)
+# with `block-dirty-bitmap-enable`. Default is false. (Since: 4.0)
#
# Since: 2.4
##
@@ -2290,7 +2305,7 @@
# @target: name of the destination dirty bitmap
#
# @bitmaps: name(s) of the source dirty bitmap(s) at @node and/or
-# fully specified BlockDirtyBitmap elements. The latter are
+# fully specified `BlockDirtyBitmap` elements. The latter are
# supported since 4.1.
#
# Since: 4.0
@@ -2325,7 +2340,7 @@
# @block-dirty-bitmap-remove:
#
# Stop write tracking and remove the dirty bitmap that was created
-# with block-dirty-bitmap-add. If the bitmap is persistent, remove it
+# with `block-dirty-bitmap-add`. If the bitmap is persistent, remove it
# from its storage too.
#
# Errors:
@@ -2464,9 +2479,6 @@
#
# @unstable: This command is meant for debugging.
#
-# Returns:
-# BlockDirtyBitmapSha256
-#
# Errors:
# - If @node is not a valid block device, DeviceNotFound
# - If @name is not found or if hashing has failed, GenericError
@@ -2512,7 +2524,7 @@
#
# @on-source-error: the action to take on an error on the source,
# default 'report'. 'stop' and 'enospc' can only be used if the
-# block device supports io-status (see BlockInfo).
+# block device supports io-status (see `BlockInfo`).
#
# @on-target-error: the action to take on an error on the target,
# default 'report' (no limitations, since this applies to a
@@ -2527,14 +2539,14 @@
# 'background' (Since: 3.0)
#
# @auto-finalize: When false, this job will wait in a PENDING state
-# after it has finished its work, waiting for @job-finalize before
+# after it has finished its work, waiting for `job-finalize` before
# making any block graph changes. When true, this job will
# automatically perform its abort or commit actions. Defaults to
# true. (Since 3.1)
#
# @auto-dismiss: When false, this job will wait in a CONCLUDED state
# after it has completely ceased all work, and awaits
-# @job-dismiss. When true, this job will automatically disappear
+# `job-dismiss`. When true, this job will automatically disappear
# without user intervention. Defaults to true. (Since 3.1)
#
# @target-is-zero: Assume the destination reads as all zeroes before
@@ -2782,9 +2794,9 @@
# The block streaming operation is performed in the background until
# the entire backing file has been copied. This command returns
# immediately once streaming has started. The status of ongoing block
-# streaming operations can be checked with query-block-jobs. The
+# streaming operations can be checked with `query-block-jobs`. The
# operation can be stopped before it has completed using the
-# job-cancel or block-job-cancel command.
+# `job-cancel` or `block-job-cancel` command.
#
# The node that receives the data is called the top image, can be
# located in any part of the chain (but always above the base image;
@@ -2803,9 +2815,9 @@
# will be the new backing file.
#
# On successful completion the image file is updated to drop the
-# backing file and the BLOCK_JOB_COMPLETED event is emitted.
+# backing file and the `BLOCK_JOB_COMPLETED` event is emitted.
#
-# In case @device is a filter node, block-stream modifies the first
+# In case @device is a filter node, `block-stream` modifies the first
# non-filter overlay node below it to point to the new backing node
# instead of modifying @device itself.
#
@@ -2846,7 +2858,7 @@
#
# @on-error: the action to take on an error (default report). 'stop'
# and 'enospc' can only be used if the block device supports
-# io-status (see BlockInfo). (Since 1.3)
+# io-status (see `BlockInfo`). (Since 1.3)
#
# @filter-node-name: the node name that should be assigned to the
# filter driver that the stream job inserts into the graph above
@@ -2854,14 +2866,14 @@
# autogenerated. (Since: 6.0)
#
# @auto-finalize: When false, this job will wait in a PENDING state
-# after it has finished its work, waiting for @job-finalize before
+# after it has finished its work, waiting for `job-finalize` before
# making any block graph changes. When true, this job will
# automatically perform its abort or commit actions. Defaults to
# true. (Since 3.1)
#
# @auto-dismiss: When false, this job will wait in a CONCLUDED state
# after it has completely ceased all work, and awaits
-# @job-dismiss. When true, this job will automatically disappear
+# `job-dismiss`. When true, this job will automatically disappear
# without user intervention. Defaults to true. (Since 3.1)
#
# Errors:
@@ -2922,13 +2934,13 @@
# command if no operation is in progress.
#
# The operation will cancel as soon as possible and then emit the
-# BLOCK_JOB_CANCELLED event. Before that happens the job is still
-# visible when enumerated using query-block-jobs.
+# `BLOCK_JOB_CANCELLED` event. Before that happens the job is still
+# visible when enumerated using `query-block-jobs`.
#
-# Note that if you issue 'block-job-cancel' after 'drive-mirror' has
-# indicated (via the event BLOCK_JOB_READY) that the source and
+# Note that if you issue `block-job-cancel` after `drive-mirror` has
+# indicated (via the event `BLOCK_JOB_READY`) that the source and
# destination are synchronized, then the event triggered by this
-# command changes to BLOCK_JOB_COMPLETED, to indicate that the
+# command changes to `BLOCK_JOB_COMPLETED`, to indicate that the
# mirroring has ended and the destination now has a point-in-time copy
# tied to the time of the cancellation.
#
@@ -2942,7 +2954,7 @@
# values.
#
# @force: If true, and the job has already emitted the event
-# BLOCK_JOB_READY, abandon the job immediately (even if it is
+# `BLOCK_JOB_READY`, abandon the job immediately (even if it is
# paused) instead of waiting for the destination to complete its
# final synchronization (since 1.3)
#
@@ -2965,7 +2977,7 @@
#
# 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.
+# READY. The corresponding `JOB_STATUS_CHANGE` event will be emitted.
#
# Cancelling a paused job automatically resumes it.
#
@@ -2975,7 +2987,7 @@
#
# Features:
#
-# @deprecated: This command is deprecated. Use @job-pause
+# @deprecated: This command is deprecated. Use `job-pause`
# instead.
#
# Errors:
@@ -3004,7 +3016,7 @@
#
# Features:
#
-# @deprecated: This command is deprecated. Use @job-resume
+# @deprecated: This command is deprecated. Use `job-resume`
# instead.
#
# Errors:
@@ -3025,14 +3037,14 @@
#
# This is supported only for drive mirroring, where it also switches
# the device to write to the target path only. Note that drive
-# mirroring includes drive-mirror, blockdev-mirror and block-commit
+# mirroring includes `drive-mirror`, `blockdev-mirror` and `block-commit`
# job (only in case of "active commit", when the node being commited
# is used by the guest). The ability to complete is signaled with a
-# BLOCK_JOB_READY event.
+# `BLOCK_JOB_READY` event.
#
# This command completes an active background block operation
# synchronously. The ordering of this command's return with the
-# BLOCK_JOB_COMPLETED event is not defined. Note that if an I/O error
+# `BLOCK_JOB_COMPLETED` event is not defined. Note that if an I/O error
# occurs during the processing of this command: 1) the command itself
# will fail; 2) the error will be processed according to the
# rerror/werror arguments that were specified when starting the
@@ -3044,7 +3056,7 @@
#
# Features:
#
-# @deprecated: This command is deprecated. Use @job-complete
+# @deprecated: This command is deprecated. Use `job-complete`
# instead.
#
# Errors:
@@ -3063,21 +3075,21 @@
# 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. In turn, automatic dismiss may be enabled only
-# for jobs that have @auto-dismiss option, which are drive-backup,
-# blockdev-backup, drive-mirror, blockdev-mirror, block-commit and
-# block-stream. @auto-dismiss is enabled by default for these
+# for jobs that have @auto-dismiss option, which are `drive-backup`,
+# `blockdev-backup`, `drive-mirror`, `blockdev-mirror`, `block-commit` and
+# `block-stream`. @auto-dismiss is enabled by default for these
# jobs.
#
# This command will refuse to operate on any job that has not yet
# reached its terminal state, CONCLUDED. For jobs that make use of
-# the BLOCK_JOB_READY event, job-cancel, block-job-cancel or
-# job-complete will still need to be used as appropriate.
+# the `BLOCK_JOB_READY` event, `job-cancel`, `block-job-cancel` or
+# `job-complete` will still need to be used as appropriate.
#
# @id: The job identifier.
#
# Features:
#
-# @deprecated: This command is deprecated. Use @job-dismiss
+# @deprecated: This command is deprecated. Use `job-dismiss`
# instead.
#
# Since: 2.12
@@ -3105,7 +3117,7 @@
#
# Features:
#
-# @deprecated: This command is deprecated. Use @job-finalize
+# @deprecated: This command is deprecated. Use `job-finalize`
# instead.
#
# Since: 2.12
@@ -3177,7 +3189,7 @@
# @on: Enabled
#
# @unmap: Enabled and even try to unmap blocks if possible. This
-# requires also that @BlockdevDiscardOptions is set to unmap for
+# requires also that `BlockdevDiscardOptions` is set to unmap for
# this device.
#
# Since: 2.1
@@ -4719,7 +4731,7 @@
# @driver: block driver name
#
# @node-name: the node name of the new node. This option is required
-# on the top level of blockdev-add. Valid node names start with
+# on the top level of `blockdev-add`. Valid node names start with
# an alphabetic character and may contain only alphanumeric
# characters, '-', '.' and '_'. Their maximum length is 31
# characters. (Since 2.0)
@@ -4923,7 +4935,7 @@
# cancelled.
#
# The command receives a list of block devices to reopen. For each
-# one of them, the top-level @node-name option (from BlockdevOptions)
+# one of them, the top-level @node-name option (from `BlockdevOptions`)
# must be specified and is used to select the block device to be
# reopened. Other @node-name options must be either omitted or set to
# the current name of the appropriate node. This command won't change
@@ -4932,7 +4944,7 @@
# In the case of options that refer to child nodes, the behavior of
# this command depends on the value:
#
-# 1) A set of options (BlockdevOptions): the child is reopened with
+# 1) A set of options (`BlockdevOptions`): the child is reopened with
# the specified set of options.
#
# 2) A reference to the current child: the child is reopened using
@@ -4946,7 +4958,7 @@
# Options (1) and (2) are supported in all cases. Option (3) is
# supported for @file and @backing, and option (4) for @backing only.
#
-# Unlike with blockdev-add, the @backing option must always be present
+# Unlike with `blockdev-add`, the @backing option must always be present
# unless the node being reopened does not have a backing file and its
# image does not have a default backing file name as part of its
# metadata.
@@ -4960,7 +4972,7 @@
##
# @blockdev-del:
#
-# Deletes a block device that has been added using blockdev-add. The
+# Deletes a block device that has been added using `blockdev-add`. The
# command will fail if the node is attached to a device or is
# otherwise being used.
#
@@ -5515,7 +5527,7 @@
# @blockdev-create:
#
# Starts a job to create an image format on a given node. The job is
-# automatically finalized, but a manual job-dismiss is required.
+# automatically finalized, but a manual `job-dismiss` is required.
#
# @job-id: Identifier for the newly created job.
#
@@ -5575,7 +5587,7 @@
#
# Starts a job to amend format specific options of an existing open
# block device. The job is automatically finalized, but a manual
-# job-dismiss is required.
+# `job-dismiss` is required.
#
# @job-id: Identifier for the newly created job.
#
@@ -5644,10 +5656,10 @@
#
# @fatal: if set, the image is marked corrupt and therefore unusable
# after this event and must be repaired (Since 2.2; before, every
-# BLOCK_IMAGE_CORRUPTED event was fatal)
+# `BLOCK_IMAGE_CORRUPTED` event was fatal)
#
-# .. note:: If action is "stop", a STOP event will eventually follow
-# the BLOCK_IO_ERROR event.
+# .. note:: If action is "stop", a `STOP` event will eventually follow
+# the `BLOCK_IO_ERROR` event.
#
# .. qmp-example::
#
@@ -5688,15 +5700,15 @@
#
# @nospace: true if I/O error was caused due to a no-space condition.
# This key is only present if query-block's io-status is present,
-# please see query-block documentation for more information
+# please see `query-block` documentation for more information
# (since: 2.2)
#
# @reason: human readable string describing the error cause. (This
# field is a debugging aid for humans, it should not be parsed by
# applications) (since: 2.2)
#
-# .. note:: If action is "stop", a STOP event will eventually follow
-# the BLOCK_IO_ERROR event.
+# .. note:: If action is "stop", a `STOP` event will eventually follow
+# the `BLOCK_IO_ERROR` event.
#
# .. note:: This event is rate-limited.
#
@@ -5838,7 +5850,7 @@
# @speed: rate limit, bytes per second
#
# .. note:: The "ready to complete" status is always reset by a
-# @BLOCK_JOB_ERROR event.
+# `BLOCK_JOB_ERROR` event.
#
# Since: 1.3
#
@@ -5860,7 +5872,7 @@
# @BLOCK_JOB_PENDING:
#
# Emitted when a block job is awaiting explicit authorization to
-# finalize graph changes via @job-finalize. If this job is part
+# finalize graph changes via `job-finalize`. If this job is part
# of a transaction, it will not emit this event until the transaction
# has converged first.
#
@@ -5909,7 +5921,7 @@
# configured write threshold. For thin-provisioned devices, this
# means the device should be extended to avoid pausing for disk
# exhaustion. The event is one shot. Once triggered, it needs to be
-# re-registered with another block-set-write-threshold command.
+# re-registered with another `block-set-write-threshold` command.
#
# @node-name: graph node name on which the threshold was exceeded.
#
@@ -5980,7 +5992,7 @@
#
# TODO: Removing children from a quorum node means introducing
# gaps in the child indices. This cannot be represented in the
-# 'children' list of BlockdevOptionsQuorum, as returned by
+# 'children' list of `BlockdevOptionsQuorum`, as returned by
# .bdrv_refresh_filename().
#
# Since: 2.7
@@ -6193,7 +6205,7 @@
# Synchronously delete an internal snapshot of a block device, when
# the format of the image used support it. The snapshot is identified
# by name or id or both. One of the name or id is required. Return
-# SnapshotInfo for the successfully deleted snapshot.
+# `SnapshotInfo` for the successfully deleted snapshot.
#
# @device: the device name or node-name of a root node to delete the
# snapshot from
@@ -6202,9 +6214,6 @@
#
# @name: optional the snapshot's name to be deleted
#
-# Returns:
-# SnapshotInfo
-#
# Errors:
# - If @device is not a valid block device, GenericError
# - If snapshot not found, GenericError
diff --git a/qapi/block-export.json b/qapi/block-export.json
index ed4deb5..6878b89 100644
--- a/qapi/block-export.json
+++ b/qapi/block-export.json
@@ -2,7 +2,8 @@
# vim: filetype=python
##
-# == Block device exports
+# Block device exports
+# ====================
##
{ 'include': 'sockets.json' }
@@ -37,9 +38,9 @@
##
# @NbdServerOptions:
#
-# Keep this type consistent with the NbdServerOptionsLegacy type. The
-# only intended difference is using SocketAddress instead of
-# SocketAddressLegacy.
+# Keep this type consistent with the `NbdServerOptionsLegacy` type. The
+# only intended difference is using `SocketAddress` instead of
+# `SocketAddressLegacy`.
#
# @addr: Address on which to listen (since 4.2).
##
@@ -50,9 +51,9 @@
##
# @NbdServerOptionsLegacy:
#
-# Keep this type consistent with the NbdServerOptions type. The only
-# intended difference is using SocketAddressLegacy instead of
-# SocketAddress.
+# Keep this type consistent with the `NbdServerOptions` type. The only
+# intended difference is using `SocketAddressLegacy` instead of
+# `SocketAddress`.
#
# @addr: Address on which to listen (since 1.3).
##
@@ -64,7 +65,7 @@
# @nbd-server-start:
#
# Start an NBD server listening on the given host and port. Block
-# devices can then be exported using @nbd-server-add. The NBD server
+# devices can then be exported using `nbd-server-add`. The NBD server
# will present them as named exports; for example, another QEMU
# instance could refer to them as "nbd:HOST:PORT:exportname=NAME".
#
@@ -80,8 +81,8 @@
##
# @BlockExportOptionsNbdBase:
#
-# An NBD block export (common options shared between nbd-server-add
-# and the NBD branch of block-export-add).
+# An NBD block export (common options shared between `nbd-server-add`
+# and the NBD branch of `block-export-add`).
#
# @name: Export name. If unspecified, the @device parameter is used
# as the export name. (Since 2.12)
@@ -98,7 +99,7 @@
# @BlockExportOptionsNbd:
#
# An NBD block export (distinct options used in the NBD branch of
-# block-export-add).
+# `block-export-add`).
#
# @bitmaps: Also export each of the named dirty bitmaps reachable from
# @device, so the NBD client can use NBD_OPT_SET_META_CONTEXT with
@@ -124,7 +125,7 @@
# A vhost-user-blk block export.
#
# @addr: The vhost-user socket on which to listen. Both 'unix' and
-# 'fd' SocketAddress types are supported. Passed fds must be UNIX
+# 'fd' `SocketAddress` types are supported. Passed fds must be UNIX
# domain sockets.
#
# @logical-block-size: Logical block size in bytes. Defaults to 512
@@ -216,7 +217,7 @@
##
# @NbdServerAddOptions:
#
-# An NBD block export, per legacy nbd-server-add command.
+# An NBD block export, per legacy `nbd-server-add` command.
#
# @device: The device name or node name of the node to be exported
#
@@ -245,7 +246,7 @@
#
# Features:
#
-# @deprecated: This command is deprecated. Use @block-export-add
+# @deprecated: This command is deprecated. Use `block-export-add`
# instead.
#
# Errors:
@@ -288,12 +289,12 @@
#
# @name: Block export id.
#
-# @mode: Mode of command operation. See @BlockExportRemoveMode
+# @mode: Mode of command operation. See `BlockExportRemoveMode`
# description. Default is 'safe'.
#
# Features:
#
-# @deprecated: This command is deprecated. Use @block-export-del
+# @deprecated: This command is deprecated. Use `block-export-del`
# instead.
#
# Errors:
@@ -312,7 +313,7 @@
# @nbd-server-stop:
#
# Stop QEMU's embedded NBD server, and unregister all devices
-# previously added via @nbd-server-add.
+# previously added via `nbd-server-add`.
#
# Since: 1.3
##
@@ -421,7 +422,7 @@
#
# @id: Block export id.
#
-# @mode: Mode of command operation. See @BlockExportRemoveMode
+# @mode: Mode of command operation. See `BlockExportRemoveMode`
# description. Default is 'safe'.
#
# Errors:
@@ -459,7 +460,7 @@
# @node-name: The node name of the block node that is exported
#
# @shutting-down: True if the export is shutting down (e.g. after a
-# block-export-del command, but before the shutdown has completed)
+# `block-export-del` command, but before the shutdown has completed)
#
# Since: 5.2
##
@@ -472,7 +473,7 @@
##
# @query-block-exports:
#
-# Returns: A list of BlockExportInfo describing all block exports
+# Returns: A list describing all block exports
#
# Since: 5.2
##
diff --git a/qapi/block.json b/qapi/block.json
index 1490a1a..46955bb 100644
--- a/qapi/block.json
+++ b/qapi/block.json
@@ -2,13 +2,16 @@
# vim: filetype=python
##
-# = Block devices
+# *************
+# Block devices
+# *************
##
{ 'include': 'block-core.json' }
##
-# == Additional block stuff (VM related)
+# Additional block stuff (VM related)
+# ===================================
##
##
@@ -86,7 +89,7 @@
# Return a list of information about each persistent reservation
# manager.
#
-# Returns: a list of @PRManagerInfo for each persistent reservation
+# Returns: a list of manager info for each persistent reservation
# manager
#
# Since: 3.0
@@ -137,7 +140,7 @@
#
# If the tray was already open before, this will be a no-op.
#
-# Once the tray opens, a DEVICE_TRAY_MOVED event is emitted. There
+# Once the tray opens, a `DEVICE_TRAY_MOVED` event is emitted. There
# are cases in which no such event will be generated, these include:
#
# - if the guest has locked the tray, @force is false and the guest
@@ -296,7 +299,7 @@
# @BlockdevChangeReadOnlyMode:
#
# Specifies the new read-only mode of a block device subject to the
-# @blockdev-change-medium command.
+# `blockdev-change-medium` command.
#
# @retain: Retains the current read-only mode
#
@@ -314,9 +317,9 @@
#
# Changes the medium inserted into a block device by ejecting the
# current medium and loading a new image file which is inserted as the
-# new medium (this command combines blockdev-open-tray,
-# blockdev-remove-medium, blockdev-insert-medium and
-# blockdev-close-tray).
+# new medium (this command combines `blockdev-open-tray`,
+# `blockdev-remove-medium`, `blockdev-insert-medium` and
+# `blockdev-close-tray`).
#
# @device: Block device name
#
@@ -331,7 +334,7 @@
# to 'retain'
#
# @force: if false (the default), an eject request through
-# blockdev-open-tray will be sent to the guest if it has locked
+# `blockdev-open-tray` will be sent to the guest if it has locked
# the tray (and the tray will not be opened immediately); if true,
# the tray will be opened regardless of whether it is locked.
# (since 7.1)
@@ -519,7 +522,7 @@
# @id: The name or QOM path of the guest device.
#
# @boundaries: list of interval boundary values (see description in
-# BlockLatencyHistogramInfo definition). If specified, all
+# `BlockLatencyHistogramInfo` definition). If specified, all
# latency histograms are removed, and empty ones created for all
# io types with intervals corresponding to @boundaries (except for
# io types, for which specific boundaries are set through the
diff --git a/qapi/char.json b/qapi/char.json
index df6e325..f0a53f7 100644
--- a/qapi/char.json
+++ b/qapi/char.json
@@ -3,7 +3,9 @@
#
##
-# = Character devices
+# *****************
+# Character devices
+# *****************
##
{ 'include': 'sockets.json' }
@@ -36,8 +38,6 @@
#
# Return information about current character devices.
#
-# Returns: a list of @ChardevInfo
-#
# Since: 0.14
#
# .. qmp-example::
@@ -82,8 +82,6 @@
#
# Return information about character device backends.
#
-# Returns: a list of @ChardevBackendInfo
-#
# Since: 2.0
#
# .. qmp-example::
@@ -772,8 +770,6 @@
#
# @backend: backend type and parameters
#
-# Returns: ChardevReturn.
-#
# Since: 1.4
#
# .. qmp-example::
@@ -812,8 +808,6 @@
#
# @backend: new backend type and parameters
#
-# Returns: ChardevReturn.
-#
# Since: 2.10
#
# .. qmp-example::
diff --git a/qapi/common.json b/qapi/common.json
index 0e3a0bb..af7e3d6 100644
--- a/qapi/common.json
+++ b/qapi/common.json
@@ -2,7 +2,9 @@
# vim: filetype=python
##
-# = Common data types
+# *****************
+# Common data types
+# *****************
##
##
diff --git a/qapi/compat.json b/qapi/compat.json
index 42034d9..90b8d51 100644
--- a/qapi/compat.json
+++ b/qapi/compat.json
@@ -2,7 +2,9 @@
# vim: filetype=python
##
-# = Compatibility policy
+# ********************
+# Compatibility policy
+# ********************
##
##
diff --git a/qapi/control.json b/qapi/control.json
index 34b733f..9a53021 100644
--- a/qapi/control.json
+++ b/qapi/control.json
@@ -3,7 +3,9 @@
#
##
-# = QMP monitor control
+# *******************
+# QMP monitor control
+# *******************
##
##
@@ -11,7 +13,7 @@
#
# Enable QMP capabilities.
#
-# @enable: An optional list of QMPCapability values to enable. The
+# @enable: An optional list of `QMPCapability` values to enable. The
# client must not enable any capability that is not mentioned in
# the QMP greeting message. If the field is not provided, it
# means no QMP capabilities will be enabled. (since 2.12)
@@ -93,8 +95,7 @@
#
# Return the current version of QEMU.
#
-# Returns: A @VersionInfo object describing the current version of
-# QEMU.
+# Returns: An object describing the current version of QEMU.
#
# Since: 0.14
#
@@ -131,7 +132,7 @@
#
# Return a list of supported QMP commands by this server
#
-# Returns: A list of @CommandInfo for all supported commands
+# Returns: A list of all supported commands
#
# Since: 0.14
#
@@ -158,10 +159,11 @@
##
# @quit:
#
-# This command will cause the QEMU process to exit gracefully. While
-# every attempt is made to send the QMP response before terminating,
-# this is not guaranteed. When using this interface, a premature EOF
-# would not be unexpected.
+# Request graceful QEMU process termination.
+#
+# While every attempt is made to send the QMP response before
+# terminating, this is not guaranteed. When using this interface, a
+# premature EOF would not be unexpected.
#
# Since: 0.14
#
diff --git a/qapi/crypto.json b/qapi/crypto.json
index 9ec6301..ab6eda4 100644
--- a/qapi/crypto.json
+++ b/qapi/crypto.json
@@ -3,7 +3,9 @@
#
##
-# = Cryptography
+# ************
+# Cryptography
+# ************
##
##
@@ -589,9 +591,9 @@
#
# Specific parameters for RSA algorithm.
#
-# @hash-alg: QCryptoHashAlgo
+# @hash-alg: `QCryptoHashAlgo`
#
-# @padding-alg: QCryptoRSAPaddingAlgo
+# @padding-alg: `QCryptoRSAPaddingAlgo`
#
# Since: 7.1
##
diff --git a/qapi/cryptodev.json b/qapi/cryptodev.json
index b13db26..eb309c2 100644
--- a/qapi/cryptodev.json
+++ b/qapi/cryptodev.json
@@ -5,7 +5,9 @@
# See the COPYING file in the top-level directory.
##
-# = Cryptography devices
+# ********************
+# Cryptography devices
+# ********************
##
##
@@ -96,8 +98,6 @@
#
# Return information about current crypto devices.
#
-# Returns: a list of @QCryptodevInfo
-#
# Since: 8.0
##
{ 'command': 'query-cryptodev', 'returns': ['QCryptodevInfo']}
diff --git a/qapi/cxl.json b/qapi/cxl.json
index 8f2e923..52cc5d4 100644
--- a/qapi/cxl.json
+++ b/qapi/cxl.json
@@ -2,7 +2,9 @@
# vim: filetype=python
##
-# = CXL devices
+# ***********
+# CXL devices
+# ***********
##
##
diff --git a/qapi/dump.json b/qapi/dump.json
index d0ba1f0..32c8c1f 100644
--- a/qapi/dump.json
+++ b/qapi/dump.json
@@ -5,7 +5,9 @@
# See the COPYING file in the top-level directory.
##
-# = Dump guest memory
+# *****************
+# Dump guest memory
+# *****************
##
##
@@ -110,7 +112,7 @@
#
# Describe the status of a long-running background guest memory dump.
#
-# @none: no dump-guest-memory has started yet.
+# @none: no `dump-guest-memory` has started yet.
#
# @active: there is one dump running in background.
#
@@ -126,9 +128,9 @@
##
# @DumpQueryResult:
#
-# The result format for 'query-dump'.
+# The result format for `query-dump`.
#
-# @status: enum of @DumpStatus, which shows current dump status
+# @status: enum of `DumpStatus`, which shows current dump status
#
# @completed: bytes written in latest dump (uncompressed)
#
@@ -146,7 +148,7 @@
#
# Query latest dump status.
#
-# Returns: A @DumpStatus object showing the dump status.
+# Returns: An object showing the dump status.
#
# Since: 2.6
#
@@ -184,7 +186,7 @@
##
# @DumpGuestMemoryCapability:
#
-# @formats: the available formats for dump-guest-memory
+# @formats: the available formats for `dump-guest-memory`
#
# Since: 2.0
##
@@ -195,10 +197,9 @@
##
# @query-dump-guest-memory-capability:
#
-# Return the available formats for dump-guest-memory
+# Return the available formats for `dump-guest-memory`
#
-# Returns: A @DumpGuestMemoryCapability object listing available
-# formats for dump-guest-memory
+# Returns: An object listing available formats for `dump-guest-memory`
#
# Since: 2.0
#
diff --git a/qapi/ebpf.json b/qapi/ebpf.json
index db19ae8..f025795 100644
--- a/qapi/ebpf.json
+++ b/qapi/ebpf.json
@@ -5,7 +5,9 @@
# See the COPYING file in the top-level directory.
##
-# = eBPF Objects
+# ************
+# eBPF Objects
+# ************
#
# eBPF object is an ELF binary that contains the eBPF program and eBPF
# map description(BTF). Overall, eBPF object should contain the
@@ -32,7 +34,7 @@
##
# @EbpfProgramID:
#
-# The eBPF programs that can be gotten with request-ebpf.
+# The eBPF programs that can be gotten with `request-ebpf`.
#
# @rss: Receive side scaling, technology that allows steering traffic
# between queues by calculation hash. Users may set up
diff --git a/qapi/error.json b/qapi/error.json
index 135c1e8..54cb02f 100644
--- a/qapi/error.json
+++ b/qapi/error.json
@@ -2,7 +2,9 @@
# vim: filetype=python
##
-# = QMP errors
+# **********
+# QMP errors
+# **********
##
##
diff --git a/qapi/introspect.json b/qapi/introspect.json
index e9e0297..5310071 100644
--- a/qapi/introspect.json
+++ b/qapi/introspect.json
@@ -10,17 +10,19 @@
# See the COPYING file in the top-level directory.
##
-# = QMP introspection
+# *****************
+# QMP introspection
+# *****************
##
##
# @query-qmp-schema:
#
-# Command query-qmp-schema exposes the QMP wire ABI as an array of
-# SchemaInfo. This lets QMP clients figure out what commands and
+# Command `query-qmp-schema` exposes the QMP wire ABI as an array of
+# `SchemaInfo`. This lets QMP clients figure out what commands and
# events are available in this QEMU, and their parameters and results.
#
-# However, the SchemaInfo can't reflect all the rules and restrictions
+# However, the `SchemaInfo` can't reflect all the rules and restrictions
# that apply to QMP. It's interface introspection (figuring out
# what's there), not interface specification. The specification is in
# the QAPI schema.
@@ -34,10 +36,10 @@
# string into a specific enum or from one specific type into an
# alternate that includes the original type alongside something else.
#
-# Returns: array of @SchemaInfo, where each element describes an
-# entity in the ABI: command, event, type, ...
+# Returns: an array where each element describes an entity in the ABI:
+# command, event, type, ...
#
-# The order of the various SchemaInfo is unspecified; however, all
+# The order of the various elements is unspecified; however, all
# names are guaranteed to be unique (no name will be duplicated
# with different meta-types).
#
@@ -54,7 +56,7 @@
##
# @SchemaMetaType:
#
-# This is a @SchemaInfo's meta type, i.e. the kind of entity it
+# This is a `SchemaInfo`'s meta type, i.e. the kind of entity it
# describes.
#
# @builtin: a predefined type such as 'int' or 'bool'.
@@ -80,7 +82,7 @@
##
# @SchemaInfo:
#
-# @name: the entity's name, inherited from @base. The SchemaInfo is
+# @name: the entity's name, inherited from @base. The `SchemaInfo` is
# always referenced by this name. Commands and events have the
# name defined in the QAPI schema. Unlike command and event
# names, type names are not part of the wire ABI. Consequently,
@@ -111,7 +113,7 @@
##
# @SchemaInfoBuiltin:
#
-# Additional SchemaInfo members for meta-type 'builtin'.
+# Additional `SchemaInfo` members for meta-type 'builtin'.
#
# @json-type: the JSON type used for this type on the wire.
#
@@ -152,7 +154,7 @@
##
# @SchemaInfoEnum:
#
-# Additional SchemaInfo members for meta-type 'enum'.
+# Additional `SchemaInfo` members for meta-type 'enum'.
#
# @members: the enum type's members, in no particular order.
# (since 6.2)
@@ -192,7 +194,7 @@
##
# @SchemaInfoArray:
#
-# Additional SchemaInfo members for meta-type 'array'.
+# Additional `SchemaInfo` members for meta-type 'array'.
#
# @element-type: the array type's element type.
#
@@ -206,7 +208,7 @@
##
# @SchemaInfoObject:
#
-# Additional SchemaInfo members for meta-type 'object'.
+# Additional `SchemaInfo` members for meta-type 'object'.
#
# @members: the object type's (non-variant) members, in no particular
# order.
@@ -271,7 +273,7 @@
##
# @SchemaInfoAlternate:
#
-# Additional SchemaInfo members for meta-type 'alternate'.
+# Additional `SchemaInfo` members for meta-type 'alternate'.
#
# @members: the alternate type's members, in no particular order. The
# members' wire encoding is distinct, see
@@ -299,7 +301,7 @@
##
# @SchemaInfoCommand:
#
-# Additional SchemaInfo members for meta-type 'command'.
+# Additional `SchemaInfo` members for meta-type 'command'.
#
# @arg-type: the name of the object type that provides the command's
# parameters.
@@ -321,7 +323,7 @@
##
# @SchemaInfoEvent:
#
-# Additional SchemaInfo members for meta-type 'event'.
+# Additional `SchemaInfo` members for meta-type 'event'.
#
# @arg-type: the name of the object type that provides the event's
# parameters.
diff --git a/qapi/job.json b/qapi/job.json
index 126fa5c..8b08350 100644
--- a/qapi/job.json
+++ b/qapi/job.json
@@ -2,7 +2,9 @@
# vim: filetype=python
##
-# = Background jobs
+# ***************
+# Background jobs
+# ***************
##
##
@@ -10,26 +12,26 @@
#
# Type of a background job.
#
-# @commit: block commit job type, see "block-commit"
+# @commit: block commit job type, see `block-commit`
#
-# @stream: block stream job type, see "block-stream"
+# @stream: block stream job type, see `block-stream`
#
-# @mirror: drive mirror job type, see "drive-mirror"
+# @mirror: drive mirror job type, see `drive-mirror`
#
-# @backup: drive backup job type, see "drive-backup"
+# @backup: drive backup job type, see `drive-backup`
#
-# @create: image creation job type, see "blockdev-create" (since 3.0)
+# @create: image creation job type, see `blockdev-create` (since 3.0)
#
-# @amend: image options amend job type, see "x-blockdev-amend"
+# @amend: image options amend job type, see `x-blockdev-amend`
# (since 5.1)
#
-# @snapshot-load: snapshot load job type, see "snapshot-load"
+# @snapshot-load: snapshot load job type, see `snapshot-load`
# (since 6.0)
#
-# @snapshot-save: snapshot save job type, see "snapshot-save"
+# @snapshot-save: snapshot save job type, see `snapshot-save`
# (since 6.0)
#
-# @snapshot-delete: snapshot delete job type, see "snapshot-delete"
+# @snapshot-delete: snapshot delete job type, see `snapshot-delete`
# (since 6.0)
#
# Since: 1.7
@@ -65,7 +67,7 @@
#
# @pending: The job has finished its work, but has finalization steps
# that it needs to make prior to completing. These changes will
-# require manual intervention via @job-finalize if auto-finalize
+# require manual intervention via `job-finalize` if auto-finalize
# was set to false. These pending changes may still fail.
#
# @aborting: The job is in the process of being aborted, and will
@@ -75,7 +77,7 @@
#
# @concluded: The job has finished all work. If auto-dismiss was set
# to false, the job will remain in this state until it is
-# dismissed via @job-dismiss.
+# dismissed via `job-dismiss`.
#
# @null: The job is in the process of being dismantled. This state
# should not ever be visible externally.
@@ -91,21 +93,21 @@
#
# Represents command verbs that can be applied to a job.
#
-# @cancel: see @job-cancel
+# @cancel: see `job-cancel`
#
-# @pause: see @job-pause
+# @pause: see `job-pause`
#
-# @resume: see @job-resume
+# @resume: see `job-resume`
#
-# @set-speed: see @block-job-set-speed
+# @set-speed: see `block-job-set-speed`
#
-# @complete: see @job-complete
+# @complete: see `job-complete`
#
-# @dismiss: see @job-dismiss
+# @dismiss: see `job-dismiss`
#
-# @finalize: see @job-finalize
+# @finalize: see `job-finalize`
#
-# @change: see @block-job-change (since 8.2)
+# @change: see `block-job-change` (since 8.2)
#
# Since: 2.12
##
@@ -138,7 +140,7 @@
#
# 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.
+# READY. The corresponding `JOB_STATUS_CHANGE` event will be emitted.
#
# Cancelling a paused job automatically resumes it.
#
@@ -173,7 +175,7 @@
# cancellation.
#
# The job will cancel as soon as possible and then emit a
-# JOB_STATUS_CHANGE event. Usually, the status will change to
+# `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.
@@ -192,14 +194,14 @@
#
# This is supported only for drive mirroring, where it also switches
# the device to write to the target path only. Note that drive
-# mirroring includes drive-mirror, blockdev-mirror and block-commit
+# mirroring includes `drive-mirror`, `blockdev-mirror` and `block-commit`
# job (only in case of "active commit", when the node being commited
# is used by the guest). The ability to complete is signaled with a
-# BLOCK_JOB_READY event.
+# `BLOCK_JOB_READY` event.
#
# This command completes an active background block operation
# synchronously. The ordering of this command's return with the
-# BLOCK_JOB_COMPLETED event is not defined. Note that if an I/O error
+# `BLOCK_JOB_COMPLETED` event is not defined. Note that if an I/O error
# occurs during the processing of this command: 1) the command itself
# will fail; 2) the error will be processed according to the
# rerror/werror arguments that were specified when starting the
@@ -217,14 +219,14 @@
# 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. In turn, automatic dismiss may be enabled only
-# for jobs that have @auto-dismiss option, which are drive-backup,
-# blockdev-backup, drive-mirror, blockdev-mirror, block-commit and
-# block-stream. @auto-dismiss is enabled by default for these
+# for jobs that have @auto-dismiss option, which are `drive-backup`,
+# `blockdev-backup`, `drive-mirror`, `blockdev-mirror`, `block-commit` and
+# `block-stream`. @auto-dismiss is enabled by default for these
# jobs.
#
# This command will refuse to operate on any job that has not yet
# reached its terminal state, CONCLUDED. For jobs that make use of
-# the JOB_READY event, job-cancel or job-complete will still need to
+# the JOB_READY event, `job-cancel` or `job-complete` will still need to
# be used as appropriate.
#
# @id: The job identifier.
@@ -295,7 +297,7 @@
#
# Return information about jobs.
#
-# Returns: a list with a @JobInfo for each active job
+# Returns: a list with info for each active job
#
# Since: 3.0
##
diff --git a/qapi/machine-common.json b/qapi/machine-common.json
index 298e51f..ed3d20a 100644
--- a/qapi/machine-common.json
+++ b/qapi/machine-common.json
@@ -5,7 +5,9 @@
# See the COPYING file in the top-level directory.
##
-# = Common machine types
+# ********************
+# Common machine types
+# ********************
##
##
@@ -26,29 +28,29 @@
#
# @thread: thread level, which would also be called SMT level or
# logical processor level. The @threads option in
-# SMPConfiguration is used to configure the topology of this
+# `SMPConfiguration` is used to configure the topology of this
# level.
#
-# @core: core level. The @cores option in SMPConfiguration is used
+# @core: core level. The @cores option in `SMPConfiguration` is used
# to configure the topology of this level.
#
-# @module: module level. The @modules option in SMPConfiguration is
+# @module: module level. The @modules option in `SMPConfiguration` is
# used to configure the topology of this level.
#
-# @cluster: cluster level. The @clusters option in SMPConfiguration
+# @cluster: cluster level. The @clusters option in `SMPConfiguration`
# is used to configure the topology of this level.
#
-# @die: die level. The @dies option in SMPConfiguration is used to
+# @die: die level. The @dies option in `SMPConfiguration` is used to
# configure the topology of this level.
#
# @socket: socket level, which would also be called package level.
-# The @sockets option in SMPConfiguration is used to configure
+# The @sockets option in `SMPConfiguration` is used to configure
# the topology of this level.
#
-# @book: book level. The @books option in SMPConfiguration is used
+# @book: book level. The @books option in `SMPConfiguration` is used
# to configure the topology of this level.
#
-# @drawer: drawer level. The @drawers option in SMPConfiguration is
+# @drawer: drawer level. The @drawers option in `SMPConfiguration` is
# used to configure the topology of this level.
#
# @default: default level. Some architectures will have default
@@ -102,9 +104,9 @@
##
# @SmpCachePropertiesWrapper:
#
-# List wrapper of SmpCacheProperties.
+# List wrapper of `SmpCacheProperties`.
#
-# @caches: the list of SmpCacheProperties.
+# @caches: the list of `SmpCacheProperties`.
#
# Since 9.2
##
diff --git a/qapi/machine.json b/qapi/machine.json
index f712e7d..6f59f70 100644
--- a/qapi/machine.json
+++ b/qapi/machine.json
@@ -5,7 +5,9 @@
# See the COPYING file in the top-level directory.
##
-# = Machines
+# ********
+# Machines
+# ********
##
{ 'include': 'common.json' }
@@ -76,6 +78,8 @@
#
# @cpu-index: index of the virtual CPU
#
+# @qom-type: QOM type name of the CPU (since 10.1)
+#
# @qom-path: path to the CPU object in the QOM tree
#
# @thread-id: ID of the underlying host thread
@@ -89,6 +93,7 @@
##
{ 'union' : 'CpuInfoFast',
'base' : { 'cpu-index' : 'int',
+ 'qom-type' : 'str',
'qom-path' : 'str',
'thread-id' : 'int',
'*props' : 'CpuInstanceProperties',
@@ -101,8 +106,6 @@
#
# Return information about all virtual CPUs.
#
-# Returns: list of @CpuInfoFast
-#
# Since: 2.12
#
# .. qmp-example::
@@ -188,7 +191,7 @@
# @acpi: machine type supports ACPI (since 8.0)
#
# @compat-props: The machine type's compatibility properties. Only
-# present when query-machines argument @compat-props is true.
+# present when `query-machines` argument @compat-props is true.
# (since 9.1)
#
# Features:
@@ -218,8 +221,6 @@
#
# @unstable: Argument @compat-props is experimental.
#
-# Returns: a list of MachineInfo
-#
# Since: 1.2
#
# .. qmp-example::
@@ -268,8 +269,6 @@
#
# Return information on the current virtual machine.
#
-# Returns: CurrentMachineParams
-#
# Since: 4.0
##
{ 'command': 'query-current-machine', 'returns': 'CurrentMachineParams' }
@@ -291,8 +290,6 @@
#
# Return information about the target for this QEMU
#
-# Returns: QemuTargetInfo
-#
# Since: 1.2
##
{ 'command': 'query-target', 'returns': 'QemuTargetInfo' }
@@ -316,8 +313,6 @@
#
# Query the guest UUID information.
#
-# Returns: The @UuidInfo for the guest
-#
# Since: 0.14
#
# .. qmp-example::
@@ -385,7 +380,7 @@
#
# Wake up guest from suspend. If the guest has wake-up from suspend
# support enabled (wakeup-suspend-support flag from
-# query-current-machine), wake-up guest from suspend if the guest is
+# `query-current-machine`), wake-up guest from suspend if the guest is
# in SUSPENDED state. Return an error otherwise.
#
# Since: 1.1
@@ -452,35 +447,6 @@
{ 'command': 'inject-nmi' }
##
-# @KvmInfo:
-#
-# Information about support for KVM acceleration
-#
-# @enabled: true if KVM acceleration is active
-#
-# @present: true if KVM acceleration is built into this executable
-#
-# Since: 0.14
-##
-{ 'struct': 'KvmInfo', 'data': {'enabled': 'bool', 'present': 'bool'} }
-
-##
-# @query-kvm:
-#
-# Return information about KVM acceleration
-#
-# Returns: @KvmInfo
-#
-# Since: 0.14
-#
-# .. qmp-example::
-#
-# -> { "execute": "query-kvm" }
-# <- { "return": { "enabled": true, "present": true } }
-##
-{ 'command': 'query-kvm', 'returns': 'KvmInfo' }
-
-##
# @NumaOptionsType:
#
# @node: NUMA nodes configuration
@@ -599,7 +565,7 @@
#
# List of CXL Fixed Memory Windows.
#
-# @cxl-fmw: List of CXLFixedMemoryWindowOptions
+# @cxl-fmw: List of `CXLFixedMemoryWindowOptions`
#
# Since: 7.1
##
@@ -654,10 +620,10 @@
##
# @NumaCpuOptions:
#
-# Option "-numa cpu" overrides default cpu to node mapping. It
-# accepts the same set of cpu properties as returned by
-# query-hotpluggable-cpus[].props, where node-id could be used to
-# override default node mapping.
+# Option "-numa cpu" overrides default cpu to node mapping. It accepts
+# the same set of cpu properties as returned by
+# `query-hotpluggable-cpus[].props <query-hotpluggable-cpus>`, where
+# node-id could be used to override default node mapping.
#
# Since: 2.10
##
@@ -671,7 +637,7 @@
# The memory hierarchy in the System Locality Latency and Bandwidth
# Information Structure of HMAT (Heterogeneous Memory Attribute Table)
#
-# For more information about @HmatLBMemoryHierarchy, see chapter
+# For more information about `HmatLBMemoryHierarchy`, see chapter
# 5.2.27.4: Table 5-146: Field "Flags" of ACPI 6.3 spec.
#
# @memory: the structure represents the memory performance
@@ -693,7 +659,7 @@
# Data type in the System Locality Latency and Bandwidth Information
# Structure of HMAT (Heterogeneous Memory Attribute Table)
#
-# For more information about @HmatLBDataType, see chapter 5.2.27.4:
+# For more information about `HmatLBDataType`, see chapter 5.2.27.4:
# Table 5-146: Field "Data Type" of ACPI 6.3 spec.
#
# @access-latency: access latency (nanoseconds)
@@ -720,7 +686,7 @@
# Set the system locality latency and bandwidth information between
# Initiator and Target proximity Domains.
#
-# For more information about @NumaHmatLBOptions, see chapter 5.2.27.4:
+# For more information about `NumaHmatLBOptions`, see chapter 5.2.27.4:
# Table 5-146 of ACPI 6.3 spec.
#
# @initiator: the Initiator Proximity Domain.
@@ -756,7 +722,7 @@
# Cache associativity in the Memory Side Cache Information Structure
# of HMAT
#
-# For more information of @HmatCacheAssociativity, see chapter
+# For more information of `HmatCacheAssociativity`, see chapter
# 5.2.27.5: Table 5-147 of ACPI 6.3 spec.
#
# @none: None (no memory side cache in this proximity domain, or cache
@@ -777,7 +743,7 @@
# Cache write policy in the Memory Side Cache Information Structure of
# HMAT
#
-# For more information of @HmatCacheWritePolicy, see chapter 5.2.27.5:
+# For more information of `HmatCacheWritePolicy`, see chapter 5.2.27.5:
# Table 5-147: Field "Cache Attributes" of ACPI 6.3 spec.
#
# @none: None (no memory side cache in this proximity domain, or cache
@@ -797,7 +763,7 @@
#
# Set the memory side cache information for a given memory domain.
#
-# For more information of @NumaHmatCacheOptions, see chapter 5.2.27.5:
+# For more information of `NumaHmatCacheOptions`, see chapter 5.2.27.5:
# Table 5-147: Field "Cache Attributes" of ACPI 6.3 spec.
#
# @node-id: the memory proximity domain to which the memory belongs.
@@ -932,8 +898,6 @@
#
# Return information for all memory backends.
#
-# Returns: a list of @Memdev.
-#
# Since: 2.1
#
# .. qmp-example::
@@ -976,7 +940,7 @@
#
# The ids other than the node-id specify the position of the CPU
# within the CPU topology (as defined by the machine property "smp",
-# thus see also type @SMPConfiguration)
+# thus see also type `SMPConfiguration`)
#
# @node-id: NUMA node ID the CPU belongs to
#
@@ -1004,7 +968,7 @@
# Since: 2.7
##
{ 'struct': 'CpuInstanceProperties',
- # Keep these in sync with the properties device_add accepts
+ # Keep these in sync with the properties `device_add` accepts
'data': { '*node-id': 'int',
'*drawer-id': 'int',
'*book-id': 'int',
@@ -1020,19 +984,19 @@
##
# @HotpluggableCPU:
#
-# @type: CPU object type for usage with device_add command
+# @type: CPU object type for usage with `device_add` command
#
# @props: list of properties to pass for hotplugging a CPU with
-# device_add
+# `device_add`
#
-# @vcpus-count: number of logical VCPU threads @HotpluggableCPU
+# @vcpus-count: number of logical VCPU threads `HotpluggableCPU`
# provides
#
# @qom-path: link to existing CPU object if CPU is present or omitted
# if CPU is not present.
#
# .. note:: Management should be prepared to pass through additional
-# properties with device_add.
+# properties with `device_add`.
#
# Since: 2.7
##
@@ -1049,8 +1013,6 @@
#
# TODO: Better documentation; currently there is none.
#
-# Returns: a list of HotpluggableCPU objects.
-#
# Since: 2.7
#
# .. qmp-example::
@@ -1172,9 +1134,6 @@
#
# Return information about the balloon device.
#
-# Returns:
-# @BalloonInfo
-#
# Errors:
# - If the balloon driver is enabled but not functional because
# the KVM kernel module cannot support it, KVMMissingCap
@@ -1196,7 +1155,7 @@
# @BALLOON_CHANGE:
#
# Emitted when the guest changes the actual BALLOON level. This value
-# is equivalent to the @actual field return by the 'query-balloon'
+# is equivalent to the @actual field return by the `query-balloon`
# command
#
# @actual: the logical size of the VM in bytes. Formula used:
@@ -1238,9 +1197,6 @@
# Return the hv-balloon driver data contained in the last received
# "STATUS" message from the guest.
#
-# Returns:
-# @HvBalloonInfo
-#
# Errors:
# - If no hv-balloon device is present, guest memory status
# reporting is not enabled or no guest memory status report
@@ -1301,6 +1257,8 @@
# Return the amount of initially allocated and present hotpluggable
# (if enabled) memory in bytes.
#
+# TODO: This line is a hack to separate the example from the body
+#
# .. qmp-example::
#
# -> { "execute": "query-memory-size-summary" }
@@ -1983,7 +1941,7 @@
#
# The result of a CPU model baseline.
#
-# @model: the baselined CpuModelInfo.
+# @model: the baselined `CpuModelInfo`.
#
# Since: 2.8
##
@@ -2032,28 +1990,28 @@
#
# * QEMU version: CPU models may look different depending on the QEMU
# version. (Except for CPU models reported as "static" in
-# query-cpu-definitions.)
+# `query-cpu-definitions`.)
# * machine-type: CPU model may look different depending on the
# machine-type. (Except for CPU models reported as "static" in
-# query-cpu-definitions.)
+# `query-cpu-definitions`.)
# * machine options (including accelerator): in some architectures,
# CPU models may look different depending on machine and accelerator
# options. (Except for CPU models reported as "static" in
-# query-cpu-definitions.)
+# `query-cpu-definitions`.)
# * "-cpu" arguments and global properties: arguments to the -cpu
# option and global properties may affect expansion of CPU models.
-# Using query-cpu-model-expansion while using these is not advised.
+# Using `query-cpu-model-expansion` while using these is not advised.
#
# Some architectures may not support comparing CPU models. s390x
# supports comparing CPU models.
#
# @modela: description of the first CPU model to compare, referred to
-# as "model A" in CpuModelCompareResult
+# as "model A" in `CpuModelCompareResult`
#
# @modelb: description of the second CPU model to compare, referred to
-# as "model B" in CpuModelCompareResult
+# as "model B" in `CpuModelCompareResult`
#
-# Returns: a CpuModelCompareInfo describing how both CPU models
+# Returns: a `CpuModelCompareInfo` describing how both CPU models
# compare
#
# Errors:
@@ -2086,17 +2044,17 @@
#
# * QEMU version: CPU models may look different depending on the QEMU
# version. (Except for CPU models reported as "static" in
-# query-cpu-definitions.)
+# `query-cpu-definitions`.)
# * machine-type: CPU model may look different depending on the
# machine-type. (Except for CPU models reported as "static" in
-# query-cpu-definitions.)
+# `query-cpu-definitions`.)
# * machine options (including accelerator): in some architectures,
# CPU models may look different depending on machine and accelerator
# options. (Except for CPU models reported as "static" in
-# query-cpu-definitions.)
+# `query-cpu-definitions`.)
# * "-cpu" arguments and global properties: arguments to the -cpu
# option and global properties may affect expansion of CPU models.
-# Using query-cpu-model-expansion while using these is not advised.
+# Using `query-cpu-model-expansion` while using these is not advised.
#
# Some architectures may not support baselining CPU models. s390x
# supports baselining CPU models.
@@ -2105,7 +2063,7 @@
#
# @modelb: description of the second CPU model to baseline
#
-# Returns: a CpuModelBaselineInfo describing the baselined CPU model
+# Returns: a `CpuModelBaselineInfo` describing the baselined CPU model
#
# Errors:
# - if baselining CPU models is not supported by the target
@@ -2125,7 +2083,7 @@
#
# The result of a cpu model expansion.
#
-# @model: the expanded CpuModelInfo.
+# @model: the expanded `CpuModelInfo`.
#
# @deprecated-props: an optional list of properties that are flagged as
# deprecated by the CPU vendor. The list depends on the
@@ -2154,17 +2112,17 @@
#
# * QEMU version: CPU models may look different depending on the QEMU
# version. (Except for CPU models reported as "static" in
-# query-cpu-definitions.)
+# `query-cpu-definitions`.)
# * machine-type: CPU model may look different depending on the
# machine-type. (Except for CPU models reported as "static" in
-# query-cpu-definitions.)
+# `query-cpu-definitions`.)
# * machine options (including accelerator): in some architectures,
# CPU models may look different depending on machine and accelerator
# options. (Except for CPU models reported as "static" in
-# query-cpu-definitions.)
+# `query-cpu-definitions`.)
# * "-cpu" arguments and global properties: arguments to the -cpu
# option and global properties may affect expansion of CPU models.
-# Using query-cpu-model-expansion while using these is not advised.
+# Using `query-cpu-model-expansion` while using these is not advised.
#
# Some architectures may not support all expansion types. s390x
# supports "full" and "static". Arm only supports "full".
@@ -2173,7 +2131,7 @@
#
# @type: expansion type, specifying how to expand the CPU model
#
-# Returns: a CpuModelExpansionInfo describing the expanded CPU model
+# Returns: a `CpuModelExpansionInfo` describing the expanded CPU model
#
# Errors:
# - if expanding CPU models is not supported
@@ -2212,7 +2170,7 @@
# from running in the current host. (since 2.8)
#
# @typename: Type name that can be used as argument to
-# @device-list-properties, to introspect properties configurable
+# `device-list-properties`, to introspect properties configurable
# using -cpu or -global. (since 2.9)
#
# @alias-of: Name of CPU model this model is an alias for. The target
@@ -2256,8 +2214,6 @@
#
# Return a list of supported virtual CPU definitions
#
-# Returns: a list of CpuDefinitionInfo
-#
# Since: 1.2
##
{ 'command': 'query-cpu-definitions', 'returns': ['CpuDefinitionInfo'] }
diff --git a/qapi/meson.build b/qapi/meson.build
index 3b035ae..ca6b61a 100644
--- a/qapi/meson.build
+++ b/qapi/meson.build
@@ -57,6 +57,7 @@ qapi_all_modules = [
]
if have_system
qapi_all_modules += [
+ 'accelerator',
'acpi',
'audio',
'cryptodev',
diff --git a/qapi/migration.json b/qapi/migration.json
index 2d39a8f..e08a99b 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -3,7 +3,9 @@
#
##
-# = Migration
+# *********
+# Migration
+# *********
##
{ 'include': 'common.json' }
@@ -193,14 +195,14 @@
#
# Information about current migration process.
#
-# @status: @MigrationStatus describing the current migration status.
+# @status: `MigrationStatus` describing the current migration status.
# If this field is not returned, no migration process has been
# initiated
#
-# @ram: @MigrationStats containing detailed migration status, only
+# @ram: `MigrationStats` containing detailed migration status, only
# returned if status is 'active' or 'completed'(since 1.2)
#
-# @xbzrle-cache: @XBZRLECacheStats containing detailed XBZRLE
+# @xbzrle-cache: `XBZRLECacheStats` containing detailed XBZRLE
# migration statistics, only returned if XBZRLE feature is on and
# status is 'active' or 'completed' (since 1.2)
#
@@ -264,7 +266,7 @@
# @socket-address: Only used for tcp, to know what the real port is
# (Since 4.0)
#
-# @vfio: @VfioStats containing detailed VFIO devices migration
+# @vfio: `VfioStats` containing detailed VFIO devices migration
# statistics, only returned if VFIO device is present, migration
# is supported by all VFIO devices and status is 'active' or
# 'completed' (since 5.2)
@@ -275,7 +277,7 @@
#
# @dirty-limit-throttle-time-per-round: Maximum throttle time (in
# microseconds) of virtual CPUs each dirty ring full round, which
-# shows how MigrationCapability dirty-limit affects the guest
+# shows how `MigrationCapability` dirty-limit affects the guest
# during live migration. (Since 8.1)
#
# @dirty-limit-ring-full-time: Estimated average dirty ring full time
@@ -324,8 +326,6 @@
# is active there will be another json-object with RAM migration
# status.
#
-# Returns: @MigrationInfo
-#
# Since: 0.14
#
# .. qmp-example::
@@ -575,8 +575,6 @@
#
# Return information about the current migration capabilities status
#
-# Returns: @MigrationCapabilityStatus
-#
# Since: 1.2
#
# .. qmp-example::
@@ -629,7 +627,7 @@
#
# @normal: the original form of migration. (since 8.2)
#
-# @cpr-reboot: The migrate command stops the VM and saves state to the
+# @cpr-reboot: The `migrate` command stops the VM and saves state to the
# URI. After quitting QEMU, the user resumes by running QEMU
# -incoming.
#
@@ -679,7 +677,7 @@
#
# New QEMU reads the CPR channel before opening a monitor, hence
# the CPR channel cannot be specified in the list of channels for
-# a migrate-incoming command. It may only be specified on the
+# a `migrate-incoming` command. It may only be specified on the
# command line.
#
# The main channel address cannot be a file type, and for an
@@ -690,10 +688,10 @@
# memory-backend-epc is not supported. The VM must be started
# with the '-machine aux-ram-share=on' option.
#
-# When using -incoming defer, you must issue the migrate command
+# When using -incoming defer, you must issue the `migrate` command
# to old QEMU before issuing any monitor commands to new QEMU.
# However, new QEMU does not open and read the migration stream
-# until you issue the migrate incoming command.
+# until you issue the `migrate-incoming` command.
#
# (since 10.0)
##
@@ -915,11 +913,11 @@
# @vcpu-dirty-limit: Dirtyrate limit (MB/s) during live migration.
# Defaults to 1. (Since 8.1)
#
-# @mode: Migration mode. See description in @MigMode. Default is
+# @mode: Migration mode. See description in `MigMode`. Default is
# 'normal'. (Since 8.2)
#
# @zero-page-detection: Whether and how to detect zero pages.
-# See description in @ZeroPageDetection. Default is 'multifd'.
+# See description in `ZeroPageDetection`. Default is 'multifd'.
# (since 9.0)
#
# @direct-io: Open migration files with O_DIRECT when possible. This
@@ -1096,11 +1094,11 @@
# @vcpu-dirty-limit: Dirtyrate limit (MB/s) during live migration.
# Defaults to 1. (Since 8.1)
#
-# @mode: Migration mode. See description in @MigMode. Default is
+# @mode: Migration mode. See description in `MigMode`. Default is
# 'normal'. (Since 8.2)
#
# @zero-page-detection: Whether and how to detect zero pages.
-# See description in @ZeroPageDetection. Default is 'multifd'.
+# See description in `ZeroPageDetection`. Default is 'multifd'.
# (since 9.0)
#
# @direct-io: Open migration files with O_DIRECT when possible. This
@@ -1112,8 +1110,8 @@
# @unstable: Members @x-checkpoint-delay and
# @x-vcpu-dirty-limit-period are experimental.
#
-# TODO: either fuse back into MigrationParameters, or make
-# MigrationParameters members mandatory
+# TODO: either fuse back into `MigrationParameters`, or make
+# `MigrationParameters` members mandatory
#
# Since: 2.4
##
@@ -1306,11 +1304,11 @@
# @vcpu-dirty-limit: Dirtyrate limit (MB/s) during live migration.
# Defaults to 1. (Since 8.1)
#
-# @mode: Migration mode. See description in @MigMode. Default is
+# @mode: Migration mode. See description in `MigMode`. Default is
# 'normal'. (Since 8.2)
#
# @zero-page-detection: Whether and how to detect zero pages.
-# See description in @ZeroPageDetection. Default is 'multifd'.
+# See description in `ZeroPageDetection`. Default is 'multifd'.
# (since 9.0)
#
# @direct-io: Open migration files with O_DIRECT when possible. This
@@ -1362,8 +1360,6 @@
#
# Return information about the current migration parameters
#
-# Returns: @MigrationParameters
-#
# Since: 2.4
#
# .. qmp-example::
@@ -1402,7 +1398,7 @@
#
# Emitted when a migration event happens
#
-# @status: @MigrationStatus describing the current migration status.
+# @status: `MigrationStatus` describing the current migration status.
#
# Since: 2.4
#
@@ -1523,8 +1519,8 @@
# The reason for a COLO exit.
#
# @none: failover has never happened. This state does not occur in
-# the COLO_EXIT event, and is only visible in the result of
-# query-colo-status.
+# the `COLO_EXIT` event, and is only visible in the result of
+# `query-colo-status`.
#
# @request: COLO exit is due to an external request.
#
@@ -1779,8 +1775,8 @@
# list connected to a destination interface endpoint.
#
# @exit-on-error: Exit on incoming migration failure. Default true.
-# When set to false, the failure triggers a MIGRATION event, and
-# error details could be retrieved with query-migrate.
+# When set to false, the failure triggers a :qapi:event:`MIGRATION`
+# event, and error details could be retrieved with `query-migrate`.
# (since 9.1)
#
# Since: 2.3
@@ -1792,7 +1788,7 @@
# already exposed above libvirt.
#
# 2. QEMU must be started with -incoming defer to allow
-# migrate-incoming to be used.
+# `migrate-incoming` to be used.
#
# 3. The uri format is the same as for -incoming
#
@@ -1845,7 +1841,7 @@
# devices of the VM are not saved by this command.
#
# @filename: the file to save the state of the devices to as binary
-# data. See xen-save-devices-state.txt for a description of the
+# data. See `xen-save-devices-state`.txt for a description of the
# binary format.
#
# @live: Optional argument to ask QEMU to treat this command as part
@@ -1886,7 +1882,7 @@
# devices of the VM are not loaded by this command.
#
# @filename: the file to load the state of the devices from as binary
-# data. See xen-save-devices-state.txt for a description of the
+# data. See `xen-save-devices-state`.txt for a description of the
# binary format.
#
# Since: 2.7
@@ -1926,7 +1922,7 @@
##
# @ReplicationStatus:
#
-# The result format for 'query-xen-replication-status'.
+# The result format for `query-xen-replication-status`.
#
# @error: true if an error happened, false if replication is normal.
#
@@ -1944,7 +1940,7 @@
#
# Query replication status while the vm is running.
#
-# Returns: A @ReplicationStatus object showing the status.
+# TODO: This line is a hack to separate the example from the body
#
# .. qmp-example::
#
@@ -1975,7 +1971,7 @@
##
# @COLOStatus:
#
-# The result format for 'query-colo-status'.
+# The result format for `query-colo-status`.
#
# @mode: COLO running mode. If COLO is running, this field will
# return 'primary' or 'secondary'.
@@ -1998,7 +1994,7 @@
#
# Query COLO status while the vm is running.
#
-# Returns: A @COLOStatus object showing the status.
+# TODO: This line is a hack to separate the example from the body
#
# .. qmp-example::
#
@@ -2099,7 +2095,7 @@
# @DirtyRateMeasureMode:
#
# Method used to measure dirty page rate. Differences between
-# available methods are explained in @calc-dirty-rate.
+# available methods are explained in `calc-dirty-rate`.
#
# @page-sampling: use page sampling
#
@@ -2167,7 +2163,7 @@
# @calc-dirty-rate:
#
# Start measuring dirty page rate of the VM. Results can be retrieved
-# with @query-dirty-rate after measurements are completed.
+# with `query-dirty-rate` after measurements are completed.
#
# Dirty page rate is the number of pages changed in a given time
# period expressed in MiB/s. The following methods of calculation are
@@ -2240,7 +2236,7 @@
##
# @query-dirty-rate:
#
-# Query results of the most recent invocation of @calc-dirty-rate.
+# Query results of the most recent invocation of `calc-dirty-rate`.
#
# @calc-time-unit: time unit in which to report calculation time.
# By default it is reported in seconds. (Since 8.2)
@@ -2290,7 +2286,7 @@
#
# Requires KVM with accelerator property "dirty-ring-size" set. A
# virtual CPU's dirty page rate is a measure of its memory load. To
-# observe dirty page rates, use @calc-dirty-rate.
+# observe dirty page rates, use `calc-dirty-rate`.
#
# @cpu-index: index of a virtual CPU, default is all.
#
@@ -2315,8 +2311,8 @@
# Cancel the upper limit of dirty page rate for virtual CPUs.
#
# Cancel the dirty page limit for the vCPU which has been set with
-# set-vcpu-dirty-limit command. Note that this command requires
-# support from dirty ring, same as the "set-vcpu-dirty-limit".
+# `set-vcpu-dirty-limit` command. Note that this command requires
+# support from dirty ring, same as the `set-vcpu-dirty-limit`.
#
# @cpu-index: index of a virtual CPU, default is all.
#
@@ -2373,8 +2369,6 @@
#
# @deprecated: This command is deprecated with no replacement yet.
#
-# Returns: @MigrationThreadInfo
-#
# Since: 7.2
##
{ 'command': 'query-migrationthreads',
@@ -2475,7 +2469,7 @@
# time it takes to load the snapshot.
#
# It is strongly recommended that @devices contain all writable block
-# device nodes that can have changed since the original @snapshot-save
+# device nodes that can have changed since the original `snapshot-save`
# command execution.
#
# .. qmp-example::
diff --git a/qapi/misc-arm.json b/qapi/misc-arm.json
index f534137..f921d74 100644
--- a/qapi/misc-arm.json
+++ b/qapi/misc-arm.json
@@ -30,14 +30,12 @@
##
# @query-gic-capabilities:
#
-# It will return a list of GICCapability objects that describe its
+# It will return a list of `GICCapability` objects that describe its
# capability bits.
#
# On non-ARM targets this command will report an error as the GIC
# technology is not applicable.
#
-# Returns: a list of GICCapability objects.
-#
# Since: 2.6
#
# .. qmp-example::
diff --git a/qapi/misc-i386.json b/qapi/misc-i386.json
index 5fefa0a..c8c91a2 100644
--- a/qapi/misc-i386.json
+++ b/qapi/misc-i386.json
@@ -6,9 +6,9 @@
##
# @rtc-reset-reinjection:
#
-# This command will reset the RTC interrupt reinjection backlog. Can
-# be used if another mechanism to synchronize guest time is in effect,
-# for example QEMU guest agent's guest-set-time command.
+# Reset the RTC interrupt reinjection backlog. Can be used if another
+# mechanism to synchronize guest time is in effect, for example QEMU
+# guest agent's guest-set-time command.
#
# Use of this command is only applicable for x86 machines with an RTC,
# and on other machines will silently return without performing any
@@ -26,7 +26,7 @@
##
# @SevState:
#
-# An enumeration of SEV state information used during @query-sev.
+# An enumeration of SEV state information used during `query-sev`.
#
# @uninit: The guest is uninitialized.
#
@@ -132,8 +132,6 @@
# @enabled field is set to 'false' and the state of all other fields
# is unspecified.
#
-# Returns: @SevInfo
-#
# Since: 2.12
#
# .. qmp-example::
@@ -165,7 +163,7 @@
# 'sev-guest' confidential virtualization object. The launch
# measurement for SEV-SNP guests is only available within the guest.
#
-# Returns: The @SevLaunchMeasureInfo for the guest
+# Returns: The guest's SEV guest launch measurement info
#
# Errors:
# - If the launch measurement is unavailable, either due to an
@@ -214,8 +212,6 @@
#
# This is only supported on AMD X86 platforms with KVM enabled.
#
-# Returns: SevCapability objects.
-#
# Errors:
# - If SEV is not available on the platform, GenericError
#
@@ -233,8 +229,7 @@
##
# @sev-inject-launch-secret:
#
-# This command injects a secret blob into memory of a SEV/SEV-ES
-# guest.
+# Inject a secret blob into a SEV/SEV-ES guest's memory.
#
# This is only valid on x86 machines configured with KVM and the
# 'sev-guest' confidential virtualization object. SEV-SNP guests do
@@ -272,7 +267,7 @@
##
# @query-sev-attestation-report:
#
-# This command is used to get the SEV attestation report.
+# Get the SEV attestation report.
#
# This is only valid on x86 machines configured with KVM and the
# 'sev-guest' confidential virtualization object. The attestation
@@ -281,13 +276,10 @@
# @mnonce: a random 16 bytes value encoded in base64 (it will be
# included in report)
#
-# Returns: SevAttestationReport objects.
-#
# Errors:
-# - This will return an error if the attestation report is
-# unavailable, either due to an invalid guest configuration
-# or if the guest has not reached the required SEV state,
-# GenericError
+# - If the attestation report is unavailable, either due to an
+# invalid guest configuration or because the guest has not
+# reached the required SEV state, GenericError
#
# Since: 6.1
#
@@ -345,8 +337,6 @@
#
# Return information about configured SGX capabilities of guest
#
-# Returns: @SgxInfo
-#
# Since: 6.2
#
# .. qmp-example::
@@ -364,8 +354,6 @@
#
# Return information about SGX capabilities of host
#
-# Returns: @SgxInfo
-#
# Since: 6.2
#
# .. qmp-example::
diff --git a/qapi/misc.json b/qapi/misc.json
index 4b9e601..28c641f 100644
--- a/qapi/misc.json
+++ b/qapi/misc.json
@@ -3,7 +3,9 @@
#
##
-# = Miscellanea
+# ***********
+# Miscellanea
+# ***********
##
{ 'include': 'common.json' }
@@ -21,7 +23,7 @@
# "@dbus-display" or the name of a character device (e.g. from
# -chardev id=XXXX)
#
-# @fdname: file descriptor name previously passed via 'getfd' command
+# @fdname: file descriptor name previously passed via `getfd` command
#
# @skipauth: whether to skip authentication. Only applies to "vnc"
# and "spice" protocols
@@ -56,8 +58,6 @@
#
# Return the name information of a guest.
#
-# Returns: @NameInfo of the guest
-#
# Since: 0.14
#
# .. qmp-example::
@@ -107,7 +107,7 @@
# declared using the ``-object iothread`` command-line option. It
# is always the main thread of the process.
#
-# Returns: a list of @IOThreadInfo for each iothread
+# Returns: a list of info for each iothread
#
# Since: 2.0
#
@@ -228,7 +228,7 @@
# Known limitations:
#
# * This command is stateless, this means that commands that depend
-# on state information (such as getfd) might not work.
+# on state information (such as `getfd`) might not work.
#
# * Commands that prompt the user for data don't currently work.
#
@@ -255,7 +255,7 @@
# .. note:: If @fdname already exists, the file descriptor assigned to
# it will be closed and replaced by the received file descriptor.
#
-# The 'closefd' command can be used to explicitly close the file
+# The `closefd` command can be used to explicitly close the file
# descriptor when it is no longer needed.
#
# .. qmp-example::
@@ -282,7 +282,7 @@
# .. note:: If @fdname already exists, the file descriptor assigned to
# it will be closed and replaced by the received file descriptor.
#
-# The 'closefd' command can be used to explicitly close the file
+# The `closefd` command can be used to explicitly close the file
# descriptor when it is no longer needed.
#
# .. qmp-example::
@@ -332,9 +332,6 @@
#
# @opaque: A free-form string that can be used to describe the fd.
#
-# Returns:
-# @AddfdInfo
-#
# Errors:
# - If file descriptor was not received, GenericError
# - If @fdset-id is a negative value, GenericError
@@ -415,8 +412,6 @@
#
# Return information describing all fd sets.
#
-# Returns: A list of @FdsetInfo
-#
# Since: 1.2
#
# .. note:: The list of fd sets is shared by all monitor connections.
@@ -480,7 +475,7 @@
#
# @name: parameter name
#
-# @type: parameter @CommandLineParameterType
+# @type: parameter `CommandLineParameterType`
#
# @help: human readable text string, not suitable for parsing.
#
@@ -502,7 +497,7 @@
#
# @option: option name
#
-# @parameters: an array of @CommandLineParameterInfo
+# @parameters: an array of `CommandLineParameterInfo`
#
# Since: 1.5
##
@@ -516,8 +511,7 @@
#
# @option: option name
#
-# Returns: list of @CommandLineOptionInfo for all options (or for the
-# given @option).
+# Returns: list of objects for all options (or for the given @option).
#
# Errors:
# - if the given @option doesn't exist
diff --git a/qapi/net.json b/qapi/net.json
index 0f76604..78bcc98 100644
--- a/qapi/net.json
+++ b/qapi/net.json
@@ -3,7 +3,9 @@
#
##
-# = Net devices
+# ***********
+# Net devices
+# ***********
##
{ 'include': 'sockets.json' }
@@ -567,25 +569,34 @@
# (default: 0).
#
# @inhibit: Don't load a default XDP program, use one already loaded
-# to the interface (default: false). Requires @sock-fds.
+# to the interface (default: false). Requires @sock-fds or @map-path.
#
# @sock-fds: A colon (:) separated list of file descriptors for
# already open but not bound AF_XDP sockets in the queue order.
# One fd per queue. These descriptors should already be added
-# into XDP socket map for corresponding queues. Requires
-# @inhibit.
+# into XDP socket map for corresponding queues. @sock-fds and
+# @map-path are mutually exclusive. Requires @inhibit.
+#
+# @map-path: The path to a pinned xsk map to push file descriptors
+# for bound AF_XDP sockets into. @map-path and @sock-fds are
+# mutually exclusive. Requires @inhibit. (Since 10.1)
+#
+# @map-start-index: Use @map-path to insert xsk sockets starting from
+# this index number (default: 0). Requires @map-path. (Since 10.1)
#
# Since: 8.2
##
{ 'struct': 'NetdevAFXDPOptions',
'data': {
- 'ifname': 'str',
- '*mode': 'AFXDPMode',
- '*force-copy': 'bool',
- '*queues': 'int',
- '*start-queue': 'int',
- '*inhibit': 'bool',
- '*sock-fds': 'str' },
+ 'ifname': 'str',
+ '*mode': 'AFXDPMode',
+ '*force-copy': 'bool',
+ '*queues': 'int',
+ '*start-queue': 'int',
+ '*inhibit': 'bool',
+ '*sock-fds': 'str',
+ '*map-path': 'str',
+ '*map-start-index': 'int32' },
'if': 'CONFIG_AF_XDP' }
##
@@ -768,7 +779,7 @@
# this to zero disables this function. This member is mutually
# exclusive with @reconnect. (default: 0) (Since: 9.2)
#
-# Only SocketAddress types 'unix', 'inet' and 'fd' are supported.
+# Only `SocketAddress` types 'unix', 'inet' and 'fd' are supported.
#
# Features:
#
@@ -793,7 +804,7 @@
#
# @local: local address
#
-# Only SocketAddress types 'unix', 'inet' and 'fd' are supported.
+# Only `SocketAddress` types 'unix', 'inet' and 'fd' are supported.
#
# If remote address is present and it's a multicast address, local
# address is optional. Otherwise local address is required and remote
@@ -963,7 +974,7 @@
#
# @name: net client name
#
-# Returns: list of @RxFilterInfo for all NICs (or for the given NIC).
+# Returns: list of info for all NICs (or for the given NIC).
#
# Errors:
# - if the given @name doesn't exist
@@ -1008,7 +1019,7 @@
##
# @NIC_RX_FILTER_CHANGED:
#
-# Emitted once until the 'query-rx-filter' command is executed, the
+# Emitted once until the `query-rx-filter` command is executed, the
# first event will always be emitted
#
# @name: net client name
diff --git a/qapi/pci.json b/qapi/pci.json
index dc85a41..694c741 100644
--- a/qapi/pci.json
+++ b/qapi/pci.json
@@ -6,7 +6,9 @@
# SPDX-License-Identifier: GPL-2.0-or-later
##
-# = PCI
+# ***
+# PCI
+# ***
##
##
@@ -83,7 +85,7 @@
#
# @bus: information about the bus the device resides on
#
-# @devices: a list of @PciDeviceInfo for each device on this bridge
+# @devices: a list of `PciDeviceInfo` for each device on this bridge
#
# Since: 0.14
##
@@ -175,7 +177,7 @@
#
# Return information about the PCI bus topology of the guest.
#
-# Returns: a list of @PciInfo for each PCI bus. Each bus is
+# Returns: a list of info for each PCI bus. Each bus is
# represented by a json-object, which has a key with a json-array
# of all PCI devices attached to it. Each device is represented
# by a json-object.
diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json
index a8f6616..82f111b 100644
--- a/qapi/qapi-schema.json
+++ b/qapi/qapi-schema.json
@@ -1,7 +1,9 @@
# -*- Mode: Python -*-
# vim: filetype=python
##
-# = Introduction
+# ************
+# Introduction
+# ************
#
# This manual describes the commands and events supported by the QEMU
# Monitor Protocol (QMP).
@@ -37,6 +39,7 @@
{ 'include': 'run-state.json' }
{ 'include': 'crypto.json' }
{ 'include': 'job.json' }
+{ 'include': 'accelerator.json' }
{ 'include': 'block.json' }
{ 'include': 'block-export.json' }
{ 'include': 'char.json' }
diff --git a/qapi/qdev.json b/qapi/qdev.json
index 32c7d10..e14a0c9 100644
--- a/qapi/qdev.json
+++ b/qapi/qdev.json
@@ -5,7 +5,9 @@
# See the COPYING file in the top-level directory.
##
-# = Device infrastructure (qdev)
+# ****************************
+# Device infrastructure (qdev)
+# ****************************
##
{ 'include': 'qom.json' }
@@ -17,8 +19,7 @@
#
# @typename: the type name of a device
#
-# Returns: a list of ObjectPropertyInfo describing a devices
-# properties
+# Returns: a list describing a devices properties
#
# .. note:: Objects can create properties at runtime, for example to
# describe links between different devices and/or objects. These
@@ -96,10 +97,10 @@
# from the guest. Hot removal is an operation that requires guest
# cooperation. This command merely requests that the guest begin
# the hot removal process. Completion of the device removal
-# process is signaled with a DEVICE_DELETED event. Guest reset
+# process is signaled with a `DEVICE_DELETED` event. Guest reset
# will automatically complete removal for all devices. If a
# guest-side error in the hot removal process is detected, the
-# device will not be removed and a DEVICE_UNPLUG_GUEST_ERROR event
+# device will not be removed and a `DEVICE_UNPLUG_GUEST_ERROR` event
# is sent. Some errors cannot be detected.
#
# Since: 0.14
diff --git a/qapi/qom.json b/qapi/qom.json
index bbdb56d..96d56df 100644
--- a/qapi/qom.json
+++ b/qapi/qom.json
@@ -10,7 +10,9 @@
{ 'include': 'crypto.json' }
##
-# = QEMU Object Model (QOM)
+# ***********************
+# QEMU Object Model (QOM)
+# ***********************
##
##
@@ -48,14 +50,12 @@
##
# @qom-list:
#
-# This command will list any properties of a object given a path in
-# the object model.
+# List properties of a object given a path in the object model.
#
-# @path: the path within the object model. See @qom-get for a
+# @path: the path within the object model. See `qom-get` for a
# description of this parameter.
#
-# Returns: a list of @ObjectPropertyInfo that describe the properties
-# of the object.
+# Returns: a list that describe the properties of the object.
#
# Since: 1.2
#
@@ -76,8 +76,7 @@
##
# @qom-get:
#
-# This command will get a property from a object model path and return
-# the value.
+# Get a property value.
#
# @path: The path within the object model. There are two forms of
# supported paths--absolute and partial paths.
@@ -128,14 +127,14 @@
##
# @qom-set:
#
-# This command will set a property from a object model path.
+# Set a property value.
#
-# @path: see @qom-get for a description of this parameter
+# @path: see `qom-get` for a description of this parameter
#
# @property: the property name to set
#
# @value: a value who's type is appropriate for the property type.
-# See @qom-get for a description of type mapping.
+# See `qom-get` for a description of type mapping.
#
# Since: 1.2
#
@@ -154,7 +153,7 @@
##
# @ObjectTypeInfo:
#
-# This structure describes a search result from @qom-list-types
+# This structure describes a search result from `qom-list-types`
#
# @name: the type name found in the search
#
@@ -171,15 +170,14 @@
##
# @qom-list-types:
#
-# This command will return a list of types given search parameters
+# Return a list of types given search parameters.
#
# @implements: if specified, only return types that implement this
# type name
#
# @abstract: if true, include abstract types in the results
#
-# Returns: a list of @ObjectTypeInfo or an empty list if no results
-# are found
+# Returns: a list of types, or an empty list if no results are found
#
# Since: 1.1
##
@@ -195,11 +193,12 @@
#
# @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
+# Returns: a list describing object properties
#
# Since: 2.12
##
@@ -789,7 +788,7 @@
#
# Properties for x-remote-object objects.
#
-# @fd: file descriptor name previously passed via 'getfd' command
+# @fd: file descriptor name previously passed via `getfd` command
#
# @devid: the id of the device to be associated with the file
# descriptor
@@ -818,7 +817,7 @@
#
# Properties for iommufd objects.
#
-# @fd: file descriptor name previously passed via 'getfd' command,
+# @fd: file descriptor name previously passed via `getfd` command,
# which represents a pre-opened /dev/iommu. This allows the
# iommufd object to be shared across several subsystems (VFIO,
# VDPA, ...), and the file descriptor to be shared with other
@@ -1278,7 +1277,7 @@
# Create a QOM object.
#
# Errors:
-# - Error if @qom-type is not a valid class name
+# - If @qom-type is not a valid class name
#
# Since: 2.0
#
@@ -1300,7 +1299,7 @@
# @id: the name of the QOM object to remove
#
# Errors:
-# - Error if @id is not a valid id for a QOM object
+# - If @id is not a valid id for a QOM object
#
# Since: 2.0
#
diff --git a/qapi/replay.json b/qapi/replay.json
index 35e0c4a..ccf84da 100644
--- a/qapi/replay.json
+++ b/qapi/replay.json
@@ -3,7 +3,9 @@
#
##
-# = Record/replay
+# *************
+# Record/replay
+# *************
##
{ 'include': 'common.json' }
@@ -47,8 +49,8 @@
# @query-replay:
#
# Retrieve the record/replay information. It includes current
-# instruction count which may be used for @replay-break and
-# @replay-seek commands.
+# instruction count which may be used for `replay-break` and
+# `replay-seek` commands.
#
# Returns: record/replay information.
#
@@ -70,7 +72,7 @@
# breakpoint. When breakpoint is set, any prior one is removed. The
# breakpoint may be set only in replay mode and only "in the future",
# i.e. at instruction counts greater than the current one. The
-# current instruction count can be observed with @query-replay.
+# current instruction count can be observed with `query-replay`.
#
# @icount: instruction count to stop at
#
@@ -86,7 +88,7 @@
##
# @replay-delete-break:
#
-# Remove replay breakpoint which was set with @replay-break. The
+# Remove replay breakpoint which was set with `replay-break`. The
# command is ignored when there are no replay breakpoints.
#
# Since: 5.2
@@ -106,7 +108,7 @@
# snapshot and replays the execution to find the desired instruction.
# When there is no preceding snapshot or the execution is not
# replayed, then the command fails. Instruction count can be obtained
-# with the @query-replay command.
+# with the `query-replay` command.
#
# @icount: target instruction count
#
diff --git a/qapi/rocker.json b/qapi/rocker.json
index 0c7ef1f..5d2dbd2 100644
--- a/qapi/rocker.json
+++ b/qapi/rocker.json
@@ -2,7 +2,9 @@
# vim: filetype=python
##
-# = Rocker switch device
+# ********************
+# Rocker switch device
+# ********************
##
##
@@ -28,8 +30,6 @@
#
# @name: switch name
#
-# Returns: @Rocker information
-#
# Since: 2.4
#
# .. qmp-example::
@@ -98,8 +98,6 @@
#
# @name: port name
#
-# Returns: a list of @RockerPort information
-#
# Since: 2.4
#
# .. qmp-example::
diff --git a/qapi/run-state.json b/qapi/run-state.json
index fd09beb..54ba5c9 100644
--- a/qapi/run-state.json
+++ b/qapi/run-state.json
@@ -3,7 +3,9 @@
#
##
-# = VM run state
+# ************
+# VM run state
+# ************
##
##
@@ -68,9 +70,9 @@
#
# @host-error: An error prevents further use of guest
#
-# @host-qmp-quit: Reaction to the QMP command 'quit'
+# @host-qmp-quit: Reaction to the QMP command `quit`
#
-# @host-qmp-system-reset: Reaction to the QMP command 'system_reset'
+# @host-qmp-system-reset: Reaction to the QMP command `system_reset`
#
# @host-signal: Reaction to a signal, such as SIGINT
#
@@ -106,7 +108,7 @@
#
# @running: true if all VCPUs are runnable, false if not runnable
#
-# @status: the virtual machine @RunState
+# @status: the virtual machine `RunState`
#
# Since: 0.14
##
@@ -119,8 +121,6 @@
#
# Query the run status of the VM
#
-# Returns: @StatusInfo reflecting the VM
-#
# Since: 0.14
#
# .. qmp-example::
@@ -143,12 +143,12 @@
# hardware-specific action) rather than a host request (such as
# sending QEMU a SIGINT). (since 2.10)
#
-# @reason: The @ShutdownCause which resulted in the SHUTDOWN.
+# @reason: The `ShutdownCause` which resulted in the `SHUTDOWN`.
# (since 4.0)
#
# .. note:: If the command-line option ``-no-shutdown`` has been
-# specified, QEMU will not exit, and a STOP event will eventually
-# follow the SHUTDOWN event.
+# specified, QEMU will not exit, and a `STOP` event will eventually
+# follow the `SHUTDOWN` event.
#
# Since: 0.12
#
@@ -183,9 +183,9 @@
# @guest: If true, the reset was triggered by a guest request (such as
# a guest-initiated ACPI reboot request or other hardware-specific
# action) rather than a host request (such as the QMP command
-# system_reset). (since 2.10)
+# `system_reset`). (since 2.10)
#
-# @reason: The @ShutdownCause of the RESET. (since 4.0)
+# @reason: The `ShutdownCause` of the `RESET`. (since 4.0)
#
# Since: 0.12
#
@@ -247,7 +247,7 @@
# saved on disk, for example, S4 state, which is sometimes called
# hibernate state
#
-# .. note:: QEMU shuts down (similar to event @SHUTDOWN) when entering
+# .. note:: QEMU shuts down (similar to event `SHUTDOWN`) when entering
# this state.
#
# Since: 1.2
@@ -281,8 +281,8 @@
#
# @action: action that has been taken
#
-# .. note:: If action is "reset", "shutdown", or "pause" the WATCHDOG
-# event is followed respectively by the RESET, SHUTDOWN, or STOP
+# .. note:: If action is "reset", "shutdown", or "pause" the `WATCHDOG`
+# event is followed respectively by the `RESET`, `SHUTDOWN`, or `STOP`
# events.
#
# .. note:: This event is rate-limited.
@@ -378,7 +378,7 @@
#
# Set watchdog action.
#
-# @action: @WatchdogAction action taken when watchdog timer expires.
+# @action: `WatchdogAction` action taken when watchdog timer expires.
#
# Since: 2.11
#
@@ -396,13 +396,13 @@
# Set the actions that will be taken by the emulator in response to
# guest events.
#
-# @reboot: @RebootAction action taken on guest reboot.
+# @reboot: `RebootAction` action taken on guest reboot.
#
-# @shutdown: @ShutdownAction action taken on guest shutdown.
+# @shutdown: `ShutdownAction` action taken on guest shutdown.
#
-# @panic: @PanicAction action taken on guest panic.
+# @panic: `PanicAction` action taken on guest panic.
#
-# @watchdog: @WatchdogAction action taken when watchdog timer expires.
+# @watchdog: `WatchdogAction` action taken when watchdog timer expires.
#
# Since: 6.0
#
@@ -529,20 +529,20 @@
#
# Hyper-V specific guest panic information (HV crash MSRs)
#
-# @arg1: for Windows, STOP code for the guest crash. For Linux,
+# @arg1: for Windows, `STOP` code for the guest crash. For Linux,
# an error code.
#
-# @arg2: for Windows, first argument of the STOP. For Linux, the
+# @arg2: for Windows, first argument of the `STOP`. For Linux, the
# guest OS ID, which has the kernel version in bits 16-47 and
# 0x8100 in bits 48-63.
#
-# @arg3: for Windows, second argument of the STOP. For Linux, the
+# @arg3: for Windows, second argument of the `STOP`. For Linux, the
# program counter of the guest.
#
-# @arg4: for Windows, third argument of the STOP. For Linux, the
+# @arg4: for Windows, third argument of the `STOP`. For Linux, the
# RAX register (x86) or the stack pointer (aarch64) of the guest.
#
-# @arg5: for Windows, fourth argument of the STOP. For x86 Linux, the
+# @arg5: for Windows, fourth argument of the `STOP`. For x86 Linux, the
# stack pointer of the guest.
#
# Since: 2.9
@@ -630,11 +630,11 @@
#
# Emitted when a memory failure occurs on host side.
#
-# @recipient: recipient is defined as @MemoryFailureRecipient.
+# @recipient: recipient is defined as `MemoryFailureRecipient`.
#
# @action: action that has been taken.
#
-# @flags: flags for MemoryFailureAction.
+# @flags: flags for `MemoryFailureAction`.
#
# Since: 5.2
#
diff --git a/qapi/sockets.json b/qapi/sockets.json
index f9f559d..82046b0 100644
--- a/qapi/sockets.json
+++ b/qapi/sockets.json
@@ -2,7 +2,9 @@
# vim: filetype=python
##
-# = Socket data types
+# *****************
+# Socket data types
+# *****************
##
##
@@ -209,14 +211,14 @@
'unix': 'UnixSocketAddressWrapper',
'vsock': 'VsockSocketAddressWrapper',
'fd': 'FdSocketAddressWrapper' } }
-# Note: This type is deprecated in favor of SocketAddress. The
-# difference between SocketAddressLegacy and SocketAddress is that the
+# Note: This type is deprecated in favor of `SocketAddress`. The
+# difference between `SocketAddressLegacy` and `SocketAddress` is that the
# latter has fewer ``{}`` on the wire.
##
# @SocketAddressType:
#
-# Available SocketAddress types
+# Available `SocketAddress` types
#
# @inet: Internet address
#
diff --git a/qapi/stats.json b/qapi/stats.json
index 8902ef9..151ac43 100644
--- a/qapi/stats.json
+++ b/qapi/stats.json
@@ -9,7 +9,9 @@
# SPDX-License-Identifier: GPL-2.0-or-later
##
-# = Statistics
+# **********
+# Statistics
+# **********
##
##
@@ -87,7 +89,7 @@
# @StatsRequest:
#
# Indicates a set of statistics that should be returned by
-# query-stats.
+# `query-stats`.
#
# @provider: provider for which to return statistics.
#
@@ -112,7 +114,7 @@
##
# @StatsFilter:
#
-# The arguments to the query-stats command; specifies a target for
+# The arguments to the `query-stats` command; specifies a target for
# which to request statistics and optionally the required subset of
# information for that target.
#
@@ -183,10 +185,10 @@
# Return runtime-collected statistics for objects such as the VM or
# its vCPUs.
#
-# The arguments are a StatsFilter and specify the provider and objects
+# The arguments are a `StatsFilter` and specify the provider and objects
# to return statistics about.
#
-# Returns: a list of StatsResult, one for each provider and object
+# Returns: a list of statistics, one for each provider and object
# (e.g., for each vCPU).
#
# Since: 7.1
@@ -203,7 +205,7 @@
#
# @name: name of the statistic; each element of the schema is uniquely
# identified by a target, a provider (both available in
-# @StatsSchema) and the name.
+# `StatsSchema`) and the name.
#
# @type: kind of statistic.
#
diff --git a/qapi/tpm.json b/qapi/tpm.json
index a16a72e..3f2850a 100644
--- a/qapi/tpm.json
+++ b/qapi/tpm.json
@@ -3,7 +3,9 @@
#
##
-# = TPM (trusted platform module) devices
+# *************************************
+# TPM (trusted platform module) devices
+# *************************************
##
##
@@ -27,8 +29,6 @@
#
# Return a list of supported TPM models
#
-# Returns: a list of TpmModel
-#
# Since: 1.5
#
# .. qmp-example::
@@ -58,8 +58,6 @@
#
# Return a list of supported TPM types
#
-# Returns: a list of TpmType
-#
# Since: 1.5
#
# .. qmp-example::
diff --git a/qapi/trace.json b/qapi/trace.json
index eb5f63f..de369da 100644
--- a/qapi/trace.json
+++ b/qapi/trace.json
@@ -7,7 +7,9 @@
# See the COPYING file in the top-level directory.
##
-# = Tracing
+# *******
+# Tracing
+# *******
##
##
@@ -47,7 +49,7 @@
#
# @name: Event name pattern (case-sensitive glob).
#
-# Returns: a list of @TraceEventInfo for the matching events
+# Returns: a list of info for the matching events
#
# Since: 2.2
#
diff --git a/qapi/transaction.json b/qapi/transaction.json
index 9d9e7af..4b4eb09 100644
--- a/qapi/transaction.json
+++ b/qapi/transaction.json
@@ -3,7 +3,9 @@
#
##
-# = Transactions
+# ************
+# Transactions
+# ************
##
{ 'include': 'block-core.json' }
@@ -67,8 +69,8 @@
#
# Features:
#
-# @deprecated: Member @drive-backup is deprecated. Use member
-# @blockdev-backup instead.
+# @deprecated: Member `drive-backup` is deprecated. Use member
+# `blockdev-backup` instead.
#
# Since: 1.1
##
@@ -156,7 +158,7 @@
# @TransactionAction:
#
# A discriminated record of operations that can be performed with
-# @transaction.
+# `transaction`.
#
# @type: the operation to be performed
#
@@ -187,7 +189,7 @@
#
# @completion-mode: Controls how jobs launched asynchronously by
# Actions will complete or fail as a group. See
-# @ActionCompletionMode for details.
+# `ActionCompletionMode` for details.
#
# Since: 2.5
##
@@ -227,11 +229,11 @@
# in the transaction. When an I/O error occurs during deletion, the
# user needs to fix it later with qemu-img or other command.
#
-# @actions: List of @TransactionAction; information needed for the
+# @actions: List of `TransactionAction`; information needed for the
# respective operations.
#
# @properties: structure of additional options to control the
-# execution of the transaction. See @TransactionProperties for
+# execution of the transaction. See `TransactionProperties` for
# additional detail.
#
# Errors:
diff --git a/qapi/uefi.json b/qapi/uefi.json
index 6592183..a206c2e 100644
--- a/qapi/uefi.json
+++ b/qapi/uefi.json
@@ -3,7 +3,9 @@
#
##
-# = UEFI Variable Store
+# *******************
+# UEFI Variable Store
+# *******************
#
# The QEMU efi variable store implementation (hw/uefi/) uses this to
# store non-volatile variables in json format on disk.
diff --git a/qapi/ui.json b/qapi/ui.json
index 514fa15..1b2f4a4 100644
--- a/qapi/ui.json
+++ b/qapi/ui.json
@@ -3,7 +3,9 @@
#
##
-# = Remote desktop
+# **************
+# Remote desktop
+# **************
##
{ 'include': 'common.json' }
@@ -39,7 +41,7 @@
##
# @SetPasswordOptions:
#
-# Options for set_password.
+# Options for `set_password`.
#
# @protocol:
# - 'vnc' to modify the VNC server password
@@ -63,7 +65,7 @@
##
# @SetPasswordOptionsVnc:
#
-# Options for set_password specific to the VNC protocol.
+# Options for `set_password` specific to the VNC protocol.
#
# @display: The id of the display where the password should be
# changed. Defaults to the first.
@@ -94,7 +96,7 @@
##
# @ExpirePasswordOptions:
#
-# General options for expire_password.
+# General options for `expire_password`.
#
# @protocol:
# - 'vnc' to modify the VNC server expiration
@@ -124,7 +126,7 @@
##
# @ExpirePasswordOptionsVnc:
#
-# Options for expire_password specific to the VNC protocol.
+# Options for `expire_password` specific to the VNC protocol.
#
# @display: The id of the display where the expiration should be
# changed. Defaults to the first.
@@ -183,7 +185,7 @@
# the head can only be specified in conjunction with the device
# ID. (Since 2.12)
#
-# @format: image format for screendump. (default: ppm) (Since 7.1)
+# @format: image format for `screendump`. (default: ppm) (Since 7.1)
#
# Since: 0.14
#
@@ -200,7 +202,8 @@
'if': 'CONFIG_PIXMAN' }
##
-# == Spice
+# Spice
+# =====
##
##
@@ -310,7 +313,7 @@
# unknown if spice server doesn't provide this information.
# (since: 1.1)
#
-# @channels: a list of @SpiceChannel for each active spice channel
+# @channels: a list of `SpiceChannel` for each active spice channel
#
# Since: 0.14
##
@@ -325,8 +328,6 @@
#
# Return information about the current SPICE server
#
-# Returns: @SpiceInfo
-#
# Since: 0.14
#
# .. qmp-example::
@@ -461,7 +462,8 @@
'if': 'CONFIG_SPICE' }
##
-# == VNC
+# VNC
+# ===
##
##
@@ -561,7 +563,7 @@
# - 'vencrypt+x509+sasl' if VEncrypt is used with x509 and SASL
# auth
#
-# @clients: a list of @VncClientInfo of all currently connected
+# @clients: a list of `VncClientInfo` of all currently connected
# clients
#
# Since: 0.14
@@ -624,12 +626,12 @@
#
# @id: vnc server name.
#
-# @server: A list of @VncBasincInfo describing all listening sockets.
+# @server: A list of `VncBasicInfo` describing all listening sockets.
# The list can be empty (in case the vnc server is disabled). It
# also may have multiple entries: normal + websocket, possibly
# also ipv4 + ipv6 in the future.
#
-# @clients: A list of @VncClientInfo of all currently connected
+# @clients: A list of `VncClientInfo` of all currently connected
# clients. The list can be empty, for obvious reasons.
#
# @auth: The current authentication type used by the non-websockets
@@ -656,8 +658,6 @@
#
# Return information about the current VNC server
#
-# Returns: @VncInfo
-#
# Since: 0.14
#
# .. qmp-example::
@@ -687,8 +687,6 @@
#
# Return a list of vnc servers. The list can be empty.
#
-# Returns: a list of @VncInfo2
-#
# Since: 2.3
##
{ 'command': 'query-vnc-servers', 'returns': ['VncInfo2'],
@@ -794,7 +792,9 @@
'if': 'CONFIG_VNC' }
##
-# = Input
+# *****
+# Input
+# *****
##
##
@@ -822,7 +822,7 @@
#
# Return information about each active mouse device
#
-# Returns: a list of @MouseInfo for each device
+# Returns: a list of info for each device
#
# Since: 0.14
#
@@ -852,7 +852,7 @@
#
# An enumeration of key name.
#
-# This is used by the @send-key command.
+# This is used by the `send-key` command.
#
# @unmapped: since 2.0
#
@@ -1023,10 +1023,10 @@
#
# Send keys to guest.
#
-# @keys: An array of @KeyValue elements. All @KeyValues in this array
-# are simultaneously sent to the guest. A @KeyValue.number value
-# is sent directly to the guest, while @KeyValue.qcode must be a
-# valid @QKeyCode value
+# @keys: An array of `KeyValue` elements. All @KeyValues in this array
+# are simultaneously sent to the guest. A `KeyValue`.number value
+# is sent directly to the guest, while `KeyValue`.qcode must be a
+# valid `QKeyCode` value
#
# @hold-time: time to delay key up events, milliseconds. Defaults to
# 100
@@ -1263,7 +1263,7 @@
# @head: head to send event(s) to, in case the display device supports
# multiple scanouts.
#
-# @events: List of InputEvent union.
+# @events: List of `InputEvent` union.
#
# Since: 2.6
#
@@ -1335,13 +1335,20 @@
# @show-menubar: Display the main window menubar. Defaults to "on".
# (Since 8.0)
#
+# @keep-aspect-ratio: Keep width/height aspect ratio of guest content when
+# resizing host window. Defaults to "on". (Since 10.1)
+#
+# @scale: Set preferred scale of the display. Defaults to 1.0. (Since 10.1)
+#
# Since: 2.12
##
{ 'struct' : 'DisplayGTK',
- 'data' : { '*grab-on-hover' : 'bool',
- '*zoom-to-fit' : 'bool',
- '*show-tabs' : 'bool',
- '*show-menubar' : 'bool' } }
+ 'data' : { '*grab-on-hover' : 'bool',
+ '*zoom-to-fit' : 'bool',
+ '*show-tabs' : 'bool',
+ '*show-menubar' : 'bool',
+ '*keep-aspect-ratio' : 'bool',
+ '*scale' : 'number' } }
##
# @DisplayEGLHeadless:
@@ -1367,7 +1374,7 @@
# first available node on the host.
#
# @p2p: Whether to use peer-to-peer connections (accepted through
-# @add_client).
+# `add_client`).
#
# @audiodev: Use the specified DBus audiodev to export audio.
#
@@ -1526,7 +1533,7 @@
#
# Display (user interface) options.
#
-# @type: Which DisplayType QEMU should use.
+# @type: Which `DisplayType` QEMU should use.
#
# @full-screen: Start user interface in fullscreen mode
# (default: off).
@@ -1564,8 +1571,6 @@
#
# Return information about display configuration
#
-# Returns: @DisplayOptions
-#
# Since: 3.1
##
{ 'command': 'query-display-options',
diff --git a/qapi/vfio.json b/qapi/vfio.json
index b53b7ca..a1a9c5b 100644
--- a/qapi/vfio.json
+++ b/qapi/vfio.json
@@ -3,7 +3,9 @@
#
##
-# = VFIO devices
+# ************
+# VFIO devices
+# ************
##
##
diff --git a/qapi/virtio.json b/qapi/virtio.json
index 73df718..9d652fe 100644
--- a/qapi/virtio.json
+++ b/qapi/virtio.json
@@ -3,7 +3,9 @@
#
##
-# = Virtio devices
+# **************
+# Virtio devices
+# **************
##
##
@@ -135,7 +137,7 @@
# @num-vqs: VirtIODevice virtqueue count. This is the number of
# active virtqueues being used by the VirtIODevice.
#
-# @status: VirtIODevice configuration status (VirtioDeviceStatus)
+# @status: VirtIODevice configuration status (`VirtioDeviceStatus`)
#
# @isr: VirtIODevice ISR
#
@@ -199,7 +201,7 @@
#
# @unstable: This command is meant for debugging.
#
-# Returns: VirtioStatus of the virtio device
+# Returns: Status of the virtio device
#
# Since: 7.2
#
@@ -563,7 +565,7 @@
#
# @unstable: This command is meant for debugging.
#
-# Returns: VirtQueueStatus of the VirtQueue
+# Returns: Status of the queue
#
# .. note:: last_avail_idx will not be displayed in the case where the
# selected VirtIODevice has a running vhost device and the
@@ -577,7 +579,7 @@
# .. qmp-example::
# :annotated:
#
-# Get VirtQueueStatus for virtio-vsock (vhost-vsock running)
+# Get `VirtQueueStatus` for virtio-vsock (vhost-vsock running)
# ::
#
# -> { "execute": "x-query-virtio-queue-status",
@@ -604,7 +606,7 @@
# .. qmp-example::
# :annotated:
#
-# Get VirtQueueStatus for virtio-serial (no vhost)
+# Get `VirtQueueStatus` for virtio-serial (no vhost)
# ::
#
# -> { "execute": "x-query-virtio-queue-status",
@@ -698,7 +700,7 @@
#
# @unstable: This command is meant for debugging.
#
-# Returns: VirtVhostQueueStatus of the vhost_virtqueue
+# Returns: Status of the vhost_virtqueue
#
# Since: 7.2
#
@@ -816,7 +818,7 @@
#
# @index: Index of the element in the queue
#
-# @descs: List of descriptors (VirtioRingDesc)
+# @descs: List of descriptors (`VirtioRingDesc`)
#
# @avail: VRingAvail info
#
@@ -847,8 +849,6 @@
#
# @unstable: This command is meant for debugging.
#
-# Returns: VirtioQueueElement information
-#
# Since: 7.2
#
# .. qmp-example::
@@ -964,16 +964,30 @@
'data': { 'iothread': 'str', '*vqs': ['uint16'] } }
##
+# @VirtIOGPUOutput:
+#
+# Describes configuration of a VirtIO GPU output.
+#
+# @name: the name of the output
+#
+# Since: 10.1
+##
+
+{ 'struct': 'VirtIOGPUOutput',
+ 'data': { 'name': 'str' } }
+
+##
# @DummyVirtioForceArrays:
#
# Not used by QMP; hack to let us use IOThreadVirtQueueMappingList
-# internally
+# and VirtIOGPUOutputList internally
#
# Since: 9.0
##
{ 'struct': 'DummyVirtioForceArrays',
- 'data': { 'unused-iothread-vq-mapping': ['IOThreadVirtQueueMapping'] } }
+ 'data': { 'unused-iothread-vq-mapping': ['IOThreadVirtQueueMapping'],
+ 'unused-virtio-gpu-output': ['VirtIOGPUOutput'] } }
##
# @GranuleMode:
diff --git a/qapi/yank.json b/qapi/yank.json
index 30f46c9..f3cd5c1 100644
--- a/qapi/yank.json
+++ b/qapi/yank.json
@@ -3,13 +3,15 @@
#
##
-# = Yank feature
+# ************
+# Yank feature
+# ************
##
##
# @YankInstanceType:
#
-# An enumeration of yank instance types. See @YankInstance for more
+# An enumeration of yank instance types. See `YankInstance` for more
# information.
#
# Since: 6.0
@@ -20,7 +22,7 @@
##
# @YankInstanceBlockNode:
#
-# Specifies which block graph node to yank. See @YankInstance for
+# Specifies which block graph node to yank. See `YankInstance` for
# more information.
#
# @node-name: the name of the block graph node
@@ -33,7 +35,7 @@
##
# @YankInstanceChardev:
#
-# Specifies which character device to yank. See @YankInstance for
+# Specifies which character device to yank. See `YankInstance` for
# more information.
#
# @id: the chardev's ID
@@ -46,7 +48,7 @@
##
# @YankInstance:
#
-# A yank instance can be yanked with the @yank qmp command to recover
+# A yank instance can be yanked with the `yank` qmp command to recover
# from a hanging QEMU.
#
# @type: yank instance type
@@ -57,9 +59,9 @@
# nbd server without attempting to reconnect.
# - socket chardev: Yanking it will shut down the connected socket.
# - migration: Yanking it will shut down all migration connections.
-# Unlike @migrate_cancel, it will not notify the migration process,
+# Unlike `migrate_cancel`, it will not notify the migration process,
# so migration will go into @failed state, instead of @cancelled
-# state. @yank should be used to recover from hangs.
+# state. `yank` should be used to recover from hangs.
#
# Since: 6.0
##
@@ -74,7 +76,7 @@
# @yank:
#
# Try to recover from hanging QEMU by yanking the specified instances.
-# See @YankInstance for more information.
+# See `YankInstance` for more information.
#
# @instances: the instances to be yanked
#
@@ -100,9 +102,9 @@
##
# @query-yank:
#
-# Query yank instances. See @YankInstance for more information.
+# Query yank instances. See `YankInstance` for more information.
#
-# Returns: list of @YankInstance
+# TODO: This line is a hack to separate the example from the body
#
# .. qmp-example::
#
diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
index c9dd70a..2c5a8a2 100644
--- a/qemu-img-cmds.hx
+++ b/qemu-img-cmds.hx
@@ -84,9 +84,9 @@ SRST
ERST
DEF("snapshot", img_snapshot,
- "snapshot [--object objectdef] [--image-opts] [-U] [-q] [-l | -a snapshot | -c snapshot | -d snapshot] filename")
+ "snapshot [--object objectdef] [-f fmt | --image-opts] [-U] [-q] [-l | -a snapshot | -c snapshot | -d snapshot] filename")
SRST
-.. option:: snapshot [--object OBJECTDEF] [--image-opts] [-U] [-q] [-l | -a SNAPSHOT | -c SNAPSHOT | -d SNAPSHOT] FILENAME
+.. option:: snapshot [--object OBJECTDEF] [-f FMT | --image-opts] [-U] [-q] [-l | -a SNAPSHOT | -c SNAPSHOT | -d SNAPSHOT] FILENAME
ERST
DEF("rebase", img_rebase,
diff --git a/qemu-img.c b/qemu-img.c
index e757071..7a162fd 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -60,7 +60,8 @@
typedef struct img_cmd_t {
const char *name;
- int (*handler)(int argc, char **argv);
+ int (*handler)(const struct img_cmd_t *ccmd, int argc, char **argv);
+ const char *description;
} img_cmd_t;
enum {
@@ -72,7 +73,6 @@ enum {
OPTION_FLUSH_INTERVAL = 261,
OPTION_NO_DRAIN = 262,
OPTION_TARGET_IMAGE_OPTS = 263,
- OPTION_SIZE = 264,
OPTION_PREALLOCATION = 265,
OPTION_SHRINK = 266,
OPTION_SALVAGE = 267,
@@ -96,13 +96,15 @@ typedef enum OutputFormat {
/* Default to cache=writeback as data integrity is not important for qemu-img */
#define BDRV_DEFAULT_CACHE "writeback"
-static void format_print(void *opaque, const char *name)
+static G_NORETURN
+void tryhelp(const char *argv0)
{
- printf(" %s", name);
+ error_printf("Try '%s --help' for more information\n", argv0);
+ exit(EXIT_FAILURE);
}
-static G_NORETURN G_GNUC_PRINTF(1, 2)
-void error_exit(const char *fmt, ...)
+static G_NORETURN G_GNUC_PRINTF(2, 3)
+void error_exit(const char *argv0, const char *fmt, ...)
{
va_list ap;
@@ -110,128 +112,43 @@ void error_exit(const char *fmt, ...)
error_vreport(fmt, ap);
va_end(ap);
- error_printf("Try 'qemu-img --help' for more information\n");
- exit(EXIT_FAILURE);
-}
-
-static G_NORETURN
-void missing_argument(const char *option)
-{
- error_exit("missing argument for option '%s'", option);
+ tryhelp(argv0);
}
+/*
+ * Print --help output for a command and exit.
+ * @syntax and @description are multi-line with trailing EOL
+ * (to allow easy extending of the text)
+ * @syntax has each subsequent line indented by 8 chars.
+ * @description is indented by 2 chars for argument on each own line,
+ * and with 5 chars for argument description (like -h arg below).
+ */
static G_NORETURN
-void unrecognized_option(const char *option)
+void cmd_help(const img_cmd_t *ccmd,
+ const char *syntax, const char *arguments)
{
- error_exit("unrecognized option '%s'", option);
+ printf(
+"Usage:\n"
+" %s %s %s\n"
+"%s.\n"
+"\n"
+"Arguments:\n"
+" -h, --help\n"
+" print this help and exit\n"
+"%s\n",
+ "qemu-img", ccmd->name, syntax, ccmd->description, arguments);
+ exit(EXIT_SUCCESS);
}
-/* Please keep in synch with docs/tools/qemu-img.rst */
-static G_NORETURN
-void help(void)
+static OutputFormat parse_output_format(const char *argv0, const char *arg)
{
- const char *help_msg =
- QEMU_IMG_VERSION
- "usage: qemu-img [standard options] command [command options]\n"
- "QEMU disk image utility\n"
- "\n"
- " '-h', '--help' display this help and exit\n"
- " '-V', '--version' output version information and exit\n"
- " '-T', '--trace' [[enable=]<pattern>][,events=<file>][,file=<file>]\n"
- " specify tracing options\n"
- "\n"
- "Command syntax:\n"
-#define DEF(option, callback, arg_string) \
- " " arg_string "\n"
-#include "qemu-img-cmds.h"
-#undef DEF
- "\n"
- "Command parameters:\n"
- " 'filename' is a disk image filename\n"
- " 'objectdef' is a QEMU user creatable object definition. See the qemu(1)\n"
- " manual page for a description of the object properties. The most common\n"
- " object type is a 'secret', which is used to supply passwords and/or\n"
- " encryption keys.\n"
- " 'fmt' is the disk image format. It is guessed automatically in most cases\n"
- " 'cache' is the cache mode used to write the output disk image, the valid\n"
- " options are: 'none', 'writeback' (default, except for convert), 'writethrough',\n"
- " 'directsync' and 'unsafe' (default for convert)\n"
- " 'src_cache' is the cache mode used to read input disk images, the valid\n"
- " options are the same as for the 'cache' option\n"
- " 'size' is the disk image size in bytes. Optional suffixes\n"
- " 'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M),\n"
- " 'T' (terabyte, 1024G), 'P' (petabyte, 1024T) and 'E' (exabyte, 1024P) are\n"
- " supported. 'b' is ignored.\n"
- " 'output_filename' is the destination disk image filename\n"
- " 'output_fmt' is the destination format\n"
- " 'options' is a comma separated list of format specific options in a\n"
- " name=value format. Use -o help for an overview of the options supported by\n"
- " the used format\n"
- " 'snapshot_param' is param used for internal snapshot, format\n"
- " is 'snapshot.id=[ID],snapshot.name=[NAME]', or\n"
- " '[ID_OR_NAME]'\n"
- " '-c' indicates that target image must be compressed (qcow format only)\n"
- " '-u' allows unsafe backing chains. For rebasing, it is assumed that old and\n"
- " new backing file match exactly. The image doesn't need a working\n"
- " backing file before rebasing in this case (useful for renaming the\n"
- " backing file). For image creation, allow creating without attempting\n"
- " to open the backing file.\n"
- " '-h' with or without a command shows this help and lists the supported formats\n"
- " '-p' show progress of command (only certain commands)\n"
- " '-q' use Quiet mode - do not print any output (except errors)\n"
- " '-S' indicates the consecutive number of bytes (defaults to 4k) that must\n"
- " contain only zeros for qemu-img to create a sparse image during\n"
- " conversion. If the number of bytes is 0, the source will not be scanned for\n"
- " unallocated or zero sectors, and the destination image will always be\n"
- " fully allocated\n"
- " '--output' takes the format in which the output must be done (human or json)\n"
- " '-n' skips the target volume creation (useful if the volume is created\n"
- " prior to running qemu-img)\n"
- "\n"
- "Parameters to bitmap subcommand:\n"
- " 'bitmap' is the name of the bitmap to manipulate, through one or more\n"
- " actions from '--add', '--remove', '--clear', '--enable', '--disable',\n"
- " or '--merge source'\n"
- " '-g granularity' sets the granularity for '--add' actions\n"
- " '-b source' and '-F src_fmt' tell '--merge' actions to find the source\n"
- " bitmaps from an alternative file\n"
- "\n"
- "Parameters to check subcommand:\n"
- " '-r' tries to repair any inconsistencies that are found during the check.\n"
- " '-r leaks' repairs only cluster leaks, whereas '-r all' fixes all\n"
- " kinds of errors, with a higher risk of choosing the wrong fix or\n"
- " hiding corruption that has already occurred.\n"
- "\n"
- "Parameters to convert subcommand:\n"
- " '--bitmaps' copies all top-level persistent bitmaps to destination\n"
- " '-m' specifies how many coroutines work in parallel during the convert\n"
- " process (defaults to 8)\n"
- " '-W' allow to write to the target out of order rather than sequential\n"
- "\n"
- "Parameters to snapshot subcommand:\n"
- " 'snapshot' is the name of the snapshot to create, apply or delete\n"
- " '-a' applies a snapshot (revert disk to saved state)\n"
- " '-c' creates a snapshot\n"
- " '-d' deletes a snapshot\n"
- " '-l' lists all snapshots in the given image\n"
- "\n"
- "Parameters to compare subcommand:\n"
- " '-f' first image format\n"
- " '-F' second image format\n"
- " '-s' run in Strict mode - fail on different image size or sector allocation\n"
- "\n"
- "Parameters to dd subcommand:\n"
- " 'bs=BYTES' read and write up to BYTES bytes at a time "
- "(default: 512)\n"
- " 'count=N' copy only N input blocks\n"
- " 'if=FILE' read from FILE\n"
- " 'of=FILE' write to FILE\n"
- " 'skip=N' skip N bs-sized blocks at the start of input\n";
-
- printf("%s\nSupported formats:", help_msg);
- bdrv_iterate_format(format_print, NULL, false);
- printf("\n\n" QEMU_HELP_BOTTOM "\n");
- exit(EXIT_SUCCESS);
+ if (!strcmp(arg, "json")) {
+ return OFORMAT_JSON;
+ } else if (!strcmp(arg, "human")) {
+ return OFORMAT_HUMAN;
+ } else {
+ error_exit(argv0, "--output expects 'human' or 'json', not '%s'", arg);
+ }
}
/*
@@ -481,18 +398,16 @@ static int add_old_style_options(const char *fmt, QemuOpts *opts,
return 0;
}
-static int64_t cvtnum_full(const char *name, const char *value, int64_t min,
- int64_t max)
+static int64_t cvtnum_full(const char *name, const char *value,
+ bool is_size, int64_t min, int64_t max)
{
int err;
uint64_t res;
- err = qemu_strtosz(value, NULL, &res);
+ err = is_size ? qemu_strtosz(value, NULL, &res) :
+ qemu_strtou64(value, NULL, 0, &res);
if (err < 0 && err != -ERANGE) {
- error_report("Invalid %s specified. You may use "
- "k, M, G, T, P or E suffixes for", name);
- error_report("kilobytes, megabytes, gigabytes, terabytes, "
- "petabytes and exabytes.");
+ error_report("Invalid %s specified: '%s'", name, value);
return err;
}
if (err == -ERANGE || res > max || res < min) {
@@ -503,15 +418,15 @@ static int64_t cvtnum_full(const char *name, const char *value, int64_t min,
return res;
}
-static int64_t cvtnum(const char *name, const char *value)
+static int64_t cvtnum(const char *name, const char *value, bool is_size)
{
- return cvtnum_full(name, value, 0, INT64_MAX);
+ return cvtnum_full(name, value, is_size, 0, INT64_MAX);
}
-static int img_create(int argc, char **argv)
+static int img_create(const img_cmd_t *ccmd, int argc, char **argv)
{
int c;
- uint64_t img_size = -1;
+ int64_t img_size = -1;
const char *fmt = "raw";
const char *base_fmt = NULL;
const char *filename;
@@ -524,29 +439,46 @@ static int img_create(int argc, char **argv)
for(;;) {
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
+ {"format", required_argument, 0, 'f'},
+ {"options", required_argument, 0, 'o'},
+ {"backing", required_argument, 0, 'b'},
+ {"backing-format", required_argument, 0, 'B'}, /* was -F in 10.0 */
+ {"backing-unsafe", no_argument, 0, 'u'},
+ {"quiet", no_argument, 0, 'q'},
{"object", required_argument, 0, OPTION_OBJECT},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":F:b:f:ho:qu",
+ c = getopt_long(argc, argv, "hf:o:b:F:B:uq",
long_options, NULL);
if (c == -1) {
break;
}
switch(c) {
- case ':':
- missing_argument(argv[optind - 1]);
- break;
- case '?':
- unrecognized_option(argv[optind - 1]);
- break;
case 'h':
- help();
- break;
- case 'F':
- base_fmt = optarg;
- break;
- case 'b':
- base_filename = optarg;
+ cmd_help(ccmd, "[-f FMT] [-o FMT_OPTS]\n"
+" [-b BACKING_FILE [-B BACKING_FMT]] [-u]\n"
+" [-q] [--object OBJDEF] FILE [SIZE]\n"
+,
+" -f, --format FMT\n"
+" specifies the format of the new image (default: raw)\n"
+" -o, --options FMT_OPTS\n"
+" format-specific options (specify '-o help' for help)\n"
+" -b, --backing BACKING_FILE\n"
+" create target image to be a CoW on top of BACKING_FILE\n"
+" -B, --backing-format BACKING_FMT (was -F in <= 10.0)\n"
+" specifies the format of BACKING_FILE (default: probing is used)\n"
+" -u, --backing-unsafe\n"
+" do not fail if BACKING_FILE can not be read\n"
+" -q, --quiet\n"
+" quiet mode (produce only error messages if any)\n"
+" --object OBJDEF\n"
+" defines QEMU user-creatable object\n"
+" FILE\n"
+" name of the image file to create (will be overritten if already exists)\n"
+" SIZE[bKMGTPE]\n"
+" image size with optional multiplier suffix (powers of 1024)\n"
+" (required unless BACKING_FILE is specified)\n"
+);
break;
case 'f':
fmt = optarg;
@@ -556,15 +488,24 @@ static int img_create(int argc, char **argv)
goto fail;
}
break;
- case 'q':
- quiet = true;
+ case 'b':
+ base_filename = optarg;
+ break;
+ case 'F': /* <=10.0 */
+ case 'B':
+ base_fmt = optarg;
break;
case 'u':
flags |= BDRV_O_NO_BACKING;
break;
+ case 'q':
+ quiet = true;
+ break;
case OPTION_OBJECT:
user_creatable_process_cmdline(optarg);
break;
+ default:
+ tryhelp(argv[0]);
}
}
@@ -576,22 +517,19 @@ static int img_create(int argc, char **argv)
}
if (optind >= argc) {
- error_exit("Expecting image file name");
+ error_exit(argv[0], "Expecting image file name");
}
optind++;
/* Get image size, if specified */
if (optind < argc) {
- int64_t sval;
-
- sval = cvtnum("image size", argv[optind++]);
- if (sval < 0) {
+ img_size = cvtnum("image size", argv[optind++], true);
+ if (img_size < 0) {
goto fail;
}
- img_size = (uint64_t)sval;
}
if (optind != argc) {
- error_exit("Unexpected argument: %s", argv[optind]);
+ error_exit(argv[0], "Unexpected argument: %s", argv[optind]);
}
bdrv_img_create(filename, fmt, base_filename, base_fmt,
@@ -716,11 +654,11 @@ static int collect_image_check(BlockDriverState *bs,
* 3 - Check completed, image has leaked clusters, but is good otherwise
* 63 - Checks are not supported by the image format
*/
-static int img_check(int argc, char **argv)
+static int img_check(const img_cmd_t *ccmd, int argc, char **argv)
{
int c, ret;
OutputFormat output_format = OFORMAT_HUMAN;
- const char *filename, *fmt, *output, *cache;
+ const char *filename, *fmt, *cache;
BlockBackend *blk;
BlockDriverState *bs;
int fix = 0;
@@ -732,7 +670,6 @@ static int img_check(int argc, char **argv)
bool force_share = false;
fmt = NULL;
- output = NULL;
cache = BDRV_DEFAULT_CACHE;
for(;;) {
@@ -740,31 +677,57 @@ static int img_check(int argc, char **argv)
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
{"format", required_argument, 0, 'f'},
+ {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
+ {"cache", required_argument, 0, 'T'},
{"repair", required_argument, 0, 'r'},
+ {"force-share", no_argument, 0, 'U'},
{"output", required_argument, 0, OPTION_OUTPUT},
+ {"quiet", no_argument, 0, 'q'},
{"object", required_argument, 0, OPTION_OBJECT},
- {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
- {"force-share", no_argument, 0, 'U'},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":hf:r:T:qU",
+ c = getopt_long(argc, argv, "hf:T:r:Uq",
long_options, &option_index);
if (c == -1) {
break;
}
switch(c) {
- case ':':
- missing_argument(argv[optind - 1]);
- break;
- case '?':
- unrecognized_option(argv[optind - 1]);
- break;
case 'h':
- help();
+ cmd_help(ccmd, "[-f FMT | --image-opts] [-T CACHE_MODE] [-r leaks|all]\n"
+" [-U] [--output human|json] [-q] [--object OBJDEF] FILE\n"
+,
+" -f, --format FMT\n"
+" specifies the format of the image explicitly (default: probing is used)\n"
+" --image-opts\n"
+" treat FILE as an option string (key=value,..), not a file name\n"
+" (incompatible with -f|--format)\n"
+" -T, --cache CACHE_MODE\n" /* why not -t ? */
+" cache mode (default: " BDRV_DEFAULT_CACHE ")\n"
+" -r, --repair leaks|all\n"
+" repair errors of the given category in the image (image will be\n"
+" opened in read-write mode, incompatible with -U|--force-share)\n"
+" -U, --force-share\n"
+" open image in shared mode for concurrent access\n"
+" --output human|json\n"
+" output format (default: human)\n"
+" -q, --quiet\n"
+" quiet mode (produce only error messages if any)\n"
+" --object OBJDEF\n"
+" defines QEMU user-creatable object\n"
+" FILE\n"
+" name of the image file, or an option string (key=value,..)\n"
+" with --image-opts, to operate on\n"
+);
break;
case 'f':
fmt = optarg;
break;
+ case OPTION_IMAGE_OPTS:
+ image_opts = true;
+ break;
+ case 'T':
+ cache = optarg;
+ break;
case 'r':
flags |= BDRV_O_RDWR;
@@ -773,44 +736,32 @@ static int img_check(int argc, char **argv)
} else if (!strcmp(optarg, "all")) {
fix = BDRV_FIX_LEAKS | BDRV_FIX_ERRORS;
} else {
- error_exit("Unknown option value for -r "
- "(expecting 'leaks' or 'all'): %s", optarg);
+ error_exit(argv[0],
+ "--repair (-r) expects 'leaks' or 'all', not '%s'",
+ optarg);
}
break;
- case OPTION_OUTPUT:
- output = optarg;
+ case 'U':
+ force_share = true;
break;
- case 'T':
- cache = optarg;
+ case OPTION_OUTPUT:
+ output_format = parse_output_format(argv[0], optarg);
break;
case 'q':
quiet = true;
break;
- case 'U':
- force_share = true;
- break;
case OPTION_OBJECT:
user_creatable_process_cmdline(optarg);
break;
- case OPTION_IMAGE_OPTS:
- image_opts = true;
- break;
+ default:
+ tryhelp(argv[0]);
}
}
if (optind != argc - 1) {
- error_exit("Expecting one image file name");
+ error_exit(argv[0], "Expecting one image file name");
}
filename = argv[optind++];
- if (output && !strcmp(output, "json")) {
- output_format = OFORMAT_JSON;
- } else if (output && !strcmp(output, "human")) {
- output_format = OFORMAT_HUMAN;
- } else if (output) {
- error_report("--output must be used with human or json as argument.");
- return 1;
- }
-
ret = bdrv_parse_cache_mode(cache, &flags, &writethrough);
if (ret < 0) {
error_report("Invalid source cache option: %s", cache);
@@ -948,7 +899,7 @@ static void run_block_job(BlockJob *job, Error **errp)
}
}
-static int img_commit(int argc, char **argv)
+static int img_commit(const img_cmd_t *ccmd, int argc, char **argv)
{
int c, ret, flags;
const char *filename, *fmt, *cache, *base;
@@ -968,38 +919,73 @@ static int img_commit(int argc, char **argv)
for(;;) {
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
- {"object", required_argument, 0, OPTION_OBJECT},
+ {"format", required_argument, 0, 'f'},
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
+ {"cache", required_argument, 0, 't'},
+ {"drop", no_argument, 0, 'd'},
+ {"base", required_argument, 0, 'b'},
+ {"rate-limit", required_argument, 0, 'r'},
+ {"progress", no_argument, 0, 'p'},
+ {"quiet", no_argument, 0, 'q'},
+ {"object", required_argument, 0, OPTION_OBJECT},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":f:ht:b:dpqr:",
+ c = getopt_long(argc, argv, "hf:t:db:r:pq",
long_options, NULL);
if (c == -1) {
break;
}
switch(c) {
- case ':':
- missing_argument(argv[optind - 1]);
- break;
- case '?':
- unrecognized_option(argv[optind - 1]);
- break;
case 'h':
- help();
+ cmd_help(ccmd, "[-f FMT | --image-opts] [-t CACHE_MODE] [-b BASE_IMG]\n"
+" [-d] [-r RATE] [-q] [--object OBJDEF] FILE\n"
+,
+" -f, --format FMT\n"
+" specify FILE image format explicitly (default: probing is used)\n"
+" --image-opts\n"
+" treat FILE as an option string (key=value,..), not a file name\n"
+" (incompatible with -f|--format)\n"
+" -t, --cache CACHE_MODE image cache mode (default: " BDRV_DEFAULT_CACHE ")\n"
+" -d, --drop\n"
+" skip emptying FILE on completion\n"
+" -b, --base BASE_IMG\n"
+" image in the backing chain to commit change to\n"
+" (default: immediate backing file; implies --drop)\n"
+" -r, --rate-limit RATE\n"
+" I/O rate limit, in bytes per second\n"
+" -p, --progress\n"
+" display progress information\n"
+" -q, --quiet\n"
+" quiet mode (produce only error messages if any)\n"
+" --object OBJDEF\n"
+" defines QEMU user-creatable object\n"
+" FILE\n"
+" name of the image file, or an option string (key=value,..)\n"
+" with --image-opts, to operate on\n"
+);
break;
case 'f':
fmt = optarg;
break;
+ case OPTION_IMAGE_OPTS:
+ image_opts = true;
+ break;
case 't':
cache = optarg;
break;
+ case 'd':
+ drop = true;
+ break;
case 'b':
base = optarg;
/* -b implies -d */
drop = true;
break;
- case 'd':
- drop = true;
+ case 'r':
+ rate_limit = cvtnum("rate limit", optarg, true);
+ if (rate_limit < 0) {
+ return 1;
+ }
break;
case 'p':
progress = true;
@@ -1007,18 +993,11 @@ static int img_commit(int argc, char **argv)
case 'q':
quiet = true;
break;
- case 'r':
- rate_limit = cvtnum("rate limit", optarg);
- if (rate_limit < 0) {
- return 1;
- }
- break;
case OPTION_OBJECT:
user_creatable_process_cmdline(optarg);
break;
- case OPTION_IMAGE_OPTS:
- image_opts = true;
- break;
+ default:
+ tryhelp(argv[0]);
}
}
@@ -1028,7 +1007,7 @@ static int img_commit(int argc, char **argv)
}
if (optind != argc - 1) {
- error_exit("Expecting one image file name");
+ error_exit(argv[0], "Expecting one image file name");
}
filename = argv[optind++];
@@ -1355,7 +1334,7 @@ static int check_empty_sectors(BlockBackend *blk, int64_t offset,
* 1 - Images differ
* >1 - Error occurred
*/
-static int img_compare(int argc, char **argv)
+static int img_compare(const img_cmd_t *ccmd, int argc, char **argv)
{
const char *fmt1 = NULL, *fmt2 = NULL, *cache, *filename1, *filename2;
BlockBackend *blk1, *blk2;
@@ -1380,25 +1359,51 @@ static int img_compare(int argc, char **argv)
for (;;) {
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
- {"object", required_argument, 0, OPTION_OBJECT},
+ {"a-format", required_argument, 0, 'f'},
+ {"b-format", required_argument, 0, 'F'},
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
+ {"strict", no_argument, 0, 's'},
+ {"cache", required_argument, 0, 'T'},
{"force-share", no_argument, 0, 'U'},
+ {"progress", no_argument, 0, 'p'},
+ {"quiet", no_argument, 0, 'q'},
+ {"object", required_argument, 0, OPTION_OBJECT},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":hf:F:T:pqsU",
+ c = getopt_long(argc, argv, "hf:F:sT:Upq",
long_options, NULL);
if (c == -1) {
break;
}
switch (c) {
- case ':':
- missing_argument(argv[optind - 1]);
- break;
- case '?':
- unrecognized_option(argv[optind - 1]);
- break;
case 'h':
- help();
+ cmd_help(ccmd,
+"[[-f FMT] [-F FMT] | --image-opts] [-s] [-T CACHE]\n"
+" [-U] [-p] [-q] [--object OBJDEF] FILE1 FILE2\n"
+,
+" -f, --a-format FMT\n"
+" specify FILE1 image format explicitly (default: probing is used)\n"
+" -F, --b-format FMT\n"
+" specify FILE2 image format explicitly (default: probing is used)\n"
+" --image-opts\n"
+" treat FILE1 and FILE2 as option strings (key=value,..), not file names\n"
+" (incompatible with -f|--a-format and -F|--b-format)\n"
+" -s, --strict\n"
+" strict mode, also check if sizes are equal\n"
+" -T, --cache CACHE_MODE\n"
+" images caching mode (default: " BDRV_DEFAULT_CACHE ")\n"
+" -U, --force-share\n"
+" open images in shared mode for concurrent access\n"
+" -p, --progress\n"
+" display progress information\n"
+" -q, --quiet\n"
+" quiet mode (produce only error messages if any)\n"
+" --object OBJDEF\n"
+" defines QEMU user-creatable object\n"
+" FILE1, FILE2\n"
+" names of the image files, or option strings (key=value,..)\n"
+" with --image-opts, to compare\n"
+);
break;
case 'f':
fmt1 = optarg;
@@ -1406,39 +1411,29 @@ static int img_compare(int argc, char **argv)
case 'F':
fmt2 = optarg;
break;
+ case OPTION_IMAGE_OPTS:
+ image_opts = true;
+ break;
+ case 's':
+ strict = true;
+ break;
case 'T':
cache = optarg;
break;
+ case 'U':
+ force_share = true;
+ break;
case 'p':
progress = true;
break;
case 'q':
quiet = true;
break;
- case 's':
- strict = true;
- break;
- case 'U':
- force_share = true;
- break;
case OPTION_OBJECT:
- {
- Error *local_err = NULL;
-
- if (!user_creatable_add_from_str(optarg, &local_err)) {
- if (local_err) {
- error_report_err(local_err);
- exit(2);
- } else {
- /* Help was printed */
- exit(EXIT_SUCCESS);
- }
- }
- break;
- }
- case OPTION_IMAGE_OPTS:
- image_opts = true;
+ user_creatable_process_cmdline(optarg);
break;
+ default:
+ tryhelp(argv[0]);
}
}
@@ -1449,7 +1444,7 @@ static int img_compare(int argc, char **argv)
if (optind != argc - 2) {
- error_exit("Expecting two image file names");
+ error_exit(argv[0], "Expecting two image file names");
}
filename1 = argv[optind++];
filename2 = argv[optind++];
@@ -2231,7 +2226,7 @@ static void set_rate_limit(BlockBackend *blk, int64_t rate_limit)
blk_set_io_limits(blk, &cfg);
}
-static int img_convert(int argc, char **argv)
+static int img_convert(const img_cmd_t *ccmd, int argc, char **argv)
{
int c, bs_i, flags, src_flags = BDRV_O_NO_SHARE;
const char *fmt = NULL, *out_fmt = NULL, *cache = "unsafe",
@@ -2267,53 +2262,122 @@ static int img_convert(int argc, char **argv)
for(;;) {
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
- {"object", required_argument, 0, OPTION_OBJECT},
+ {"source-format", required_argument, 0, 'f'},
+ /*
+ * XXX: historic --image-opts acts on source file only,
+ * it seems better to have it affect both source and target,
+ * and have separate --source-image-opts for source,
+ * but this might break existing setups.
+ */
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
- {"force-share", no_argument, 0, 'U'},
- {"target-image-opts", no_argument, 0, OPTION_TARGET_IMAGE_OPTS},
- {"salvage", no_argument, 0, OPTION_SALVAGE},
- {"target-is-zero", no_argument, 0, OPTION_TARGET_IS_ZERO},
+ {"source-cache", required_argument, 0, 'T'},
+ {"snapshot", required_argument, 0, 'l'},
{"bitmaps", no_argument, 0, OPTION_BITMAPS},
{"skip-broken-bitmaps", no_argument, 0, OPTION_SKIP_BROKEN},
+ {"salvage", no_argument, 0, OPTION_SALVAGE},
+ {"target-format", required_argument, 0, 'O'},
+ {"target-image-opts", no_argument, 0, OPTION_TARGET_IMAGE_OPTS},
+ {"target-format-options", required_argument, 0, 'o'},
+ {"target-cache", required_argument, 0, 't'},
+ {"backing", required_argument, 0, 'b'},
+ {"backing-format", required_argument, 0, 'F'},
+ {"sparse-size", required_argument, 0, 'S'},
+ {"no-create", no_argument, 0, 'n'},
+ {"target-is-zero", no_argument, 0, OPTION_TARGET_IS_ZERO},
+ {"force-share", no_argument, 0, 'U'},
+ {"rate-limit", required_argument, 0, 'r'},
+ {"parallel", required_argument, 0, 'm'},
+ {"oob-writes", no_argument, 0, 'W'},
+ {"copy-range-offloading", no_argument, 0, 'C'},
+ {"progress", no_argument, 0, 'p'},
+ {"quiet", no_argument, 0, 'q'},
+ {"object", required_argument, 0, OPTION_OBJECT},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":hf:O:B:CcF:o:l:S:pt:T:qnm:WUr:",
+ c = getopt_long(argc, argv, "hf:O:b:B:CcF:o:l:S:pt:T:nm:WUr:q",
long_options, NULL);
if (c == -1) {
break;
}
- switch(c) {
- case ':':
- missing_argument(argv[optind - 1]);
- break;
- case '?':
- unrecognized_option(argv[optind - 1]);
- break;
+ switch (c) {
case 'h':
- help();
+ cmd_help(ccmd, "[-f SRC_FMT | --image-opts] [-T SRC_CACHE]\n"
+" [-l SNAPSHOT] [--bitmaps [--skip-broken-bitmaps]] [--salvage]\n"
+" [-O TGT_FMT | --target-image-opts] [-o TGT_FMT_OPTS] [-t TGT_CACHE]\n"
+" [-b BACKING_FILE [-F BACKING_FMT]] [-S SPARSE_SIZE]\n"
+" [-n] [--target-is-zero] [-c]\n"
+" [-U] [-r RATE] [-m NUM_PARALLEL] [-W] [-C] [-p] [-q] [--object OBJDEF]\n"
+" SRC_FILE [SRC_FILE2...] TGT_FILE\n"
+,
+" -f, --source-format SRC_FMT\n"
+" specify format of all SRC_FILEs explicitly (default: probing is used)\n"
+" --image-opts\n"
+" treat each SRC_FILE as an option string (key=value,...), not a file name\n"
+" (incompatible with -f|--source-format)\n"
+" -T, --source-cache SRC_CACHE\n"
+" source image(s) cache mode (" BDRV_DEFAULT_CACHE ")\n"
+" -l, --snapshot SNAPSHOT\n"
+" specify source snapshot\n"
+" --bitmaps\n"
+" also copy any persistent bitmaps present in source\n"
+" --skip-broken-bitmaps\n"
+" skip (do not error out) any broken bitmaps\n"
+" --salvage\n"
+" ignore errors on input (convert unreadable areas to zeros)\n"
+" -O, --target-format TGT_FMT\n"
+" specify TGT_FILE image format (default: raw)\n"
+" --target-image-opts\n"
+" treat TGT_FILE as an option string (key=value,...), not a file name\n"
+" (incompatible with -O|--target-format)\n"
+" -o, --target-format-options TGT_FMT_OPTS\n"
+" TGT_FMT-specific options\n"
+" -t, --target-cache TGT_CACHE\n"
+" cache mode when opening output image (default: unsafe)\n"
+" -b, --backing BACKING_FILE (was -B in <= 10.0)\n"
+" create target image to be a CoW on top of BACKING_FILE\n"
+" -F, --backing-format BACKING_FMT\n" /* -B used for -b in <=10.0 */
+" specify BACKING_FILE image format explicitly (default: probing is used)\n"
+" -S, --sparse-size SPARSE_SIZE[bkKMGTPE]\n"
+" specify number of consecutive zero bytes to treat as a gap on output\n"
+" (rounded down to nearest 512 bytes), with optional multiplier suffix\n"
+" -n, --no-create\n"
+" omit target volume creation (e.g. on rbd)\n"
+" --target-is-zero\n"
+" indicates that the target volume is pre-zeroed\n"
+" -c, --compress\n"
+" create compressed output image (qcow and qcow2 formats only)\n"
+" -U, --force-share\n"
+" open images in shared mode for concurrent access\n"
+" -r, --rate-limit RATE\n"
+" I/O rate limit, in bytes per second\n"
+" -m, --parallel NUM_PARALLEL\n"
+" specify parallelism (default: 8)\n"
+" -C, --copy-range-offloading\n"
+" try to use copy offloading\n"
+" -W, --oob-writes\n"
+" enable out-of-order writes to improve performance\n"
+" -p, --progress\n"
+" display progress information\n"
+" -q, --quiet\n"
+" quiet mode (produce only error messages if any)\n"
+" --object OBJDEF\n"
+" defines QEMU user-creatable object\n"
+" SRC_FILE...\n"
+" one or more source image file names,\n"
+" or option strings (key=value,..) with --source-image-opts\n"
+" TGT_FILE\n"
+" target (output) image file name,\n"
+" or option string (key=value,..) with --target-image-opts\n"
+);
break;
case 'f':
fmt = optarg;
break;
- case 'O':
- out_fmt = optarg;
- break;
- case 'B':
- out_baseimg = optarg;
- break;
- case 'C':
- s.copy_range = true;
- break;
- case 'c':
- s.compressed = true;
- break;
- case 'F':
- backing_fmt = optarg;
+ case OPTION_IMAGE_OPTS:
+ image_opts = true;
break;
- case 'o':
- if (accumulate_options(&options, optarg) < 0) {
- goto fail_getopt;
- }
+ case 'T':
+ src_cache = optarg;
break;
case 'l':
if (strstart(optarg, SNAPSHOT_OPT_BASE, NULL)) {
@@ -2328,11 +2392,41 @@ static int img_convert(int argc, char **argv)
snapshot_name = optarg;
}
break;
+ case OPTION_BITMAPS:
+ bitmaps = true;
+ break;
+ case OPTION_SKIP_BROKEN:
+ skip_broken = true;
+ break;
+ case OPTION_SALVAGE:
+ s.salvage = true;
+ break;
+ case 'O':
+ out_fmt = optarg;
+ break;
+ case OPTION_TARGET_IMAGE_OPTS:
+ tgt_image_opts = true;
+ break;
+ case 'o':
+ if (accumulate_options(&options, optarg) < 0) {
+ goto fail_getopt;
+ }
+ break;
+ case 't':
+ cache = optarg;
+ break;
+ case 'B': /* <=10.0 */
+ case 'b':
+ out_baseimg = optarg;
+ break;
+ case 'F': /* can't use -B as it used as -b in <=10.0 */
+ backing_fmt = optarg;
+ break;
case 'S':
{
int64_t sval;
- sval = cvtnum("buffer size for sparse output", optarg);
+ sval = cvtnum("buffer size for sparse output", optarg, true);
if (sval < 0) {
goto fail_getopt;
} else if (!QEMU_IS_ALIGNED(sval, BDRV_SECTOR_SIZE) ||
@@ -2348,67 +2442,53 @@ static int img_convert(int argc, char **argv)
explict_min_sparse = true;
break;
}
- case 'p':
- progress = true;
- break;
- case 't':
- cache = optarg;
- break;
- case 'T':
- src_cache = optarg;
- break;
- case 'q':
- s.quiet = true;
- break;
case 'n':
skip_create = true;
break;
- case 'm':
- if (qemu_strtol(optarg, NULL, 0, &s.num_coroutines) ||
- s.num_coroutines < 1 || s.num_coroutines > MAX_COROUTINES) {
- error_report("Invalid number of coroutines. Allowed number of"
- " coroutines is between 1 and %d", MAX_COROUTINES);
- goto fail_getopt;
- }
+ case OPTION_TARGET_IS_ZERO:
+ /*
+ * The user asserting that the target is blank has the
+ * same effect as the target driver supporting zero
+ * initialisation.
+ */
+ s.has_zero_init = true;
break;
- case 'W':
- s.wr_in_order = false;
+ case 'c':
+ s.compressed = true;
break;
case 'U':
force_share = true;
break;
case 'r':
- rate_limit = cvtnum("rate limit", optarg);
+ rate_limit = cvtnum("rate limit", optarg, true);
if (rate_limit < 0) {
goto fail_getopt;
}
break;
- case OPTION_OBJECT:
- user_creatable_process_cmdline(optarg);
- break;
- case OPTION_IMAGE_OPTS:
- image_opts = true;
+ case 'm':
+ s.num_coroutines = cvtnum_full("number of coroutines", optarg,
+ false, 1, MAX_COROUTINES);
+ if (s.num_coroutines < 0) {
+ goto fail_getopt;
+ }
break;
- case OPTION_SALVAGE:
- s.salvage = true;
+ case 'W':
+ s.wr_in_order = false;
break;
- case OPTION_TARGET_IMAGE_OPTS:
- tgt_image_opts = true;
+ case 'C':
+ s.copy_range = true;
break;
- case OPTION_TARGET_IS_ZERO:
- /*
- * The user asserting that the target is blank has the
- * same effect as the target driver supporting zero
- * initialisation.
- */
- s.has_zero_init = true;
+ case 'p':
+ progress = true;
break;
- case OPTION_BITMAPS:
- bitmaps = true;
+ case 'q':
+ s.quiet = true;
break;
- case OPTION_SKIP_BROKEN:
- skip_broken = true;
+ case OPTION_OBJECT:
+ user_creatable_process_cmdline(optarg);
break;
+ default:
+ tryhelp(argv[0]);
}
}
@@ -2999,79 +3079,82 @@ err:
return NULL;
}
-static int img_info(int argc, char **argv)
+static int img_info(const img_cmd_t *ccmd, int argc, char **argv)
{
int c;
OutputFormat output_format = OFORMAT_HUMAN;
bool chain = false;
- const char *filename, *fmt, *output;
+ const char *filename, *fmt;
BlockGraphInfoList *list;
bool image_opts = false;
bool force_share = false;
fmt = NULL;
- output = NULL;
for(;;) {
- int option_index = 0;
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
{"format", required_argument, 0, 'f'},
- {"output", required_argument, 0, OPTION_OUTPUT},
- {"backing-chain", no_argument, 0, OPTION_BACKING_CHAIN},
- {"object", required_argument, 0, OPTION_OBJECT},
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
+ {"backing-chain", no_argument, 0, OPTION_BACKING_CHAIN},
{"force-share", no_argument, 0, 'U'},
+ {"output", required_argument, 0, OPTION_OUTPUT},
+ {"object", required_argument, 0, OPTION_OBJECT},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":f:hU",
- long_options, &option_index);
+ c = getopt_long(argc, argv, "hf:U", long_options, NULL);
if (c == -1) {
break;
}
switch(c) {
- case ':':
- missing_argument(argv[optind - 1]);
- break;
- case '?':
- unrecognized_option(argv[optind - 1]);
- break;
case 'h':
- help();
+ cmd_help(ccmd, "[-f FMT | --image-opts] [--backing-chain] [-U]\n"
+" [--output human|json] [--object OBJDEF] FILE\n"
+,
+" -f, --format FMT\n"
+" specify FILE image format explicitly (default: probing is used)\n"
+" --image-opts\n"
+" treat FILE as an option string (key=value,..), not a file name\n"
+" (incompatible with -f|--format)\n"
+" --backing-chain\n"
+" display information about the backing chain for copy-on-write overlays\n"
+" -U, --force-share\n"
+" open image in shared mode for concurrent access\n"
+" --output human|json\n"
+" specify output format (default: human)\n"
+" --object OBJDEF\n"
+" defines QEMU user-creatable object\n"
+" FILE\n"
+" name of the image file, or option string (key=value,..)\n"
+" with --image-opts, to operate on\n"
+);
break;
case 'f':
fmt = optarg;
break;
+ case OPTION_IMAGE_OPTS:
+ image_opts = true;
+ break;
+ case OPTION_BACKING_CHAIN:
+ chain = true;
+ break;
case 'U':
force_share = true;
break;
case OPTION_OUTPUT:
- output = optarg;
- break;
- case OPTION_BACKING_CHAIN:
- chain = true;
+ output_format = parse_output_format(argv[0], optarg);
break;
case OPTION_OBJECT:
user_creatable_process_cmdline(optarg);
break;
- case OPTION_IMAGE_OPTS:
- image_opts = true;
- break;
+ default:
+ tryhelp(argv[0]);
}
}
if (optind != argc - 1) {
- error_exit("Expecting one image file name");
+ error_exit(argv[0], "Expecting one image file name");
}
filename = argv[optind++];
- if (output && !strcmp(output, "json")) {
- output_format = OFORMAT_JSON;
- } else if (output && !strcmp(output, "human")) {
- output_format = OFORMAT_HUMAN;
- } else if (output) {
- error_report("--output must be used with human or json as argument.");
- return 1;
- }
-
list = collect_image_info_list(image_opts, filename, fmt, chain,
force_share);
if (!list) {
@@ -3224,13 +3307,13 @@ static inline bool entry_mergeable(const MapEntry *curr, const MapEntry *next)
return true;
}
-static int img_map(int argc, char **argv)
+static int img_map(const img_cmd_t *ccmd, int argc, char **argv)
{
int c;
OutputFormat output_format = OFORMAT_HUMAN;
BlockBackend *blk;
BlockDriverState *bs;
- const char *filename, *fmt, *output;
+ const char *filename, *fmt;
int64_t length;
MapEntry curr = { .length = 0 }, next;
int ret = 0;
@@ -3240,78 +3323,85 @@ static int img_map(int argc, char **argv)
int64_t max_length = -1;
fmt = NULL;
- output = NULL;
for (;;) {
- int option_index = 0;
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
{"format", required_argument, 0, 'f'},
- {"output", required_argument, 0, OPTION_OUTPUT},
- {"object", required_argument, 0, OPTION_OBJECT},
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
- {"force-share", no_argument, 0, 'U'},
{"start-offset", required_argument, 0, 's'},
{"max-length", required_argument, 0, 'l'},
+ {"force-share", no_argument, 0, 'U'},
+ {"output", required_argument, 0, OPTION_OUTPUT},
+ {"object", required_argument, 0, OPTION_OBJECT},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":f:s:l:hU",
- long_options, &option_index);
+ c = getopt_long(argc, argv, "hf:s:l:U",
+ long_options, NULL);
if (c == -1) {
break;
}
switch (c) {
- case ':':
- missing_argument(argv[optind - 1]);
- break;
- case '?':
- unrecognized_option(argv[optind - 1]);
- break;
case 'h':
- help();
+ cmd_help(ccmd, "[-f FMT | --image-opts]\n"
+" [--start-offset OFFSET] [--max-length LENGTH]\n"
+" [--output human|json] [-U] [--object OBJDEF] FILE\n"
+,
+" -f, --format FMT\n"
+" specify FILE image format explicitly (default: probing is used)\n"
+" --image-opts\n"
+" treat FILE as an option string (key=value,..), not a file name\n"
+" (incompatible with -f|--format)\n"
+" -s, --start-offset OFFSET\n"
+" start at the given OFFSET in the image, not at the beginning\n"
+" -l, --max-length LENGTH\n"
+" process at most LENGTH bytes instead of up to the end of the image\n"
+" --output human|json\n"
+" specify output format name (default: human)\n"
+" -U, --force-share\n"
+" open image in shared mode for concurrent access\n"
+" --object OBJDEF\n"
+" defines QEMU user-creatable object\n"
+" FILE\n"
+" the image file name, or option string (key=value,..)\n"
+" with --image-opts, to operate on\n"
+);
break;
case 'f':
fmt = optarg;
break;
- case 'U':
- force_share = true;
- break;
- case OPTION_OUTPUT:
- output = optarg;
+ case OPTION_IMAGE_OPTS:
+ image_opts = true;
break;
case 's':
- start_offset = cvtnum("start offset", optarg);
+ start_offset = cvtnum("start offset", optarg, true);
if (start_offset < 0) {
return 1;
}
break;
case 'l':
- max_length = cvtnum("max length", optarg);
+ max_length = cvtnum("max length", optarg, true);
if (max_length < 0) {
return 1;
}
break;
+ case OPTION_OUTPUT:
+ output_format = parse_output_format(argv[0], optarg);
+ break;
+ case 'U':
+ force_share = true;
+ break;
case OPTION_OBJECT:
user_creatable_process_cmdline(optarg);
break;
- case OPTION_IMAGE_OPTS:
- image_opts = true;
- break;
+ default:
+ tryhelp(argv[0]);
}
}
if (optind != argc - 1) {
- error_exit("Expecting one image file name");
+ error_exit(argv[0], "Expecting one image file name");
}
filename = argv[optind];
- if (output && !strcmp(output, "json")) {
- output_format = OFORMAT_JSON;
- } else if (output && !strcmp(output, "human")) {
- output_format = OFORMAT_HUMAN;
- } else if (output) {
- error_report("--output must be used with human or json as argument.");
- return 1;
- }
-
blk = img_open(image_opts, filename, fmt, 0, false, false, force_share);
if (!blk) {
return 1;
@@ -3368,18 +3458,19 @@ out:
return ret < 0;
}
-#define SNAPSHOT_LIST 1
-#define SNAPSHOT_CREATE 2
-#define SNAPSHOT_APPLY 3
-#define SNAPSHOT_DELETE 4
+/* the same as options */
+#define SNAPSHOT_LIST 'l'
+#define SNAPSHOT_CREATE 'c'
+#define SNAPSHOT_APPLY 'a'
+#define SNAPSHOT_DELETE 'd'
-static int img_snapshot(int argc, char **argv)
+static int img_snapshot(const img_cmd_t *ccmd, int argc, char **argv)
{
BlockBackend *blk;
BlockDriverState *bs;
QEMUSnapshotInfo sn;
- char *filename, *snapshot_name = NULL;
- int c, ret = 0, bdrv_oflags;
+ char *filename, *fmt = NULL, *snapshot_name = NULL;
+ int c, ret = 0;
int action = 0;
bool quiet = false;
Error *err = NULL;
@@ -3387,86 +3478,100 @@ static int img_snapshot(int argc, char **argv)
bool force_share = false;
int64_t rt;
- bdrv_oflags = BDRV_O_RDWR;
/* Parse commandline parameters */
for(;;) {
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
- {"object", required_argument, 0, OPTION_OBJECT},
+ {"format", required_argument, 0, 'f'},
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
+ {"list", no_argument, 0, SNAPSHOT_LIST},
+ {"apply", required_argument, 0, SNAPSHOT_APPLY},
+ {"create", required_argument, 0, SNAPSHOT_CREATE},
+ {"delete", required_argument, 0, SNAPSHOT_DELETE},
{"force-share", no_argument, 0, 'U'},
+ {"quiet", no_argument, 0, 'q'},
+ {"object", required_argument, 0, OPTION_OBJECT},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":la:c:d:hqU",
+ c = getopt_long(argc, argv, "hf:la:c:d:Uq",
long_options, NULL);
if (c == -1) {
break;
}
switch(c) {
- case ':':
- missing_argument(argv[optind - 1]);
- break;
- case '?':
- unrecognized_option(argv[optind - 1]);
- break;
case 'h':
- help();
- return 0;
- case 'l':
- if (action) {
- error_exit("Cannot mix '-l', '-a', '-c', '-d'");
- return 0;
- }
- action = SNAPSHOT_LIST;
- bdrv_oflags &= ~BDRV_O_RDWR; /* no need for RW */
+ cmd_help(ccmd, "[-f FMT | --image-opts] [-l | -a|-c|-d SNAPSHOT]\n"
+" [-U] [-q] [--object OBJDEF] FILE\n"
+,
+" -f, --format FMT\n"
+" specify FILE format explicitly (default: probing is used)\n"
+" --image-opts\n"
+" treat FILE as an option string (key=value,..), not a file name\n"
+" (incompatible with -f|--format)\n"
+" -l, --list\n"
+" list snapshots in FILE (default action if no -l|-c|-a|-d is given)\n"
+" -c, --create SNAPSHOT\n"
+" create named snapshot\n"
+" -a, --apply SNAPSHOT\n"
+" apply named snapshot to the base\n"
+" -d, --delete SNAPSHOT\n"
+" delete named snapshot\n"
+" (only one of -l|-c|-a|-d can be specified)\n"
+" -U, --force-share\n"
+" open image in shared mode for concurrent access\n"
+" -q, --quiet\n"
+" quiet mode (produce only error messages if any)\n"
+" --object OBJDEF\n"
+" defines QEMU user-creatable object\n"
+" FILE\n"
+" name of the image file, or option string (key=value,..)\n"
+" with --image-opts) to operate on\n"
+);
break;
- case 'a':
- if (action) {
- error_exit("Cannot mix '-l', '-a', '-c', '-d'");
- return 0;
- }
- action = SNAPSHOT_APPLY;
- snapshot_name = optarg;
+ case 'f':
+ fmt = optarg;
break;
- case 'c':
- if (action) {
- error_exit("Cannot mix '-l', '-a', '-c', '-d'");
- return 0;
- }
- action = SNAPSHOT_CREATE;
- snapshot_name = optarg;
+ case OPTION_IMAGE_OPTS:
+ image_opts = true;
break;
- case 'd':
+ case SNAPSHOT_LIST:
+ case SNAPSHOT_APPLY:
+ case SNAPSHOT_CREATE:
+ case SNAPSHOT_DELETE:
if (action) {
- error_exit("Cannot mix '-l', '-a', '-c', '-d'");
+ error_exit(argv[0], "Cannot mix '-l', '-a', '-c', '-d'");
return 0;
}
- action = SNAPSHOT_DELETE;
+ action = c;
snapshot_name = optarg;
break;
- case 'q':
- quiet = true;
- break;
case 'U':
force_share = true;
break;
+ case 'q':
+ quiet = true;
+ break;
case OPTION_OBJECT:
user_creatable_process_cmdline(optarg);
break;
- case OPTION_IMAGE_OPTS:
- image_opts = true;
- break;
+ default:
+ tryhelp(argv[0]);
}
}
if (optind != argc - 1) {
- error_exit("Expecting one image file name");
+ error_exit(argv[0], "Expecting one image file name");
}
filename = argv[optind++];
+ if (!action) {
+ action = SNAPSHOT_LIST;
+ }
+
/* Open the image */
- blk = img_open(image_opts, filename, NULL, bdrv_oflags, false, quiet,
- force_share);
+ blk = img_open(image_opts, filename, fmt,
+ action == SNAPSHOT_LIST ? 0 : BDRV_O_RDWR,
+ false, quiet, force_share);
if (!blk) {
return 1;
}
@@ -3533,7 +3638,7 @@ static int img_snapshot(int argc, char **argv)
return 0;
}
-static int img_rebase(int argc, char **argv)
+static int img_rebase(const img_cmd_t *ccmd, int argc, char **argv)
{
BlockBackend *blk = NULL, *blk_old_backing = NULL, *blk_new_backing = NULL;
uint8_t *buf_old = NULL;
@@ -3564,45 +3669,89 @@ static int img_rebase(int argc, char **argv)
for(;;) {
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
- {"object", required_argument, 0, OPTION_OBJECT},
+ {"format", required_argument, 0, 'f'},
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
- {"force-share", no_argument, 0, 'U'},
+ {"cache", required_argument, 0, 't'},
{"compress", no_argument, 0, 'c'},
+ {"backing", required_argument, 0, 'b'},
+ {"backing-format", required_argument, 0, 'B'},
+ {"backing-cache", required_argument, 0, 'T'},
+ {"backing-unsafe", no_argument, 0, 'u'},
+ {"force-share", no_argument, 0, 'U'},
+ {"progress", no_argument, 0, 'p'},
+ {"quiet", no_argument, 0, 'q'},
+ {"object", required_argument, 0, OPTION_OBJECT},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":hf:F:b:upt:T:qUc",
+ c = getopt_long(argc, argv, "hf:t:cb:F:B:T:uUpq",
long_options, NULL);
if (c == -1) {
break;
}
- switch(c) {
- case ':':
- missing_argument(argv[optind - 1]);
- break;
- case '?':
- unrecognized_option(argv[optind - 1]);
- break;
+ switch (c) {
case 'h':
- help();
+ cmd_help(ccmd, "[-f FMT | --image-opts] [-t CACHE]\n"
+" [-b BACKING_FILE [-B BACKING_FMT] [-T BACKING_CACHE]] [-u]\n"
+" [-c] [-U] [-p] [-q] [--object OBJDEF] FILE\n"
+,
+" -f, --format FMT\n"
+" specify FILE format explicitly (default: probing is used)\n"
+" --image-opts\n"
+" treat FILE as an option string (key=value,..), not a file name\n"
+" (incompatible with -f|--format)\n"
+" -t, --cache CACHE\n"
+" cache mode for FILE (default: " BDRV_DEFAULT_CACHE ")\n"
+" -b, --backing BACKING_FILE|\"\"\n"
+" rebase onto this file (specify empty name for no backing file)\n"
+" -B, --backing-format BACKING_FMT (was -F in <=10.0)\n"
+" specify format for BACKING_FILE explicitly (default: probing is used)\n"
+" -T, --backing-cache CACHE\n"
+" BACKING_FILE cache mode (default: " BDRV_DEFAULT_CACHE ")\n"
+" -u, --backing-unsafe\n"
+" do not fail if BACKING_FILE can not be read\n"
+" -c, --compress\n"
+" compress image (when image supports this)\n"
+" -U, --force-share\n"
+" open image in shared mode for concurrent access\n"
+" -p, --progress\n"
+" display progress information\n"
+" -q, --quiet\n"
+" quiet mode (produce only error messages if any)\n"
+" --object OBJDEF\n"
+" defines QEMU user-creatable object\n"
+" FILE\n"
+" name of the image file, or option string (key=value,..)\n"
+" with --image-opts, to operate on\n"
+);
return 0;
case 'f':
fmt = optarg;
break;
- case 'F':
- out_basefmt = optarg;
+ case OPTION_IMAGE_OPTS:
+ image_opts = true;
+ break;
+ case 't':
+ cache = optarg;
break;
case 'b':
out_baseimg = optarg;
break;
+ case 'F': /* <=10.0 */
+ case 'B':
+ out_basefmt = optarg;
+ break;
case 'u':
unsafe = 1;
break;
+ case 'c':
+ compress = true;
+ break;
+ case 'U':
+ force_share = true;
+ break;
case 'p':
progress = 1;
break;
- case 't':
- cache = optarg;
- break;
case 'T':
src_cache = optarg;
break;
@@ -3612,15 +3761,8 @@ static int img_rebase(int argc, char **argv)
case OPTION_OBJECT:
user_creatable_process_cmdline(optarg);
break;
- case OPTION_IMAGE_OPTS:
- image_opts = true;
- break;
- case 'U':
- force_share = true;
- break;
- case 'c':
- compress = true;
- break;
+ default:
+ tryhelp(argv[0]);
}
}
@@ -3629,10 +3771,11 @@ static int img_rebase(int argc, char **argv)
}
if (optind != argc - 1) {
- error_exit("Expecting one image file name");
+ error_exit(argv[0], "Expecting one image file name");
}
if (!unsafe && !out_baseimg) {
- error_exit("Must specify backing file (-b) or use unsafe mode (-u)");
+ error_exit(argv[0],
+ "Must specify backing file (-b) or use unsafe mode (-u)");
}
filename = argv[optind++];
@@ -4026,11 +4169,11 @@ out:
return 0;
}
-static int img_resize(int argc, char **argv)
+static int img_resize(const img_cmd_t *ccmd, int argc, char **argv)
{
Error *err = NULL;
int c, ret, relative;
- const char *filename, *fmt, *size;
+ const char *filename = NULL, *fmt = NULL, *size = NULL;
int64_t n, total_size, current_size;
bool quiet = false;
BlockBackend *blk = NULL;
@@ -4053,50 +4196,52 @@ static int img_resize(int argc, char **argv)
bool image_opts = false;
bool shrink = false;
- /* Remove size from argv manually so that negative numbers are not treated
- * as options by getopt. */
- if (argc < 3) {
- error_exit("Not enough arguments");
- return 1;
- }
-
- size = argv[--argc];
-
/* Parse getopt arguments */
- fmt = NULL;
for(;;) {
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
- {"object", required_argument, 0, OPTION_OBJECT},
+ {"format", required_argument, 0, 'f'},
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
{"preallocation", required_argument, 0, OPTION_PREALLOCATION},
{"shrink", no_argument, 0, OPTION_SHRINK},
+ {"quiet", no_argument, 0, 'q'},
+ {"object", required_argument, 0, OPTION_OBJECT},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":f:hq",
+ c = getopt_long(argc, argv, "-hf:q",
long_options, NULL);
if (c == -1) {
break;
}
switch(c) {
- case ':':
- missing_argument(argv[optind - 1]);
- break;
- case '?':
- unrecognized_option(argv[optind - 1]);
- break;
case 'h':
- help();
- break;
+ cmd_help(ccmd, "[-f FMT | --image-opts] [--preallocation PREALLOC] [--shrink]\n"
+" [-q] [--object OBJDEF] FILE [+-]SIZE[bkKMGTPE]\n"
+,
+" -f, --format FMT\n"
+" specify FILE format explicitly (default: probing is used)\n"
+" --image-opts\n"
+" treat FILE as an option string (key=value,...), not a file name\n"
+" (incompatible with -f|--format)\n"
+" --shrink\n"
+" allow operation when the new size is smaller than the original\n"
+" --preallocation PREALLOC\n"
+" specify FMT-specific preallocation type for the new areas\n"
+" -q, --quiet\n"
+" quiet mode (produce only error messages if any)\n"
+" --object OBJDEF\n"
+" defines QEMU user-creatable object\n"
+" FILE\n"
+" name of the image file, or option string (key=value,..)\n"
+" with --image-opts, to operate on\n"
+" [+-]SIZE[bkKMGTPE]\n"
+" new image size or amount by which to shrink (-)/grow (+),\n"
+" with optional multiplier suffix (powers of 1024, default is bytes)\n"
+);
+ return 0;
case 'f':
fmt = optarg;
break;
- case 'q':
- quiet = true;
- break;
- case OPTION_OBJECT:
- user_creatable_process_cmdline(optarg);
- break;
case OPTION_IMAGE_OPTS:
image_opts = true;
break;
@@ -4111,12 +4256,43 @@ static int img_resize(int argc, char **argv)
case OPTION_SHRINK:
shrink = true;
break;
+ case 'q':
+ quiet = true;
+ break;
+ case OPTION_OBJECT:
+ user_creatable_process_cmdline(optarg);
+ break;
+ case 1: /* a non-optional argument */
+ if (!filename) {
+ filename = optarg;
+ /* see if we have -size (number) next to filename */
+ if (optind < argc) {
+ size = argv[optind];
+ if (size[0] == '-' && size[1] >= '0' && size[1] <= '9') {
+ ++optind;
+ } else {
+ size = NULL;
+ }
+ }
+ } else if (!size) {
+ size = optarg;
+ } else {
+ error_exit(argv[0], "Extra argument(s) in command line");
+ }
+ break;
+ default:
+ tryhelp(argv[0]);
}
}
- if (optind != argc - 1) {
- error_exit("Expecting image file name and size");
+ if (!filename && optind < argc) {
+ filename = argv[optind++];
+ }
+ if (!size && optind < argc) {
+ size = argv[optind++];
+ }
+ if (!filename || !size || optind < argc) {
+ error_exit(argv[0], "Expecting image file name and size");
}
- filename = argv[optind++];
/* Choose grow, shrink, or absolute resize mode */
switch (size[0]) {
@@ -4239,7 +4415,7 @@ static int print_amend_option_help(const char *format)
return 0;
}
-static int img_amend(int argc, char **argv)
+static int img_amend(const img_cmd_t *ccmd, int argc, char **argv)
{
Error *err = NULL;
int c, ret = 0;
@@ -4259,26 +4435,48 @@ static int img_amend(int argc, char **argv)
for (;;) {
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
- {"object", required_argument, 0, OPTION_OBJECT},
+ {"options", required_argument, 0, 'o'},
+ {"format", required_argument, 0, 'f'},
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
+ {"cache", required_argument, 0, 't'},
{"force", no_argument, 0, OPTION_FORCE},
+ {"progress", no_argument, 0, 'p'},
+ {"quiet", no_argument, 0, 'q'},
+ {"object", required_argument, 0, OPTION_OBJECT},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":ho:f:t:pq",
+ c = getopt_long(argc, argv, "ho:f:t:pq",
long_options, NULL);
if (c == -1) {
break;
}
switch (c) {
- case ':':
- missing_argument(argv[optind - 1]);
- break;
- case '?':
- unrecognized_option(argv[optind - 1]);
- break;
case 'h':
- help();
+ cmd_help(ccmd, "-o FMT_OPTS [-f FMT | --image-opts]\n"
+" [-t CACHE] [--force] [-p] [-q] [--object OBJDEF] FILE\n"
+,
+" -o, --options FMT_OPTS\n"
+" FMT-specfic format options (required)\n"
+" -f, --format FMT\n"
+" specify FILE format explicitly (default: probing is used)\n"
+" --image-opts\n"
+" treat FILE as an option string (key=value,..), not a file name\n"
+" (incompatible with -f|--format)\n"
+" -t, --cache CACHE\n"
+" cache mode for FILE (default: " BDRV_DEFAULT_CACHE ")\n"
+" --force\n"
+" allow certain unsafe operations\n"
+" -p, --progres\n"
+" show operation progress\n"
+" -q, --quiet\n"
+" quiet mode (produce only error messages if any)\n"
+" --object OBJDEF\n"
+" defines QEMU user-creatable object\n"
+" FILE\n"
+" name of the image file, or option string (key=value,..)\n"
+" with --image-opts, to operate on\n"
+);
break;
case 'o':
if (accumulate_options(&options, optarg) < 0) {
@@ -4289,9 +4487,15 @@ static int img_amend(int argc, char **argv)
case 'f':
fmt = optarg;
break;
+ case OPTION_IMAGE_OPTS:
+ image_opts = true;
+ break;
case 't':
cache = optarg;
break;
+ case OPTION_FORCE:
+ force = true;
+ break;
case 'p':
progress = true;
break;
@@ -4301,17 +4505,13 @@ static int img_amend(int argc, char **argv)
case OPTION_OBJECT:
user_creatable_process_cmdline(optarg);
break;
- case OPTION_IMAGE_OPTS:
- image_opts = true;
- break;
- case OPTION_FORCE:
- force = true;
- break;
+ default:
+ tryhelp(argv[0]);
}
}
if (!options) {
- error_exit("Must specify options (-o)");
+ error_exit(argv[0], "Must specify options (-o)");
}
if (quiet) {
@@ -4507,7 +4707,7 @@ static void bench_cb(void *opaque, int ret)
}
}
-static int img_bench(int argc, char **argv)
+static int img_bench(const img_cmd_t *ccmd, int argc, char **argv)
{
int c, ret = 0;
const char *fmt = NULL, *filename;
@@ -4517,9 +4717,9 @@ static int img_bench(int argc, char **argv)
int count = 75000;
int depth = 64;
int64_t offset = 0;
- size_t bufsize = 4096;
+ ssize_t bufsize = 4096;
int pattern = 0;
- size_t step = 0;
+ ssize_t step = 0;
int flush_interval = 0;
bool drain_on_flush = true;
int64_t image_size;
@@ -4535,53 +4735,105 @@ static int img_bench(int argc, char **argv)
for (;;) {
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
- {"flush-interval", required_argument, 0, OPTION_FLUSH_INTERVAL},
+ {"format", required_argument, 0, 'f'},
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
+ {"cache", required_argument, 0, 't'},
+ {"count", required_argument, 0, 'c'},
+ {"depth", required_argument, 0, 'd'},
+ {"offset", required_argument, 0, 'o'},
+ {"buffer-size", required_argument, 0, 's'},
+ {"step-size", required_argument, 0, 'S'},
+ {"write", no_argument, 0, 'w'},
{"pattern", required_argument, 0, OPTION_PATTERN},
+ {"flush-interval", required_argument, 0, OPTION_FLUSH_INTERVAL},
{"no-drain", no_argument, 0, OPTION_NO_DRAIN},
+ {"aio", required_argument, 0, 'i'},
+ {"native", no_argument, 0, 'n'},
{"force-share", no_argument, 0, 'U'},
+ {"quiet", no_argument, 0, 'q'},
+ {"object", required_argument, 0, OPTION_OBJECT},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":hc:d:f:ni:o:qs:S:t:wU", long_options,
- NULL);
+ c = getopt_long(argc, argv, "hf:t:c:d:o:s:S:wi:nUq",
+ long_options, NULL);
if (c == -1) {
break;
}
switch (c) {
- case ':':
- missing_argument(argv[optind - 1]);
+ case 'h':
+ cmd_help(ccmd, "[-f FMT | --image-opts] [-t CACHE]\n"
+" [-c COUNT] [-d DEPTH] [-o OFFSET] [-s BUFFER_SIZE] [-S STEP_SIZE]\n"
+" [-w [--pattern PATTERN] [--flush-interval INTERVAL [--no-drain]]]\n"
+" [-i AIO] [-n] [-U] [-q] FILE\n"
+,
+" -f, --format FMT\n"
+" specify FILE format explicitly\n"
+" --image-opts\n"
+" indicates that FILE is a complete image specification\n"
+" instead of a file name (incompatible with --format)\n"
+" -t, --cache CACHE\n"
+" cache mode for FILE (default: " BDRV_DEFAULT_CACHE ")\n"
+" -c, --count COUNT\n"
+" number of I/O requests to perform\n"
+" -d, --depth DEPTH\n"
+" number of requests to perform in parallel\n"
+" -o, --offset OFFSET\n"
+" start first request at this OFFSET\n"
+" -s, --buffer-size BUFFER_SIZE[bkKMGTPE]\n"
+" size of each I/O request, with optional multiplier suffix\n"
+" (powers of 1024, default is 4K)\n"
+" -S, --step-size STEP_SIZE[bkKMGTPE]\n"
+" each next request offset increment, with optional multiplier suffix\n"
+" (powers of 1024, default is the same as BUFFER_SIZE)\n"
+" -w, --write\n"
+" perform write test (default is read)\n"
+" --pattern PATTERN\n"
+" write this pattern byte instead of zero\n"
+" --flush-interval FLUSH_INTERVAL\n"
+" issue flush after this number of requests\n"
+" --no-drain\n"
+" do not wait when flushing pending requests\n"
+" -i, --aio AIO\n"
+" async-io backend (threads, native, io_uring)\n"
+" -n, --native\n"
+" use native AIO backend if possible\n"
+" -U, --force-share\n"
+" open images in shared mode for concurrent access\n"
+" -q, --quiet\n"
+" quiet mode (produce only error messages if any)\n"
+" --object OBJDEF\n"
+" defines QEMU user-creatable object\n"
+" FILE\n"
+" name of the image file, or option string (key=value,..)\n"
+" with --image-opts, to operate on\n"
+);
break;
- case '?':
- unrecognized_option(argv[optind - 1]);
+ case 'f':
+ fmt = optarg;
break;
- case 'h':
- help();
+ case OPTION_IMAGE_OPTS:
+ image_opts = true;
+ break;
+ case 't':
+ ret = bdrv_parse_cache_mode(optarg, &flags, &writethrough);
+ if (ret < 0) {
+ error_report("Invalid cache mode");
+ ret = -1;
+ goto out;
+ }
break;
case 'c':
- {
- unsigned long res;
-
- if (qemu_strtoul(optarg, NULL, 0, &res) < 0 || res > INT_MAX) {
- error_report("Invalid request count specified");
+ count = cvtnum_full("request count", optarg, false, 1, INT_MAX);
+ if (count < 0) {
return 1;
}
- count = res;
break;
- }
case 'd':
- {
- unsigned long res;
-
- if (qemu_strtoul(optarg, NULL, 0, &res) <= 0 || res > INT_MAX) {
- error_report("Invalid queue depth specified");
+ depth = cvtnum_full("queue depth", optarg, false, 1, INT_MAX);
+ if (depth < 0) {
return 1;
}
- depth = res;
- break;
- }
- case 'f':
- fmt = optarg;
break;
case 'n':
flags |= BDRV_O_NATIVE_AIO;
@@ -4595,89 +4847,59 @@ static int img_bench(int argc, char **argv)
}
break;
case 'o':
- {
- offset = cvtnum("offset", optarg);
+ offset = cvtnum("offset", optarg, true);
if (offset < 0) {
return 1;
}
break;
- }
- break;
- case 'q':
- quiet = true;
- break;
case 's':
- {
- int64_t sval;
-
- sval = cvtnum_full("buffer size", optarg, 0, INT_MAX);
- if (sval < 0) {
+ bufsize = cvtnum_full("buffer size", optarg, true, 1, INT_MAX);
+ if (bufsize < 0) {
return 1;
}
-
- bufsize = sval;
break;
- }
case 'S':
- {
- int64_t sval;
-
- sval = cvtnum_full("step_size", optarg, 0, INT_MAX);
- if (sval < 0) {
+ step = cvtnum_full("step size", optarg, true, 0, INT_MAX);
+ if (step < 0) {
return 1;
}
-
- step = sval;
- break;
- }
- case 't':
- ret = bdrv_parse_cache_mode(optarg, &flags, &writethrough);
- if (ret < 0) {
- error_report("Invalid cache mode");
- ret = -1;
- goto out;
- }
break;
case 'w':
flags |= BDRV_O_RDWR;
is_write = true;
break;
- case 'U':
- force_share = true;
- break;
case OPTION_PATTERN:
- {
- unsigned long res;
-
- if (qemu_strtoul(optarg, NULL, 0, &res) < 0 || res > 0xff) {
- error_report("Invalid pattern byte specified");
+ pattern = cvtnum_full("pattern byte", optarg, false, 0, 0xff);
+ if (pattern < 0) {
return 1;
}
- pattern = res;
break;
- }
case OPTION_FLUSH_INTERVAL:
- {
- unsigned long res;
-
- if (qemu_strtoul(optarg, NULL, 0, &res) < 0 || res > INT_MAX) {
- error_report("Invalid flush interval specified");
+ flush_interval = cvtnum_full("flush interval", optarg,
+ false, 0, INT_MAX);
+ if (flush_interval < 0) {
return 1;
}
- flush_interval = res;
break;
- }
case OPTION_NO_DRAIN:
drain_on_flush = false;
break;
- case OPTION_IMAGE_OPTS:
- image_opts = true;
+ case 'U':
+ force_share = true;
break;
+ case 'q':
+ quiet = true;
+ break;
+ case OPTION_OBJECT:
+ user_creatable_process_cmdline(optarg);
+ break;
+ default:
+ tryhelp(argv[0]);
}
}
if (optind != argc - 1) {
- error_exit("Expecting one image file name");
+ error_exit(argv[0], "Expecting one image file name");
}
filename = argv[argc - 1];
@@ -4777,7 +4999,7 @@ typedef struct ImgBitmapAction {
QSIMPLEQ_ENTRY(ImgBitmapAction) next;
} ImgBitmapAction;
-static int img_bitmap(int argc, char **argv)
+static int img_bitmap(const img_cmd_t *ccmd, int argc, char **argv)
{
Error *err = NULL;
int c, ret = 1;
@@ -4799,48 +5021,69 @@ static int img_bitmap(int argc, char **argv)
for (;;) {
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
- {"object", required_argument, 0, OPTION_OBJECT},
+ {"format", required_argument, 0, 'f'},
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
{"add", no_argument, 0, OPTION_ADD},
+ {"granularity", required_argument, 0, 'g'},
{"remove", no_argument, 0, OPTION_REMOVE},
{"clear", no_argument, 0, OPTION_CLEAR},
{"enable", no_argument, 0, OPTION_ENABLE},
{"disable", no_argument, 0, OPTION_DISABLE},
{"merge", required_argument, 0, OPTION_MERGE},
- {"granularity", required_argument, 0, 'g'},
{"source-file", required_argument, 0, 'b'},
{"source-format", required_argument, 0, 'F'},
+ {"object", required_argument, 0, OPTION_OBJECT},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":b:f:F:g:h", long_options, NULL);
+ c = getopt_long(argc, argv, "hf:g:b:F:",
+ long_options, NULL);
if (c == -1) {
break;
}
switch (c) {
- case ':':
- missing_argument(argv[optind - 1]);
- break;
- case '?':
- unrecognized_option(argv[optind - 1]);
- break;
case 'h':
- help();
- break;
- case 'b':
- src_filename = optarg;
+ cmd_help(ccmd, "[-f FMT | --image-opts]\n"
+" ( --add [-g SIZE] | --remove | --clear | --enable | --disable |\n"
+" --merge SOURCE [-b SRC_FILE [-F SRC_FMT]] )..\n"
+" [--object OBJDEF] FILE BITMAP\n"
+,
+" -f, --format FMT\n"
+" specify FILE format explicitly (default: probing is used)\n"
+" --image-opts\n"
+" treat FILE as an option string (key=value,..), not a file name\n"
+" (incompatible with -f|--format)\n"
+" --add\n"
+" creates BITMAP in FILE, enables to record future edits\n"
+" -g, --granularity SIZE[bKMGTPE]\n"
+" sets non-default granularity for the bitmap being added,\n"
+" with optional multiplier suffix (in powers of 1024)\n"
+" --remove\n"
+" removes BITMAP from FILE\n"
+" --clear\n"
+" clears BITMAP in FILE\n"
+" --enable, --disable\n"
+" starts and stops recording future edits to BITMAP in FILE\n"
+" --merge SOURCE\n"
+" merges contents of the SOURCE bitmap into BITMAP in FILE\n"
+" -b, --source-file SRC_FILE\n"
+" select alternative source file for --merge\n"
+" -F, --source-format SRC_FMT\n"
+" specify format for SRC_FILE explicitly\n"
+" --object OBJDEF\n"
+" defines QEMU user-creatable object\n"
+" FILE\n"
+" name of the image file, or option string (key=value,..)\n"
+" with --image-opts, to operate on\n"
+" BITMAP\n"
+" name of the bitmap to add, remove, clear, enable, disable or merge to\n"
+);
break;
case 'f':
fmt = optarg;
break;
- case 'F':
- src_fmt = optarg;
- break;
- case 'g':
- granularity = cvtnum("granularity", optarg);
- if (granularity < 0) {
- return 1;
- }
+ case OPTION_IMAGE_OPTS:
+ image_opts = true;
break;
case OPTION_ADD:
act = g_new0(ImgBitmapAction, 1);
@@ -4848,6 +5091,12 @@ static int img_bitmap(int argc, char **argv)
QSIMPLEQ_INSERT_TAIL(&actions, act, next);
add = true;
break;
+ case 'g':
+ granularity = cvtnum("granularity", optarg, true);
+ if (granularity < 0) {
+ return 1;
+ }
+ break;
case OPTION_REMOVE:
act = g_new0(ImgBitmapAction, 1);
act->act = BITMAP_REMOVE;
@@ -4875,12 +5124,17 @@ static int img_bitmap(int argc, char **argv)
QSIMPLEQ_INSERT_TAIL(&actions, act, next);
merge = true;
break;
+ case 'b':
+ src_filename = optarg;
+ break;
+ case 'F':
+ src_fmt = optarg;
+ break;
case OPTION_OBJECT:
user_creatable_process_cmdline(optarg);
break;
- case OPTION_IMAGE_OPTS:
- image_opts = true;
- break;
+ default:
+ tryhelp(argv[0]);
}
}
@@ -5023,7 +5277,7 @@ static int img_dd_bs(const char *arg,
{
int64_t res;
- res = cvtnum_full("bs", arg, 1, INT_MAX);
+ res = cvtnum_full("bs", arg, true, 1, INT_MAX);
if (res < 0) {
return 1;
@@ -5037,7 +5291,7 @@ static int img_dd_count(const char *arg,
struct DdIo *in, struct DdIo *out,
struct DdInfo *dd)
{
- dd->count = cvtnum("count", arg);
+ dd->count = cvtnum("count", arg, true);
if (dd->count < 0) {
return 1;
@@ -5068,7 +5322,7 @@ static int img_dd_skip(const char *arg,
struct DdIo *in, struct DdIo *out,
struct DdInfo *dd)
{
- in->offset = cvtnum("skip", arg);
+ in->offset = cvtnum("skip", arg, true);
if (in->offset < 0) {
return 1;
@@ -5077,7 +5331,7 @@ static int img_dd_skip(const char *arg,
return 0;
}
-static int img_dd(int argc, char **argv)
+static int img_dd(const img_cmd_t *ccmd, int argc, char **argv)
{
int ret = 0;
char *arg = NULL;
@@ -5121,31 +5375,54 @@ static int img_dd(int argc, char **argv)
};
const struct option long_options[] = {
{ "help", no_argument, 0, 'h'},
- { "object", required_argument, 0, OPTION_OBJECT},
+ { "format", required_argument, 0, 'f'},
{ "image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
+ { "output-format", required_argument, 0, 'O'},
{ "force-share", no_argument, 0, 'U'},
+ { "object", required_argument, 0, OPTION_OBJECT},
{ 0, 0, 0, 0 }
};
- while ((c = getopt_long(argc, argv, ":hf:O:U", long_options, NULL))) {
+ while ((c = getopt_long(argc, argv, "hf:O:U", long_options, NULL))) {
if (c == EOF) {
break;
}
switch (c) {
- case 'O':
- out_fmt = optarg;
+ case 'h':
+ cmd_help(ccmd, "[-f FMT|--image-opts] [-O OUTPUT_FMT] [-U]\n"
+" [--object OBJDEF] [bs=BLOCK_SIZE] [count=BLOCKS] if=INPUT of=OUTPUT\n"
+,
+" -f, --format FMT\n"
+" specify format for INPUT explicitly (default: probing is used)\n"
+" --image-opts\n"
+" treat INPUT as an option string (key=value,..), not a file name\n"
+" (incompatible with -f|--format)\n"
+" -O, --output-format OUTPUT_FMT\n"
+" format of the OUTPUT (default: raw)\n"
+" -U, --force-share\n"
+" open images in shared mode for concurrent access\n"
+" --object OBJDEF\n"
+" defines QEMU user-creatable object\n"
+" bs=BLOCK_SIZE[bKMGTP]\n"
+" size of the I/O block, with optional multiplier suffix (powers of 1024)\n"
+" (default: 512)\n"
+" count=COUNT\n"
+" number of blocks to convert (default whole INPUT)\n"
+" if=INPUT\n"
+" name of the file, or option string (key=value,..)\n"
+" with --image-opts, to use for input\n"
+" of=OUTPUT\n"
+" output file name to create (will be overridden if alrady exists)\n"
+);
break;
case 'f':
fmt = optarg;
break;
- case ':':
- missing_argument(argv[optind - 1]);
- break;
- case '?':
- unrecognized_option(argv[optind - 1]);
+ case OPTION_IMAGE_OPTS:
+ image_opts = true;
break;
- case 'h':
- help();
+ case 'O':
+ out_fmt = optarg;
break;
case 'U':
force_share = true;
@@ -5153,9 +5430,8 @@ static int img_dd(int argc, char **argv)
case OPTION_OBJECT:
user_creatable_process_cmdline(optarg);
break;
- case OPTION_IMAGE_OPTS:
- image_opts = true;
- break;
+ default:
+ tryhelp(argv[0]);
}
}
@@ -5345,17 +5621,8 @@ static void dump_json_block_measure_info(BlockMeasureInfo *info)
g_string_free(str, true);
}
-static int img_measure(int argc, char **argv)
+static int img_measure(const img_cmd_t *ccmd, int argc, char **argv)
{
- static const struct option long_options[] = {
- {"help", no_argument, 0, 'h'},
- {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
- {"object", required_argument, 0, OPTION_OBJECT},
- {"output", required_argument, 0, OPTION_OUTPUT},
- {"size", required_argument, 0, OPTION_SIZE},
- {"force-share", no_argument, 0, 'U'},
- {0, 0, 0, 0}
- };
OutputFormat output_format = OFORMAT_HUMAN;
BlockBackend *in_blk = NULL;
BlockDriver *drv;
@@ -5370,29 +5637,67 @@ static int img_measure(int argc, char **argv)
QemuOpts *sn_opts = NULL;
QemuOptsList *create_opts = NULL;
bool image_opts = false;
- uint64_t img_size = UINT64_MAX;
+ int64_t img_size = -1;
BlockMeasureInfo *info = NULL;
Error *local_err = NULL;
int ret = 1;
int c;
- while ((c = getopt_long(argc, argv, "hf:O:o:l:U",
+ static const struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"source-format", required_argument, 0, 'f'}, /* img_convert */
+ {"format", required_argument, 0, 'f'},
+ {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
+ {"source-image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, /* img_convert */
+ {"snapshot", required_argument, 0, 'l'},
+ {"target-format", required_argument, 0, 'O'},
+ {"target-format-options", required_argument, 0, 'o'}, /* img_convert */
+ {"options", required_argument, 0, 'o'},
+ {"force-share", no_argument, 0, 'U'},
+ {"output", required_argument, 0, OPTION_OUTPUT},
+ {"object", required_argument, 0, OPTION_OBJECT},
+ {"size", required_argument, 0, 's'},
+ {0, 0, 0, 0}
+ };
+
+ while ((c = getopt_long(argc, argv, "hf:l:O:o:Us:",
long_options, NULL)) != -1) {
switch (c) {
- case '?':
case 'h':
- help();
+ cmd_help(ccmd, "[-f FMT|--image-opts] [-l SNAPSHOT]\n"
+" [-O TARGET_FMT] [-o TARGET_FMT_OPTS] [--output human|json]\n"
+" [--object OBJDEF] (--size SIZE | FILE)\n"
+,
+" -f, --format\n"
+" specify format of FILE explicitly (default: probing is used)\n"
+" --image-opts\n"
+" indicates that FILE is a complete image specification\n"
+" instead of a file name (incompatible with --format)\n"
+" -l, --snapshot SNAPSHOT\n"
+" use this snapshot in FILE as source\n"
+" -O, --target-format TARGET_FMT\n"
+" desired target/output image format (default: raw)\n"
+" -o TARGET_FMT_OPTS\n"
+" options specific to TARGET_FMT\n"
+" --output human|json\n"
+" output format (default: human)\n"
+" -U, --force-share\n"
+" open images in shared mode for concurrent access\n"
+" --object OBJDEF\n"
+" defines QEMU user-creatable object\n"
+" -s, --size SIZE[bKMGTPE]\n"
+" measure file size for given image size,\n"
+" with optional multiplier suffix (powers of 1024)\n"
+" FILE\n"
+" measure file size required to convert from FILE (either a file name\n"
+" or an option string (key=value,..) with --image-options)\n"
+);
break;
case 'f':
fmt = optarg;
break;
- case 'O':
- out_fmt = optarg;
- break;
- case 'o':
- if (accumulate_options(&options, optarg) < 0) {
- goto out;
- }
+ case OPTION_IMAGE_OPTS:
+ image_opts = true;
break;
case 'l':
if (strstart(optarg, SNAPSHOT_OPT_BASE, NULL)) {
@@ -5407,37 +5712,31 @@ static int img_measure(int argc, char **argv)
snapshot_name = optarg;
}
break;
+ case 'O':
+ out_fmt = optarg;
+ break;
+ case 'o':
+ if (accumulate_options(&options, optarg) < 0) {
+ goto out;
+ }
+ break;
case 'U':
force_share = true;
break;
+ case OPTION_OUTPUT:
+ output_format = parse_output_format(argv[0], optarg);
+ break;
case OPTION_OBJECT:
user_creatable_process_cmdline(optarg);
break;
- case OPTION_IMAGE_OPTS:
- image_opts = true;
- break;
- case OPTION_OUTPUT:
- if (!strcmp(optarg, "json")) {
- output_format = OFORMAT_JSON;
- } else if (!strcmp(optarg, "human")) {
- output_format = OFORMAT_HUMAN;
- } else {
- error_report("--output must be used with human or json "
- "as argument.");
+ case 's':
+ img_size = cvtnum("image size", optarg, true);
+ if (img_size < 0) {
goto out;
}
break;
- case OPTION_SIZE:
- {
- int64_t sval;
-
- sval = cvtnum("image size", optarg);
- if (sval < 0) {
- goto out;
- }
- img_size = (uint64_t)sval;
- }
- break;
+ default:
+ tryhelp(argv[0]);
}
}
@@ -5452,11 +5751,11 @@ static int img_measure(int argc, char **argv)
error_report("--image-opts, -f, and -l require a filename argument.");
goto out;
}
- if (filename && img_size != UINT64_MAX) {
+ if (filename && img_size != -1) {
error_report("--size N cannot be used together with a filename.");
goto out;
}
- if (!filename && img_size == UINT64_MAX) {
+ if (!filename && img_size == -1) {
error_report("Either --size N or one filename must be specified.");
goto out;
}
@@ -5504,7 +5803,7 @@ static int img_measure(int argc, char **argv)
goto out;
}
}
- if (img_size != UINT64_MAX) {
+ if (img_size != -1) {
qemu_opt_set_number(opts, BLOCK_OPT_SIZE, img_size, &error_abort);
}
@@ -5538,13 +5837,49 @@ out:
}
static const img_cmd_t img_cmds[] = {
-#define DEF(option, callback, arg_string) \
- { option, callback },
-#include "qemu-img-cmds.h"
-#undef DEF
+ { "amend", img_amend,
+ "Update format-specific options of the image" },
+ { "bench", img_bench,
+ "Run a simple image benchmark" },
+ { "bitmap", img_bitmap,
+ "Perform modifications of the persistent bitmap in the image" },
+ { "check", img_check,
+ "Check basic image integrity" },
+ { "commit", img_commit,
+ "Commit image to its backing file" },
+ { "compare", img_compare,
+ "Check if two images have the same contents" },
+ { "convert", img_convert,
+ "Copy one or more images to another with optional format conversion" },
+ { "create", img_create,
+ "Create and format a new image file" },
+ { "dd", img_dd,
+ "Copy input to output with optional format conversion" },
+ { "info", img_info,
+ "Display information about the image" },
+ { "map", img_map,
+ "Dump image metadata" },
+ { "measure", img_measure,
+ "Calculate the file size required for a new image" },
+ { "rebase", img_rebase,
+ "Change the backing file of the image" },
+ { "resize", img_resize,
+ "Resize the image" },
+ { "snapshot", img_snapshot,
+ "List or manipulate snapshots in the image" },
{ NULL, NULL, },
};
+static void format_print(void *opaque, const char *name)
+{
+ int *np = opaque;
+ if (*np + strlen(name) > 75) {
+ printf("\n ");
+ *np = 1;
+ }
+ *np += printf(" %s", name);
+}
+
int main(int argc, char **argv)
{
const img_cmd_t *cmd;
@@ -5572,23 +5907,39 @@ int main(int argc, char **argv)
module_call_init(MODULE_INIT_QOM);
bdrv_init();
- if (argc < 2) {
- error_exit("Not enough arguments");
- }
qemu_add_opts(&qemu_source_opts);
qemu_add_opts(&qemu_trace_opts);
- while ((c = getopt_long(argc, argv, "+:hVT:", long_options, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, "+hVT:", long_options, NULL)) != -1) {
switch (c) {
- case ':':
- missing_argument(argv[optind - 1]);
- return 0;
- case '?':
- unrecognized_option(argv[optind - 1]);
- return 0;
case 'h':
- help();
+ printf(
+QEMU_IMG_VERSION
+"QEMU disk image utility. Usage:\n"
+"\n"
+" qemu-img [standard options] COMMAND [--help | command options]\n"
+"\n"
+"Standard options:\n"
+" -h, --help\n"
+" display this help and exit\n"
+" -V, --version\n"
+" display version info and exit\n"
+" -T,--trace TRACE\n"
+" specify tracing options:\n"
+" [[enable=]<pattern>][,events=<file>][,file=<file>]\n"
+"\n"
+"Recognized commands (run qemu-img COMMAND --help for command-specific help):\n\n");
+ for (cmd = img_cmds; cmd->name != NULL; cmd++) {
+ printf(" %s - %s\n", cmd->name, cmd->description);
+ }
+ printf("\nSupported image formats:\n");
+ c = 99; /* force a newline */
+ bdrv_iterate_format(format_print, &c, false);
+ if (c) {
+ printf("\n");
+ }
+ printf("\n" QEMU_HELP_BOTTOM "\n");
return 0;
case 'V':
printf(QEMU_IMG_VERSION);
@@ -5596,18 +5947,16 @@ int main(int argc, char **argv)
case 'T':
trace_opt_parse(optarg);
break;
+ default:
+ tryhelp(argv[0]);
}
}
- cmdname = argv[optind];
-
- /* reset getopt_long scanning */
- argc -= optind;
- if (argc < 1) {
- return 0;
+ if (optind >= argc) {
+ error_exit(argv[0], "Not enough arguments");
}
- argv += optind;
- qemu_reset_optind();
+
+ cmdname = argv[optind];
if (!trace_init_backends()) {
exit(1);
@@ -5618,10 +5967,16 @@ int main(int argc, char **argv)
/* find the command */
for (cmd = img_cmds; cmd->name != NULL; cmd++) {
if (!strcmp(cmdname, cmd->name)) {
- return cmd->handler(argc, argv);
+ g_autofree char *argv0 = g_strdup_printf("%s %s", argv[0], cmdname);
+ /* reset options and getopt processing (incl return order) */
+ argv += optind;
+ argc -= optind;
+ qemu_reset_optind();
+ argv[0] = argv0;
+ return cmd->handler(cmd, argc, argv);
}
}
/* not found */
- error_exit("Command not found: %s", cmdname);
+ error_exit(argv[0], "Command not found: %s", cmdname);
}
diff --git a/qemu-options.hx b/qemu-options.hx
index 1a425b2..ab23f14 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -38,6 +38,7 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \
" nvdimm=on|off controls NVDIMM support (default=off)\n"
" memory-encryption=@var{} memory encryption object to use (default=none)\n"
" hmat=on|off controls ACPI HMAT support (default=off)\n"
+ " spcr=on|off controls ACPI SPCR support (default=on)\n"
#ifdef CONFIG_POSIX
" aux-ram-share=on|off allocate auxiliary guest RAM as shared (default: off)\n"
#endif
@@ -105,6 +106,10 @@ SRST
Enables or disables ACPI Heterogeneous Memory Attribute Table
(HMAT) support. The default is off.
+ ``spcr=on|off``
+ Enables or disables ACPI Serial Port Console Redirection Table
+ (SPCR) support. The default is on.
+
``aux-ram-share=on|off``
Allocate auxiliary guest RAM as an anonymous file that is
shareable with an external process. This option applies to
@@ -2281,6 +2286,8 @@ DEF("spice", HAS_ARG, QEMU_OPTION_spice,
" [,streaming-video=[off|all|filter]][,disable-copy-paste=on|off]\n"
" [,disable-agent-file-xfer=on|off][,agent-mouse=[on|off]]\n"
" [,playback-compression=[on|off]][,seamless-migration=[on|off]]\n"
+ " [,video-codec=<codec>\n"
+ " [,max-refresh-rate=rate\n"
" [,gl=[on|off]][,rendernode=<file>]\n"
" enable spice\n"
" at least one of {port, tls-port} is mandatory\n",
@@ -2369,6 +2376,17 @@ SRST
``seamless-migration=[on|off]``
Enable/disable spice seamless migration. Default is off.
+ ``video-codec=<codec>``
+ Provide the preferred codec the Spice server should use with the
+ Gstreamer encoder. This option is only relevant when gl=on is
+ specified. If no codec is provided, then the codec gstreamer:h264
+ would be used as default. And, for the case where gl=off, the
+ default codec to be used is determined by the Spice server.
+
+ ``max-refresh-rate=rate``
+ Provide the maximum refresh rate (or FPS) at which the encoding
+ requests should be sent to the Spice server. Default would be 30.
+
``gl=[on|off]``
Enable/disable OpenGL context. Default is off.
@@ -2929,6 +2947,7 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
#ifdef CONFIG_AF_XDP
"-netdev af-xdp,id=str,ifname=name[,mode=native|skb][,force-copy=on|off]\n"
" [,queues=n][,start-queue=m][,inhibit=on|off][,sock-fds=x:y:...:z]\n"
+ " [,map-path=/path/to/socket/map][,map-start-index=i]\n"
" attach to the existing network interface 'name' with AF_XDP socket\n"
" use 'mode=MODE' to specify an XDP program attach mode\n"
" use 'force-copy=on|off' to force XDP copy mode even if device supports zero-copy (default: off)\n"
@@ -2936,6 +2955,8 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
" with inhibit=on,\n"
" use 'sock-fds' to provide file descriptors for already open AF_XDP sockets\n"
" added to a socket map in XDP program. One socket per queue.\n"
+ " use 'map-path' to provide the socket map location to populate AF_XDP sockets with,\n"
+ " and use 'map-start-index' to specify the starting index for the map (default: 0) (Since 10.1)\n"
" use 'queues=n' to specify how many queues of a multiqueue interface should be used\n"
" use 'start-queue=m' to specify the first queue that should be used\n"
#endif
@@ -3759,7 +3780,7 @@ SRST
# launch QEMU instance
|qemu_system| linux.img -nic vde,sock=/tmp/myswitch
-``-netdev af-xdp,id=str,ifname=name[,mode=native|skb][,force-copy=on|off][,queues=n][,start-queue=m][,inhibit=on|off][,sock-fds=x:y:...:z]``
+``-netdev af-xdp,id=str,ifname=name[,mode=native|skb][,force-copy=on|off][,queues=n][,start-queue=m][,inhibit=on|off][,sock-fds=x:y:...:z][,map-path=/path/to/socket/map][,map-start-index=i]``
Configure AF_XDP backend to connect to a network interface 'name'
using AF_XDP socket. A specific program attach mode for a default
XDP program can be forced with 'mode', defaults to best-effort,
@@ -3799,7 +3820,8 @@ SRST
-netdev af-xdp,id=n1,ifname=eth0,queues=1,start-queue=1
XDP program can also be loaded externally. In this case 'inhibit' option
- should be set to 'on' and 'sock-fds' provided with file descriptors for
+ should be set to 'on'. Either 'sock-fds' or 'map-path' can be used with
+ 'inhibit' enabled. 'sock-fds' can be provided with file descriptors for
already open but not bound XDP sockets already added to a socket map for
corresponding queues. One socket per queue.
@@ -3808,6 +3830,21 @@ SRST
|qemu_system| linux.img -device virtio-net-pci,netdev=n1 \\
-netdev af-xdp,id=n1,ifname=eth0,queues=3,inhibit=on,sock-fds=15:16:17
+ For the 'inhibit' option set to 'on' used together with 'map-path' it is
+ expected that the XDP program with the socket map is already loaded on
+ the networking device and the map pinned into BPF file system. The path
+ to the pinned map is then passed to QEMU which then creates the file
+ descriptors and inserts them into the existing socket map.
+
+ .. parsed-literal::
+
+ |qemu_system| linux.img -device virtio-net-pci,netdev=n1 \\
+ -netdev af-xdp,id=n1,ifname=eth0,queues=2,inhibit=on,map-path=/sys/fs/bpf/xsks_map
+
+ Additionally, 'map-start-index' can be used to specify the start offset
+ for insertion into the socket map. The combination of 'map-path' and
+ 'sock-fds' together is not supported.
+
``-netdev vhost-user,chardev=id[,vhostforce=on|off][,queues=n]``
Establish a vhost-user netdev, backed by a chardev id. The chardev
should be a unix domain socket backed one. The vhost-user uses a
diff --git a/rust/qemu-api/src/bindings.rs b/rust/qemu-api/src/bindings.rs
index 3cdad0f..b8104de 100644
--- a/rust/qemu-api/src/bindings.rs
+++ b/rust/qemu-api/src/bindings.rs
@@ -14,7 +14,8 @@
clippy::missing_const_for_fn,
clippy::ptr_offset_with_cast,
clippy::useless_transmute,
- clippy::missing_safety_doc
+ clippy::missing_safety_doc,
+ clippy::too_many_arguments
)]
//! `bindgen`-generated declarations.
diff --git a/scripts/qapi/parser.py b/scripts/qapi/parser.py
index 949d9e8..2529edf 100644
--- a/scripts/qapi/parser.py
+++ b/scripts/qapi/parser.py
@@ -584,10 +584,6 @@ class QAPISchemaParser:
doc.append_line(text)
line = self.get_doc_indented(doc)
no_more_args = True
- elif line.startswith('='):
- raise QAPIParseError(
- self,
- "unexpected '=' markup in definition documentation")
else:
# plain paragraph
doc.ensure_untagged_section(self.info)
@@ -597,22 +593,15 @@ class QAPISchemaParser:
# Free-form documentation
doc = QAPIDoc(info)
doc.ensure_untagged_section(self.info)
- first = True
while line is not None:
if match := self._match_at_name_colon(line):
raise QAPIParseError(
self,
"'@%s:' not allowed in free-form documentation"
% match.group(1))
- if line.startswith('='):
- if not first:
- raise QAPIParseError(
- self,
- "'=' heading must come first in a comment block")
doc.append_line(line)
self.accept(False)
line = self.get_doc_line()
- first = False
self.accept()
doc.end()
@@ -815,6 +804,43 @@ class QAPIDoc:
% feature.name)
self.features[feature.name].connect(feature)
+ def ensure_returns(self, info: QAPISourceInfo) -> None:
+
+ def _insert_near_kind(
+ kind: QAPIDoc.Kind,
+ new_sect: QAPIDoc.Section,
+ after: bool = False,
+ ) -> bool:
+ for idx, sect in enumerate(reversed(self.all_sections)):
+ if sect.kind == kind:
+ pos = len(self.all_sections) - idx - 1
+ if after:
+ pos += 1
+ self.all_sections.insert(pos, new_sect)
+ return True
+ return False
+
+ if any(s.kind == QAPIDoc.Kind.RETURNS for s in self.all_sections):
+ return
+
+ # Stub "Returns" section for undocumented returns value
+ stub = QAPIDoc.Section(info, QAPIDoc.Kind.RETURNS)
+
+ if any(_insert_near_kind(kind, stub, after) for kind, after in (
+ # 1. If arguments, right after those.
+ (QAPIDoc.Kind.MEMBER, True),
+ # 2. Elif errors, right *before* those.
+ (QAPIDoc.Kind.ERRORS, False),
+ # 3. Elif features, right *before* those.
+ (QAPIDoc.Kind.FEATURE, False),
+ )):
+ return
+
+ # Otherwise, it should go right after the intro. The intro
+ # is always the first section and is always present (even
+ # when empty), so we can insert directly at index=1 blindly.
+ self.all_sections.insert(1, stub)
+
def check_expr(self, expr: QAPIExpression) -> None:
if 'command' in expr:
if self.returns and 'returns' not in expr:
diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py
index cbe3b5a..3abddea 100644
--- a/scripts/qapi/schema.py
+++ b/scripts/qapi/schema.py
@@ -1062,6 +1062,9 @@ class QAPISchemaCommand(QAPISchemaDefinition):
if self.arg_type and self.arg_type.is_implicit():
self.arg_type.connect_doc(doc)
+ if self.ret_type and self.info:
+ doc.ensure_returns(self.info)
+
def visit(self, visitor: QAPISchemaVisitor) -> None:
super().visit(visitor)
visitor.visit_command(
diff --git a/storage-daemon/qapi/qapi-schema.json b/storage-daemon/qapi/qapi-schema.json
index 0427594..478e7a9 100644
--- a/storage-daemon/qapi/qapi-schema.json
+++ b/storage-daemon/qapi/qapi-schema.json
@@ -14,7 +14,9 @@
# storage daemon.
##
-# = Introduction
+# ************
+# Introduction
+# ************
#
# This manual describes the commands and events supported by the QEMU
# storage daemon QMP.
@@ -51,7 +53,9 @@
{ 'include': '../../qapi/job.json' }
##
-# = Block devices
+# *************
+# Block devices
+# *************
##
{ 'include': '../../qapi/block-core.json' }
{ 'include': '../../qapi/block-export.json' }
diff --git a/system/cpus.c b/system/cpus.c
index 8e6da2e..2567235 100644
--- a/system/cpus.c
+++ b/system/cpus.c
@@ -31,7 +31,7 @@
#include "qapi/qapi-events-run-state.h"
#include "qapi/qmp/qerror.h"
#include "exec/gdbstub.h"
-#include "system/accel-ops.h"
+#include "accel/accel-cpu-ops.h"
#include "system/hw_accel.h"
#include "exec/cpu-common.h"
#include "qemu/thread.h"
diff --git a/system/memory.c b/system/memory.c
index e8d9b15..5646547 100644
--- a/system/memory.c
+++ b/system/memory.c
@@ -22,6 +22,7 @@
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "qemu/qemu-print.h"
+#include "qemu/target-info.h"
#include "qom/object.h"
#include "trace.h"
#include "system/ram_addr.h"
@@ -29,6 +30,7 @@
#include "system/runstate.h"
#include "system/tcg.h"
#include "qemu/accel.h"
+#include "accel/accel-ops.h"
#include "hw/boards.h"
#include "migration/vmstate.h"
#include "system/address-spaces.h"
diff --git a/system/qtest.c b/system/qtest.c
index 301b03b..fa42c9f 100644
--- a/system/qtest.c
+++ b/system/qtest.c
@@ -29,6 +29,7 @@
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "qemu/cutils.h"
+#include "qemu/target-info.h"
#include "qom/object_interfaces.h"
#define MAX_IRQ 256
diff --git a/system/runstate.c b/system/runstate.c
index 38900c9..6178b00 100644
--- a/system/runstate.c
+++ b/system/runstate.c
@@ -306,18 +306,6 @@ struct VMChangeStateEntry {
static QTAILQ_HEAD(, VMChangeStateEntry) vm_change_state_head =
QTAILQ_HEAD_INITIALIZER(vm_change_state_head);
-/**
- * qemu_add_vm_change_state_handler_prio:
- * @cb: the callback to invoke
- * @opaque: user data passed to the callback
- * @priority: low priorities execute first when the vm runs and the reverse is
- * true when the vm stops
- *
- * Register a callback function that is invoked when the vm starts or stops
- * running.
- *
- * Returns: an entry to be freed using qemu_del_vm_change_state_handler()
- */
VMChangeStateEntry *qemu_add_vm_change_state_handler_prio(
VMChangeStateHandler *cb, void *opaque, int priority)
{
@@ -325,24 +313,6 @@ VMChangeStateEntry *qemu_add_vm_change_state_handler_prio(
opaque, priority);
}
-/**
- * qemu_add_vm_change_state_handler_prio_full:
- * @cb: the main callback to invoke
- * @prepare_cb: a callback to invoke before the main callback
- * @cb_ret: the main callback to invoke with return value
- * @opaque: user data passed to the callbacks
- * @priority: low priorities execute first when the vm runs and the reverse is
- * true when the vm stops
- *
- * Register a main callback function and an optional prepare callback function
- * that are invoked when the vm starts or stops running. The main callback and
- * the prepare callback are called in two separate phases: First all prepare
- * callbacks are called and only then all main callbacks are called. As its
- * name suggests, the prepare callback can be used to do some preparatory work
- * before invoking the main callback.
- *
- * Returns: an entry to be freed using qemu_del_vm_change_state_handler()
- */
VMChangeStateEntry *
qemu_add_vm_change_state_handler_prio_full(VMChangeStateHandler *cb,
VMChangeStateHandler *prepare_cb,
@@ -437,6 +407,7 @@ static ShutdownCause reset_requested;
static ShutdownCause shutdown_requested;
static int shutdown_exit_code = EXIT_SUCCESS;
static int shutdown_signal;
+static bool force_shutdown;
static pid_t shutdown_pid;
static int powerdown_requested;
static int debug_requested;
@@ -457,6 +428,11 @@ ShutdownCause qemu_shutdown_requested_get(void)
return shutdown_requested;
}
+bool qemu_force_shutdown_requested(void)
+{
+ return force_shutdown;
+}
+
ShutdownCause qemu_reset_requested_get(void)
{
return reset_requested;
@@ -805,6 +781,7 @@ void qemu_system_killed(int signal, pid_t pid)
* we are in a signal handler.
*/
shutdown_requested = SHUTDOWN_CAUSE_HOST_SIGNAL;
+ force_shutdown = true;
qemu_notify_event();
}
@@ -820,6 +797,9 @@ void qemu_system_shutdown_request(ShutdownCause reason)
trace_qemu_system_shutdown_request(reason);
replay_shutdown_request(reason);
shutdown_requested = reason;
+ if (reason == SHUTDOWN_CAUSE_HOST_QMP_QUIT) {
+ force_shutdown = true;
+ }
qemu_notify_event();
}
diff --git a/system/tpm.c b/system/tpm.c
index 8df0f6e..903b29c 100644
--- a/system/tpm.c
+++ b/system/tpm.c
@@ -21,6 +21,7 @@
#include "system/tpm.h"
#include "qemu/config-file.h"
#include "qemu/error-report.h"
+#include "qemu/help_option.h"
static QLIST_HEAD(, TPMBackend) tpm_backends =
QLIST_HEAD_INITIALIZER(tpm_backends);
@@ -179,9 +180,9 @@ int tpm_config_parse(QemuOptsList *opts_list, const char *optstr)
{
QemuOpts *opts;
- if (!strcmp(optstr, "help")) {
+ if (is_help_option(optstr)) {
tpm_display_backend_drivers();
- return -1;
+ exit(EXIT_SUCCESS);
}
opts = qemu_opts_parse_noisily(opts_list, optstr, true);
if (!opts) {
diff --git a/target-info-stub.c b/target-info-stub.c
index fecc0e7..ca0caa3 100644
--- a/target-info-stub.c
+++ b/target-info-stub.c
@@ -14,9 +14,11 @@
static const TargetInfo target_info_stub = {
.target_name = TARGET_NAME,
+ .target_arch = SYS_EMU_TARGET__MAX,
.long_bits = TARGET_LONG_BITS,
.cpu_type = CPU_RESOLVING_TYPE,
.machine_typename = TYPE_MACHINE,
+ .endianness = TARGET_BIG_ENDIAN ? ENDIAN_MODE_BIG : ENDIAN_MODE_LITTLE,
};
const TargetInfo *target_info(void)
diff --git a/target-info.c b/target-info.c
index 16fdca7..3110ab3 100644
--- a/target-info.c
+++ b/target-info.c
@@ -8,7 +8,9 @@
#include "qemu/osdep.h"
#include "qemu/target-info.h"
+#include "qemu/target-info-qapi.h"
#include "qemu/target-info-impl.h"
+#include "qapi/error.h"
const char *target_name(void)
{
@@ -20,6 +22,17 @@ unsigned target_long_bits(void)
return target_info()->long_bits;
}
+SysEmuTarget target_arch(void)
+{
+ SysEmuTarget arch = target_info()->target_arch;
+
+ if (arch == SYS_EMU_TARGET__MAX) {
+ arch = qapi_enum_parse(&SysEmuTarget_lookup, target_name(), -1,
+ &error_abort);
+ }
+ return arch;
+}
+
const char *target_cpu_type(void)
{
return target_info()->cpu_type;
@@ -29,3 +42,13 @@ const char *target_machine_typename(void)
{
return target_info()->machine_typename;
}
+
+EndianMode target_endian_mode(void)
+{
+ return target_info()->endianness;
+}
+
+bool target_big_endian(void)
+{
+ return target_endian_mode() == ENDIAN_MODE_BIG;
+}
diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c
index 2082db4..bf1787a 100644
--- a/target/alpha/cpu.c
+++ b/target/alpha/cpu.c
@@ -286,6 +286,7 @@ static void alpha_cpu_class_init(ObjectClass *oc, const void *data)
cc->get_pc = alpha_cpu_get_pc;
cc->gdb_read_register = alpha_cpu_gdb_read_register;
cc->gdb_write_register = alpha_cpu_gdb_write_register;
+ cc->gdb_core_xml_file = "alpha-core.xml";
#ifndef CONFIG_USER_ONLY
dc->vmsd = &vmstate_alpha_cpu;
cc->sysemu_ops = &alpha_sysemu_ops;
diff --git a/target/arm/arm-qmp-cmds.c b/target/arm/arm-qmp-cmds.c
index cefd235..d292c97 100644
--- a/target/arm/arm-qmp-cmds.c
+++ b/target/arm/arm-qmp-cmds.c
@@ -21,6 +21,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/target-info.h"
#include "hw/boards.h"
#include "kvm_arm.h"
#include "qapi/error.h"
@@ -241,7 +242,7 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
CpuDefinitionInfoList *cpu_list = NULL;
GSList *list;
- list = object_class_get_list(TYPE_ARM_CPU, false);
+ list = object_class_get_list(target_cpu_type(), false);
g_slist_foreach(list, arm_cpu_add_definition, &cpu_list);
g_slist_free(list);
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 08c43f6..e2b2337 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -23,7 +23,6 @@
#include "qemu/timer.h"
#include "qemu/log.h"
#include "exec/page-vary.h"
-#include "exec/tswap.h"
#include "target/arm/idau.h"
#include "qemu/module.h"
#include "qapi/error.h"
diff --git a/target/i386/nvmm/nvmm-accel-ops.c b/target/i386/nvmm/nvmm-accel-ops.c
index a5517b0..3799260 100644
--- a/target/i386/nvmm/nvmm-accel-ops.c
+++ b/target/i386/nvmm/nvmm-accel-ops.c
@@ -10,7 +10,7 @@
#include "qemu/osdep.h"
#include "system/kvm_int.h"
#include "qemu/main-loop.h"
-#include "system/accel-ops.h"
+#include "accel/accel-cpu-ops.h"
#include "system/cpus.h"
#include "qemu/guest-random.h"
diff --git a/target/i386/nvmm/nvmm-all.c b/target/i386/nvmm/nvmm-all.c
index 11c2630..92e3b8b 100644
--- a/target/i386/nvmm/nvmm-all.c
+++ b/target/i386/nvmm/nvmm-all.c
@@ -12,6 +12,7 @@
#include "system/address-spaces.h"
#include "system/ioport.h"
#include "qemu/accel.h"
+#include "accel/accel-ops.h"
#include "system/nvmm.h"
#include "system/cpus.h"
#include "system/runstate.h"
diff --git a/target/i386/tcg/system/excp_helper.c b/target/i386/tcg/system/excp_helper.c
index c162621..50040f6 100644
--- a/target/i386/tcg/system/excp_helper.c
+++ b/target/i386/tcg/system/excp_helper.c
@@ -25,7 +25,6 @@
#include "exec/page-protection.h"
#include "exec/target_page.h"
#include "exec/tlb-flags.h"
-#include "exec/tswap.h"
#include "tcg/helper-tcg.h"
typedef struct TranslateParams {
diff --git a/target/i386/whpx/whpx-accel-ops.c b/target/i386/whpx/whpx-accel-ops.c
index 5f4841c..da58805 100644
--- a/target/i386/whpx/whpx-accel-ops.c
+++ b/target/i386/whpx/whpx-accel-ops.c
@@ -11,7 +11,7 @@
#include "qemu/osdep.h"
#include "system/kvm_int.h"
#include "qemu/main-loop.h"
-#include "system/accel-ops.h"
+#include "accel/accel-cpu-ops.h"
#include "system/cpus.h"
#include "qemu/guest-random.h"
diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c
index 22ac609..b72dcff 100644
--- a/target/i386/whpx/whpx-all.c
+++ b/target/i386/whpx/whpx-all.c
@@ -14,6 +14,7 @@
#include "system/ioport.h"
#include "gdbstub/helpers.h"
#include "qemu/accel.h"
+#include "accel/accel-ops.h"
#include "system/whpx.h"
#include "system/cpus.h"
#include "system/runstate.h"
diff --git a/target/i386/xsave_helper.c b/target/i386/xsave_helper.c
index 24ab7be..996e9f3 100644
--- a/target/i386/xsave_helper.c
+++ b/target/i386/xsave_helper.c
@@ -5,7 +5,6 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "exec/tswap.h"
void x86_cpu_xsave_all_areas(X86CPU *cpu, void *buf, uint32_t buflen)
{
diff --git a/target/loongarch/loongarch-qmp-cmds.c b/target/loongarch/loongarch-qmp-cmds.c
index f5f1cd0..1d8cd32 100644
--- a/target/loongarch/loongarch-qmp-cmds.c
+++ b/target/loongarch/loongarch-qmp-cmds.c
@@ -7,6 +7,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/target-info.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-machine.h"
#include "cpu.h"
@@ -32,7 +33,7 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
CpuDefinitionInfoList *cpu_list = NULL;
GSList *list;
- list = object_class_get_list(TYPE_LOONGARCH_CPU, false);
+ list = object_class_get_list(target_cpu_type(), false);
g_slist_foreach(list, loongarch_cpu_add_definition, &cpu_list);
g_slist_free(list);
diff --git a/target/mips/cpu-defs.c.inc b/target/mips/cpu-defs.c.inc
index 922fc39..d93b9d3 100644
--- a/target/mips/cpu-defs.c.inc
+++ b/target/mips/cpu-defs.c.inc
@@ -756,8 +756,9 @@ const mips_def_t mips_defs[] =
(1 << CP0C3_RXI) | (1 << CP0C3_LPA) | (1 << CP0C3_VInt),
.CP0_Config4 = MIPS_CONFIG4 | (1U << CP0C4_M) | (3 << CP0C4_IE) |
(1 << CP0C4_AE) | (0xfc << CP0C4_KScrExist),
- .CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_XNP) | (1 << CP0C5_VP) |
- (1 << CP0C5_LLB) | (1 << CP0C5_MRP) | (3 << CP0C5_GI),
+ .CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_CRCP) | (1 << CP0C5_XNP) |
+ (1 << CP0C5_VP) | (1 << CP0C5_LLB) | (1 << CP0C5_MRP) |
+ (3 << CP0C5_GI),
.CP0_Config5_rw_bitmask = (1 << CP0C5_MSAEn) | (1 << CP0C5_SBRI) |
(1 << CP0C5_FRE) | (1 << CP0C5_UFE),
.CP0_LLAddr_rw_bitmask = 0,
@@ -796,8 +797,9 @@ const mips_def_t mips_defs[] =
(1 << CP0C3_RXI) | (1 << CP0C3_LPA) | (1 << CP0C3_VInt),
.CP0_Config4 = MIPS_CONFIG4 | (1U << CP0C4_M) | (3 << CP0C4_IE) |
(1 << CP0C4_AE) | (0xfc << CP0C4_KScrExist),
- .CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_XNP) | (1 << CP0C5_VP) |
- (1 << CP0C5_LLB) | (1 << CP0C5_MRP) | (3 << CP0C5_GI),
+ .CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_CRCP) | (1 << CP0C5_XNP) |
+ (1 << CP0C5_VP) | (1 << CP0C5_LLB) | (1 << CP0C5_MRP) |
+ (3 << CP0C5_GI),
.CP0_Config5_rw_bitmask = (1 << CP0C5_MSAEn) | (1 << CP0C5_SBRI) |
(1 << CP0C5_FRE) | (1 << CP0C5_UFE),
.CP0_LLAddr_rw_bitmask = 0,
diff --git a/target/mips/helper.h b/target/mips/helper.h
index 7e40041..b6cd53c 100644
--- a/target/mips/helper.h
+++ b/target/mips/helper.h
@@ -21,6 +21,8 @@ DEF_HELPER_FLAGS_1(bitswap, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(dbitswap, TCG_CALL_NO_RWG_SE, tl, tl)
#endif
+DEF_HELPER_3(crc32, tl, tl, tl, i32)
+DEF_HELPER_3(crc32c, tl, tl, tl, i32)
DEF_HELPER_FLAGS_4(rotx, TCG_CALL_NO_RWG_SE, tl, tl, i32, i32, i32)
/* microMIPS functions */
diff --git a/target/mips/meson.build b/target/mips/meson.build
index 247979a..abf0ce3 100644
--- a/target/mips/meson.build
+++ b/target/mips/meson.build
@@ -7,6 +7,7 @@ mips_ss.add(files(
'gdbstub.c',
'msa.c',
))
+mips_ss.add(zlib)
if have_system
subdir('system')
diff --git a/target/mips/system/mips-qmp-cmds.c b/target/mips/system/mips-qmp-cmds.c
index d98d662..b6a2874 100644
--- a/target/mips/system/mips-qmp-cmds.c
+++ b/target/mips/system/mips-qmp-cmds.c
@@ -7,6 +7,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/target-info.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-machine.h"
#include "cpu.h"
@@ -40,7 +41,7 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
CpuDefinitionInfoList *cpu_list = NULL;
GSList *list;
- list = object_class_get_list(TYPE_MIPS_CPU, false);
+ list = object_class_get_list(target_cpu_type(), false);
g_slist_foreach(list, mips_cpu_add_definition, &cpu_list);
g_slist_free(list);
diff --git a/target/mips/tcg/micromips_translate.c.inc b/target/mips/tcg/micromips_translate.c.inc
index c479bec..8fda7c8 100644
--- a/target/mips/tcg/micromips_translate.c.inc
+++ b/target/mips/tcg/micromips_translate.c.inc
@@ -1795,7 +1795,7 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx)
return;
case LSA:
check_insn(ctx, ISA_MIPS_R6);
- gen_lsa(ctx, rd, rt, rs, extract32(ctx->opcode, 9, 2));
+ gen_lsa(ctx, rd, rt, rs, extract32(ctx->opcode, 9, 2) + 1);
break;
case ALIGN:
check_insn(ctx, ISA_MIPS_R6);
diff --git a/target/mips/tcg/msa_translate.c b/target/mips/tcg/msa_translate.c
index 75cf80a..82b1499 100644
--- a/target/mips/tcg/msa_translate.c
+++ b/target/mips/tcg/msa_translate.c
@@ -780,7 +780,7 @@ TRANS_DF_iv(ST, trans_msa_ldst, gen_helper_msa_st);
static bool trans_LSA(DisasContext *ctx, arg_r *a)
{
- return gen_lsa(ctx, a->rd, a->rt, a->rs, a->sa);
+ return gen_lsa(ctx, a->rd, a->rt, a->rs, a->sa + 1);
}
static bool trans_DLSA(DisasContext *ctx, arg_r *a)
@@ -788,5 +788,5 @@ static bool trans_DLSA(DisasContext *ctx, arg_r *a)
if (TARGET_LONG_BITS != 64) {
return false;
}
- return gen_dlsa(ctx, a->rd, a->rt, a->rs, a->sa);
+ return gen_dlsa(ctx, a->rd, a->rt, a->rs, a->sa + 1);
}
diff --git a/target/mips/tcg/nanomips_translate.c.inc b/target/mips/tcg/nanomips_translate.c.inc
index 1e27414..9d4e0be 100644
--- a/target/mips/tcg/nanomips_translate.c.inc
+++ b/target/mips/tcg/nanomips_translate.c.inc
@@ -3626,12 +3626,7 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx)
gen_p_lsx(ctx, rd, rs, rt);
break;
case NM_LSA:
- /*
- * In nanoMIPS, the shift field directly encodes the shift
- * amount, meaning that the supported shift values are in
- * the range 0 to 3 (instead of 1 to 4 in MIPSR6).
- */
- gen_lsa(ctx, rd, rt, rs, extract32(ctx->opcode, 9, 2) - 1);
+ gen_lsa(ctx, rd, rt, rs, extract32(ctx->opcode, 9, 2));
break;
case NM_EXTW:
gen_ext(ctx, 32, rd, rs, rt, extract32(ctx->opcode, 6, 5));
diff --git a/target/mips/tcg/octeon.decode b/target/mips/tcg/octeon.decode
index 0c787cb..102a058 100644
--- a/target/mips/tcg/octeon.decode
+++ b/target/mips/tcg/octeon.decode
@@ -1,6 +1,7 @@
# Octeon Architecture Module instruction set
#
# Copyright (C) 2022 Pavel Dovgalyuk
+# Copyright (C) 2024 Philippe Mathieu-Daudé
#
# SPDX-License-Identifier: LGPL-2.1-or-later
#
@@ -39,3 +40,10 @@ CINS 011100 ..... ..... ..... ..... 11001 . @bitfield
POP 011100 rs:5 00000 rd:5 00000 10110 dw:1
SEQNE 011100 rs:5 rt:5 rd:5 00000 10101 ne:1
SEQNEI 011100 rs:5 rt:5 imm:s10 10111 ne:1
+
+&lx base index rd
+@lx ...... base:5 index:5 rd:5 ...... ..... &lx
+LWX 011111 ..... ..... ..... 00000 001010 @lx
+LHX 011111 ..... ..... ..... 00100 001010 @lx
+LBUX 011111 ..... ..... ..... 00110 001010 @lx
+LDX 011111 ..... ..... ..... 01000 001010 @lx
diff --git a/target/mips/tcg/octeon_translate.c b/target/mips/tcg/octeon_translate.c
index d9eb437..b2eca29 100644
--- a/target/mips/tcg/octeon_translate.c
+++ b/target/mips/tcg/octeon_translate.c
@@ -174,3 +174,15 @@ static bool trans_SEQNEI(DisasContext *ctx, arg_SEQNEI *a)
}
return true;
}
+
+static bool trans_lx(DisasContext *ctx, arg_lx *a, MemOp mop)
+{
+ gen_lx(ctx, a->rd, a->base, a->index, mop);
+
+ return true;
+}
+
+TRANS(LBUX, trans_lx, MO_UB);
+TRANS(LHX, trans_lx, MO_SW);
+TRANS(LWX, trans_lx, MO_SL);
+TRANS(LDX, trans_lx, MO_UQ);
diff --git a/target/mips/tcg/op_helper.c b/target/mips/tcg/op_helper.c
index b906d10..4502ae2 100644
--- a/target/mips/tcg/op_helper.c
+++ b/target/mips/tcg/op_helper.c
@@ -24,6 +24,8 @@
#include "exec/helper-proto.h"
#include "exec/memop.h"
#include "fpu_helper.h"
+#include "qemu/crc32c.h"
+#include <zlib.h>
static inline target_ulong bitswap(target_ulong v)
{
@@ -142,6 +144,30 @@ target_ulong helper_rotx(target_ulong rs, uint32_t shift, uint32_t shiftx,
return (int64_t)(int32_t)(uint32_t)tmp5;
}
+/* these crc32 functions are based on target/loongarch/tcg/op_helper.c */
+target_ulong helper_crc32(target_ulong val, target_ulong m, uint32_t sz)
+{
+ uint8_t buf[8];
+ target_ulong mask = ((sz * 8) == 64) ?
+ (target_ulong) -1ULL :
+ ((1ULL << (sz * 8)) - 1);
+
+ m &= mask;
+ stq_le_p(buf, m);
+ return (int32_t) (crc32(val ^ 0xffffffff, buf, sz) ^ 0xffffffff);
+}
+
+target_ulong helper_crc32c(target_ulong val, target_ulong m, uint32_t sz)
+{
+ uint8_t buf[8];
+ target_ulong mask = ((sz * 8) == 64) ?
+ (target_ulong) -1ULL :
+ ((1ULL << (sz * 8)) - 1);
+ m &= mask;
+ stq_le_p(buf, m);
+ return (int32_t) (crc32c(val, buf, sz) ^ 0xffffffff);
+}
+
void helper_fork(target_ulong arg1, target_ulong arg2)
{
/*
diff --git a/target/mips/tcg/rel6.decode b/target/mips/tcg/rel6.decode
index d6989cf..7fbcb10 100644
--- a/target/mips/tcg/rel6.decode
+++ b/target/mips/tcg/rel6.decode
@@ -16,11 +16,16 @@
&r rs rt rd sa
+&special3_crc rs rt c sz
+
@lsa ...... rs:5 rt:5 rd:5 ... sa:2 ...... &r
+@crc32 ...... rs:5 rt:5 ..... c:3 sz:2 ...... &special3_crc
LSA 000000 ..... ..... ..... 000 .. 000101 @lsa
DLSA 000000 ..... ..... ..... 000 .. 010101 @lsa
+CRC32 011111 ..... ..... 00000 ... .. 001111 @crc32
+
REMOVED 010011 ----- ----- ----- ----- ------ # COP1X (COP3)
REMOVED 011100 ----- ----- ----- ----- ------ # SPECIAL2
diff --git a/target/mips/tcg/rel6_translate.c b/target/mips/tcg/rel6_translate.c
index 59f237b..4c05662 100644
--- a/target/mips/tcg/rel6_translate.c
+++ b/target/mips/tcg/rel6_translate.c
@@ -23,7 +23,7 @@ bool trans_REMOVED(DisasContext *ctx, arg_REMOVED *a)
static bool trans_LSA(DisasContext *ctx, arg_r *a)
{
- return gen_lsa(ctx, a->rd, a->rt, a->rs, a->sa);
+ return gen_lsa(ctx, a->rd, a->rt, a->rs, a->sa + 1);
}
static bool trans_DLSA(DisasContext *ctx, arg_r *a)
@@ -31,5 +31,17 @@ static bool trans_DLSA(DisasContext *ctx, arg_r *a)
if (TARGET_LONG_BITS != 64) {
return false;
}
- return gen_dlsa(ctx, a->rd, a->rt, a->rs, a->sa);
+ return gen_dlsa(ctx, a->rd, a->rt, a->rs, a->sa + 1);
+}
+
+static bool trans_CRC32(DisasContext *ctx, arg_special3_crc *a)
+{
+ if (unlikely(!ctx->crcp)
+ || unlikely((a->sz == 3) && (!(ctx->hflags & MIPS_HFLAG_64)))
+ || unlikely((a->c >= 2))) {
+ gen_reserved_instruction(ctx);
+ return true;
+ }
+ gen_crc32(ctx, a->rt, a->rs, a->rt, a->sz, a->c);
+ return true;
}
diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c
index 8658315..d91d6ef 100644
--- a/target/mips/tcg/translate.c
+++ b/target/mips/tcg/translate.c
@@ -1957,6 +1957,17 @@ void gen_base_offset_addr(DisasContext *ctx, TCGv addr, int base, int offset)
}
}
+void gen_base_index_addr(DisasContext *ctx, TCGv addr, int base, int index)
+{
+ if (base == 0) {
+ gen_load_gpr(addr, index);
+ } else if (index == 0) {
+ gen_load_gpr(addr, base);
+ } else {
+ gen_op_addr_add(ctx, addr, cpu_gpr[base], cpu_gpr[index]);
+ }
+}
+
static target_ulong pc_relative_pc(DisasContext *ctx)
{
target_ulong pc = ctx->base.pc_next;
@@ -2025,6 +2036,15 @@ static void gen_lxr(DisasContext *ctx, TCGv reg, TCGv addr,
tcg_gen_or_tl(reg, t0, t1);
}
+void gen_lx(DisasContext *ctx, int rd, int base, int index, MemOp mop)
+{
+ TCGv t0 = tcg_temp_new();
+
+ gen_base_index_addr(ctx, t0, base, index);
+ tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, mo_endian(ctx) | mop);
+ gen_store_gpr(t0, rd);
+}
+
/* Load */
static void gen_ld(DisasContext *ctx, uint32_t opc,
int rt, int base, int offset)
@@ -10546,13 +10566,7 @@ static void gen_flt3_ldst(DisasContext *ctx, uint32_t opc,
{
TCGv t0 = tcg_temp_new();
- if (base == 0) {
- gen_load_gpr(t0, index);
- } else if (index == 0) {
- gen_load_gpr(t0, base);
- } else {
- gen_op_addr_add(ctx, t0, cpu_gpr[base], cpu_gpr[index]);
- }
+ gen_base_index_addr(ctx, t0, base, index);
/*
* Don't do NOP if destination is zero: we must perform the actual
* memory access.
@@ -11323,47 +11337,6 @@ enum {
/* MIPSDSP functions. */
-/* Indexed load is not for DSP only */
-static void gen_mips_lx(DisasContext *ctx, uint32_t opc,
- int rd, int base, int offset)
-{
- TCGv t0;
-
- if (!(ctx->insn_flags & INSN_OCTEON)) {
- check_dsp(ctx);
- }
- t0 = tcg_temp_new();
-
- if (base == 0) {
- gen_load_gpr(t0, offset);
- } else if (offset == 0) {
- gen_load_gpr(t0, base);
- } else {
- gen_op_addr_add(ctx, t0, cpu_gpr[base], cpu_gpr[offset]);
- }
-
- switch (opc) {
- case OPC_LBUX:
- tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_UB);
- gen_store_gpr(t0, rd);
- break;
- case OPC_LHX:
- tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, mo_endian(ctx) | MO_SW);
- gen_store_gpr(t0, rd);
- break;
- case OPC_LWX:
- tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, mo_endian(ctx) | MO_SL);
- gen_store_gpr(t0, rd);
- break;
-#if defined(TARGET_MIPS64)
- case OPC_LDX:
- tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, mo_endian(ctx) | MO_UQ);
- gen_store_gpr(t0, rd);
- break;
-#endif
- }
-}
-
static void gen_mipsdsp_arith(DisasContext *ctx, uint32_t op1, uint32_t op2,
int ret, int v1, int v2)
{
@@ -13449,6 +13422,29 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx)
}
}
+void gen_crc32(DisasContext *ctx, int rd, int rs, int rt, int sz,
+ int crc32c)
+{
+ TCGv t0;
+ TCGv t1;
+ TCGv_i32 tsz = tcg_constant_i32(1 << sz);
+ if (rd == 0) {
+ /* Treat as NOP. */
+ return;
+ }
+ t0 = tcg_temp_new();
+ t1 = tcg_temp_new();
+
+ gen_load_gpr(t0, rt);
+ gen_load_gpr(t1, rs);
+
+ if (crc32c) {
+ gen_helper_crc32c(cpu_gpr[rd], t0, t1, tsz);
+ } else {
+ gen_helper_crc32(cpu_gpr[rd], t0, t1, tsz);
+ }
+}
+
static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx)
{
int rs, rt, rd, sa;
@@ -13611,15 +13607,22 @@ static void decode_opc_special3_legacy(CPUMIPSState *env, DisasContext *ctx)
}
break;
case OPC_LX_DSP:
+ check_dsp(ctx);
op2 = MASK_LX(ctx->opcode);
switch (op2) {
#if defined(TARGET_MIPS64)
case OPC_LDX:
+ gen_lx(ctx, rd, rs, rt, MO_UQ);
+ break;
#endif
case OPC_LBUX:
+ gen_lx(ctx, rd, rs, rt, MO_UB);
+ break;
case OPC_LHX:
+ gen_lx(ctx, rd, rs, rt, MO_SW);
+ break;
case OPC_LWX:
- gen_mips_lx(ctx, op2, rd, rs, rt);
+ gen_lx(ctx, rd, rs, rt, MO_SL);
break;
default: /* Invalid */
MIPS_INVAL("MASK LX");
@@ -15095,6 +15098,7 @@ static void mips_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
ctx->abs2008 = (env->active_fpu.fcr31 >> FCR31_ABS2008) & 1;
ctx->mi = (env->CP0_Config5 >> CP0C5_MI) & 1;
ctx->gi = (env->CP0_Config5 >> CP0C5_GI) & 3;
+ ctx->crcp = (env->CP0_Config5 >> CP0C5_CRCP) & 1;
restore_cpu_state(env, ctx);
#ifdef CONFIG_USER_ONLY
ctx->mem_idx = MIPS_HFLAG_UM;
diff --git a/target/mips/tcg/translate.h b/target/mips/tcg/translate.h
index 1bf153d..89dde1e 100644
--- a/target/mips/tcg/translate.h
+++ b/target/mips/tcg/translate.h
@@ -51,6 +51,7 @@ typedef struct DisasContext {
bool abs2008;
bool mi;
int gi;
+ bool crcp;
} DisasContext;
#define DISAS_STOP DISAS_TARGET_0
@@ -153,6 +154,7 @@ void check_cp1_registers(DisasContext *ctx, int regs);
void check_cop1x(DisasContext *ctx);
void gen_base_offset_addr(DisasContext *ctx, TCGv addr, int base, int offset);
+void gen_base_index_addr(DisasContext *ctx, TCGv addr, int base, int index);
void gen_move_low32(TCGv ret, TCGv_i64 arg);
void gen_move_high32(TCGv ret, TCGv_i64 arg);
void gen_load_gpr(TCGv t, int reg);
@@ -167,6 +169,7 @@ void gen_store_fpr32(DisasContext *ctx, TCGv_i32 t, int reg);
void gen_store_fpr64(DisasContext *ctx, TCGv_i64 t, int reg);
int get_fp_bit(int cc);
+void gen_lx(DisasContext *ctx, int rd, int base, int index, MemOp mop);
void gen_ldxs(DisasContext *ctx, int base, int index, int rd);
void gen_align(DisasContext *ctx, int wordsz, int rd, int rs, int rt, int bp);
void gen_addiupc(DisasContext *ctx, int rx, int imm,
@@ -181,6 +184,7 @@ bool gen_lsa(DisasContext *ctx, int rd, int rt, int rs, int sa);
bool gen_dlsa(DisasContext *ctx, int rd, int rt, int rs, int sa);
void gen_rdhwr(DisasContext *ctx, int rt, int rd, int sel);
+void gen_crc32(DisasContext *ctx, int rd, int rs, int rt, int sz, int crc32c);
extern TCGv cpu_gpr[32], cpu_PC;
#if defined(TARGET_MIPS64)
diff --git a/target/mips/tcg/translate_addr_const.c b/target/mips/tcg/translate_addr_const.c
index 6f4b39f..1d140e9 100644
--- a/target/mips/tcg/translate_addr_const.c
+++ b/target/mips/tcg/translate_addr_const.c
@@ -26,7 +26,7 @@ bool gen_lsa(DisasContext *ctx, int rd, int rt, int rs, int sa)
t1 = tcg_temp_new();
gen_load_gpr(t0, rs);
gen_load_gpr(t1, rt);
- tcg_gen_shli_tl(t0, t0, sa + 1);
+ tcg_gen_shli_tl(t0, t0, sa);
tcg_gen_add_tl(cpu_gpr[rd], t0, t1);
tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
return true;
@@ -47,7 +47,7 @@ bool gen_dlsa(DisasContext *ctx, int rd, int rt, int rs, int sa)
t1 = tcg_temp_new();
gen_load_gpr(t0, rs);
gen_load_gpr(t1, rt);
- tcg_gen_shli_tl(t0, t0, sa + 1);
+ tcg_gen_shli_tl(t0, t0, sa);
tcg_gen_add_tl(cpu_gpr[rd], t0, t1);
return true;
}
diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h
index b8fb12a..ae8d4b3 100644
--- a/target/ppc/mmu-hash64.h
+++ b/target/ppc/mmu-hash64.h
@@ -1,8 +1,6 @@
#ifndef MMU_HASH64_H
#define MMU_HASH64_H
-#include "exec/tswap.h"
-
#ifndef CONFIG_USER_ONLY
#ifdef TARGET_PPC64
diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c
index b41c29d..7c67d67 100644
--- a/target/riscv/vector_helper.c
+++ b/target/riscv/vector_helper.c
@@ -27,7 +27,6 @@
#include "exec/helper-proto.h"
#include "exec/tlb-flags.h"
#include "exec/target_page.h"
-#include "exec/tswap.h"
#include "fpu/softfloat.h"
#include "tcg/tcg-gvec-desc.h"
#include "internals.h"
diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c
index ed7701b..245caf2 100644
--- a/target/sparc/cpu.c
+++ b/target/sparc/cpu.c
@@ -1090,6 +1090,7 @@ static void sparc_cpu_class_init(ObjectClass *oc, const void *data)
cc->disas_set_info = cpu_sparc_disas_set_info;
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
+ cc->gdb_core_xml_file = "sparc64-core.xml";
cc->gdb_num_core_regs = 86;
#else
cc->gdb_num_core_regs = 72;
diff --git a/tests/data/acpi/aarch64/virt/DSDT b/tests/data/acpi/aarch64/virt/DSDT
index 36d3e5d..18d97e8 100644
--- a/tests/data/acpi/aarch64/virt/DSDT
+++ b/tests/data/acpi/aarch64/virt/DSDT
Binary files differ
diff --git a/tests/data/acpi/aarch64/virt/DSDT.acpihmatvirt b/tests/data/acpi/aarch64/virt/DSDT.acpihmatvirt
index e6154d0..2cef095 100644
--- a/tests/data/acpi/aarch64/virt/DSDT.acpihmatvirt
+++ b/tests/data/acpi/aarch64/virt/DSDT.acpihmatvirt
Binary files differ
diff --git a/tests/data/acpi/aarch64/virt/DSDT.acpipcihp b/tests/data/acpi/aarch64/virt/DSDT.acpipcihp
new file mode 100644
index 0000000..8d55a87
--- /dev/null
+++ b/tests/data/acpi/aarch64/virt/DSDT.acpipcihp
Binary files differ
diff --git a/tests/data/acpi/aarch64/virt/DSDT.hpoffacpiindex b/tests/data/acpi/aarch64/virt/DSDT.hpoffacpiindex
new file mode 100644
index 0000000..970d43f
--- /dev/null
+++ b/tests/data/acpi/aarch64/virt/DSDT.hpoffacpiindex
Binary files differ
diff --git a/tests/data/acpi/aarch64/virt/DSDT.memhp b/tests/data/acpi/aarch64/virt/DSDT.memhp
index 33f011d..372ca3d 100644
--- a/tests/data/acpi/aarch64/virt/DSDT.memhp
+++ b/tests/data/acpi/aarch64/virt/DSDT.memhp
Binary files differ
diff --git a/tests/data/acpi/aarch64/virt/DSDT.pxb b/tests/data/acpi/aarch64/virt/DSDT.pxb
index c0fdc6e..c277988 100644
--- a/tests/data/acpi/aarch64/virt/DSDT.pxb
+++ b/tests/data/acpi/aarch64/virt/DSDT.pxb
Binary files differ
diff --git a/tests/data/acpi/aarch64/virt/DSDT.topology b/tests/data/acpi/aarch64/virt/DSDT.topology
index 029d03e..ebbeedc 100644
--- a/tests/data/acpi/aarch64/virt/DSDT.topology
+++ b/tests/data/acpi/aarch64/virt/DSDT.topology
Binary files differ
diff --git a/tests/data/acpi/aarch64/virt/DSDT.viot b/tests/data/acpi/aarch64/virt/DSDT.viot
new file mode 100644
index 0000000..b897d66
--- /dev/null
+++ b/tests/data/acpi/aarch64/virt/DSDT.viot
Binary files differ
diff --git a/tests/data/acpi/aarch64/virt/PPTT b/tests/data/acpi/aarch64/virt/PPTT
index 7a1258e..15598a9 100644
--- a/tests/data/acpi/aarch64/virt/PPTT
+++ b/tests/data/acpi/aarch64/virt/PPTT
Binary files differ
diff --git a/tests/data/acpi/aarch64/virt/PPTT.acpihmatvirt b/tests/data/acpi/aarch64/virt/PPTT.acpihmatvirt
index 4eef303..7b613dd 100644
--- a/tests/data/acpi/aarch64/virt/PPTT.acpihmatvirt
+++ b/tests/data/acpi/aarch64/virt/PPTT.acpihmatvirt
Binary files differ
diff --git a/tests/data/acpi/aarch64/virt/PPTT.topology b/tests/data/acpi/aarch64/virt/PPTT.topology
index 3fbcae5..6b864f0 100644
--- a/tests/data/acpi/aarch64/virt/PPTT.topology
+++ b/tests/data/acpi/aarch64/virt/PPTT.topology
Binary files differ
diff --git a/tests/data/acpi/loongarch64/virt/APIC b/tests/data/acpi/loongarch64/virt/APIC
new file mode 100644
index 0000000..3477789
--- /dev/null
+++ b/tests/data/acpi/loongarch64/virt/APIC
Binary files differ
diff --git a/tests/data/acpi/loongarch64/virt/APIC.topology b/tests/data/acpi/loongarch64/virt/APIC.topology
new file mode 100644
index 0000000..da0089d
--- /dev/null
+++ b/tests/data/acpi/loongarch64/virt/APIC.topology
Binary files differ
diff --git a/tests/data/acpi/loongarch64/virt/DSDT b/tests/data/acpi/loongarch64/virt/DSDT
new file mode 100644
index 0000000..b31841a
--- /dev/null
+++ b/tests/data/acpi/loongarch64/virt/DSDT
Binary files differ
diff --git a/tests/data/acpi/loongarch64/virt/DSDT.memhp b/tests/data/acpi/loongarch64/virt/DSDT.memhp
new file mode 100644
index 0000000..e291200
--- /dev/null
+++ b/tests/data/acpi/loongarch64/virt/DSDT.memhp
Binary files differ
diff --git a/tests/data/acpi/loongarch64/virt/DSDT.numamem b/tests/data/acpi/loongarch64/virt/DSDT.numamem
new file mode 100644
index 0000000..07923ac
--- /dev/null
+++ b/tests/data/acpi/loongarch64/virt/DSDT.numamem
Binary files differ
diff --git a/tests/data/acpi/loongarch64/virt/DSDT.topology b/tests/data/acpi/loongarch64/virt/DSDT.topology
new file mode 100644
index 0000000..6dfbb49
--- /dev/null
+++ b/tests/data/acpi/loongarch64/virt/DSDT.topology
Binary files differ
diff --git a/tests/data/acpi/loongarch64/virt/FACP b/tests/data/acpi/loongarch64/virt/FACP
new file mode 100644
index 0000000..04d8d4c
--- /dev/null
+++ b/tests/data/acpi/loongarch64/virt/FACP
Binary files differ
diff --git a/tests/data/acpi/loongarch64/virt/MCFG b/tests/data/acpi/loongarch64/virt/MCFG
new file mode 100644
index 0000000..5f93b05
--- /dev/null
+++ b/tests/data/acpi/loongarch64/virt/MCFG
Binary files differ
diff --git a/tests/data/acpi/loongarch64/virt/PPTT b/tests/data/acpi/loongarch64/virt/PPTT
new file mode 100644
index 0000000..15598a9
--- /dev/null
+++ b/tests/data/acpi/loongarch64/virt/PPTT
Binary files differ
diff --git a/tests/data/acpi/loongarch64/virt/PPTT.topology b/tests/data/acpi/loongarch64/virt/PPTT.topology
new file mode 100644
index 0000000..7fc9298
--- /dev/null
+++ b/tests/data/acpi/loongarch64/virt/PPTT.topology
Binary files differ
diff --git a/tests/qapi-schema/doc-bad-section.out b/tests/data/acpi/loongarch64/virt/SLIT
index e69de29..e69de29 100644
--- a/tests/qapi-schema/doc-bad-section.out
+++ b/tests/data/acpi/loongarch64/virt/SLIT
diff --git a/tests/data/acpi/loongarch64/virt/SLIT.numamem b/tests/data/acpi/loongarch64/virt/SLIT.numamem
new file mode 100644
index 0000000..67f0081
--- /dev/null
+++ b/tests/data/acpi/loongarch64/virt/SLIT.numamem
Binary files differ
diff --git a/tests/data/acpi/loongarch64/virt/SPCR b/tests/data/acpi/loongarch64/virt/SPCR
new file mode 100644
index 0000000..3cc9bbc
--- /dev/null
+++ b/tests/data/acpi/loongarch64/virt/SPCR
Binary files differ
diff --git a/tests/data/acpi/loongarch64/virt/SRAT b/tests/data/acpi/loongarch64/virt/SRAT
new file mode 100644
index 0000000..ff234ce
--- /dev/null
+++ b/tests/data/acpi/loongarch64/virt/SRAT
Binary files differ
diff --git a/tests/data/acpi/loongarch64/virt/SRAT.memhp b/tests/data/acpi/loongarch64/virt/SRAT.memhp
new file mode 100644
index 0000000..5253218
--- /dev/null
+++ b/tests/data/acpi/loongarch64/virt/SRAT.memhp
Binary files differ
diff --git a/tests/data/acpi/loongarch64/virt/SRAT.numamem b/tests/data/acpi/loongarch64/virt/SRAT.numamem
new file mode 100644
index 0000000..2972a9a
--- /dev/null
+++ b/tests/data/acpi/loongarch64/virt/SRAT.numamem
Binary files differ
diff --git a/tests/data/acpi/loongarch64/virt/SRAT.topology b/tests/data/acpi/loongarch64/virt/SRAT.topology
new file mode 100644
index 0000000..4a44831
--- /dev/null
+++ b/tests/data/acpi/loongarch64/virt/SRAT.topology
Binary files differ
diff --git a/tests/data/acpi/rebuild-expected-aml.sh b/tests/data/acpi/rebuild-expected-aml.sh
index c1092fb..cbf9ffe 100755
--- a/tests/data/acpi/rebuild-expected-aml.sh
+++ b/tests/data/acpi/rebuild-expected-aml.sh
@@ -12,7 +12,7 @@
# This work is licensed under the terms of the GNU GPLv2.
# See the COPYING.LIB file in the top-level directory.
-qemu_arches="x86_64 aarch64 riscv64"
+qemu_arches="x86_64 aarch64 riscv64 loongarch64"
if [ ! -e "tests/qtest/bios-tables-test" ]; then
echo "Test: bios-tables-test is required! Run make check before this script."
@@ -37,7 +37,7 @@ if [ -z "$qemu_bins" ]; then
echo "Only the following architectures are currently supported: $qemu_arches"
echo "None of these configured!"
echo "To fix, run configure \
- --target-list=x86_64-softmmu,aarch64-softmmu,riscv64-softmmu"
+ --target-list=x86_64-softmmu,aarch64-softmmu,riscv64-softmmu,loongarch64-softmmu"
exit 1;
fi
diff --git a/tests/data/acpi/riscv64/virt/DSDT b/tests/data/acpi/riscv64/virt/DSDT
index 6a33f56..527f239 100644
--- a/tests/data/acpi/riscv64/virt/DSDT
+++ b/tests/data/acpi/riscv64/virt/DSDT
Binary files differ
diff --git a/tests/data/acpi/x86/microvm/DSDT.pcie b/tests/data/acpi/x86/microvm/DSDT.pcie
index 8eacd21..ba258f4 100644
--- a/tests/data/acpi/x86/microvm/DSDT.pcie
+++ b/tests/data/acpi/x86/microvm/DSDT.pcie
Binary files differ
diff --git a/tests/qapi-schema/doc-bad-section.err b/tests/qapi-schema/doc-bad-section.err
deleted file mode 100644
index 785cacc..0000000
--- a/tests/qapi-schema/doc-bad-section.err
+++ /dev/null
@@ -1 +0,0 @@
-doc-bad-section.json:5:1: unexpected '=' markup in definition documentation
diff --git a/tests/qapi-schema/doc-bad-section.json b/tests/qapi-schema/doc-bad-section.json
deleted file mode 100644
index 8175d95..0000000
--- a/tests/qapi-schema/doc-bad-section.json
+++ /dev/null
@@ -1,10 +0,0 @@
-# = section within an expression comment
-
-##
-# @Enum:
-# == No good here
-# @one: The _one_ {and only}
-#
-# @two is undocumented
-##
-{ 'enum': 'Enum', 'data': [ 'one', 'two' ] }
diff --git a/tests/qapi-schema/doc-good.json b/tests/qapi-schema/doc-good.json
index 14b808f..fac1342 100644
--- a/tests/qapi-schema/doc-good.json
+++ b/tests/qapi-schema/doc-good.json
@@ -8,7 +8,9 @@
'documentation-exceptions': [ 'Enum', 'Variant1', 'Alternate', 'cmd' ] } }
##
-# = Section
+# *******
+# Section
+# *******
##
##
@@ -16,7 +18,8 @@
##
##
-# == Subsection
+# Subsection
+# ==========
#
# *with emphasis*
# @var {in braces}
@@ -144,7 +147,8 @@
'if': { 'not': { 'any': [ 'IFONE', 'IFTWO' ] } } }
##
-# == Another subsection
+# Another subsection
+# ==================
##
##
diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out
index dc8352e..04a5507 100644
--- a/tests/qapi-schema/doc-good.out
+++ b/tests/qapi-schema/doc-good.out
@@ -55,13 +55,16 @@ event EVT_BOXED Object
feature feat3
doc freeform
body=
-= Section
+*******
+Section
+*******
doc freeform
body=
Just text, no heading.
doc freeform
body=
-== Subsection
+Subsection
+==========
*with emphasis*
@var {in braces}
@@ -155,7 +158,8 @@ description starts on the same line
a feature
doc freeform
body=
-== Another subsection
+Another subsection
+==================
doc symbol=cmd
body=
diff --git a/tests/qapi-schema/doc-good.txt b/tests/qapi-schema/doc-good.txt
index 17a1d56..74b7368 100644
--- a/tests/qapi-schema/doc-good.txt
+++ b/tests/qapi-schema/doc-good.txt
@@ -1,6 +1,8 @@
Section
*******
+Just text, no heading.
+
Subsection
==========
@@ -35,249 +37,145 @@ Example:
-> in <- out Examples: - *verbatim* - {braces}
+Enum Enum
+ *Availability*: "IFCOND"
-"Enum" (Enum)
--------------
-
-
-Values
-~~~~~~
-
-"one" (**If: **"IFONE")
- The _one_ {and only}, description on the same line
-
-"two"
- Not documented
-
-
-Features
-~~~~~~~~
-
-"enum-feat"
- Also _one_ {and only}
-
-"enum-member-feat"
- a member feature
-
-"two" is undocumented
-
-
-If
-~~
-
-"IFCOND"
-
-
-"Base" (Object)
----------------
-
-
-Members
-~~~~~~~
-
-"base1": "Enum"
- description starts on a new line, minimally indented
-
-
-If
-~~
-
-"IFALL1 and IFALL2"
-
-
-"Variant1" (Object)
--------------------
-
-A paragraph
-
-Another paragraph
-
-"var1" is undocumented
+ Values:
+ * **one** -- The _one_ {and only}, description on the same line
+ * **two** -- Not documented
-Members
-~~~~~~~
+ Features:
+ * **enum-feat** -- Also _one_ {and only}
-"var1": "string" (**If: **"IFSTR")
- Not documented
+ * **enum-member-feat** -- a member feature
+ "two" is undocumented
-Features
-~~~~~~~~
+Object Base
+ *Availability*: "IFALL1 and IFALL2"
-"variant1-feat"
- a feature
+ Members:
+ * **base1** ("Enum") -- description starts on a new line,
+ minimally indented
-"member-feat"
- a member feature
+Object Variant1
+ A paragraph
-"Variant2" (Object)
--------------------
+ Another paragraph
+ "var1" is undocumented
-"Object" (Object)
------------------
+ Members:
+ * **var1** ("string") -- Not documented
+ Features:
+ * **variant1-feat** -- a feature
-Members
-~~~~~~~
+ * **member-feat** -- a member feature
-The members of "Base"
-The members of "Variant1" when "base1" is ""one""
-The members of "Variant2" when "base1" is ""two"" (**If: **"IFONE or
-IFTWO")
+Object Variant2
-Features
-~~~~~~~~
+Object Object
-"union-feat1"
- a feature
+ Members:
+ * The members of "Base".
+ * When "base1" is "one": The members of "Variant1".
-"Alternate" (Alternate)
------------------------
+ * When "base1" is "two": The members of "Variant2".
+ Features:
+ * **union-feat1** -- a feature
-Members
-~~~~~~~
+Alternate Alternate
+ *Availability*: "not (IFONE or IFTWO)"
-"i": "int"
- description starts on the same line remainder indented the same "b"
- is undocumented
+ Alternatives:
+ * **i** ("int") -- description starts on the same line remainder
+ indented the same "b" is undocumented
-"b": "boolean"
- Not documented
+ * **b** ("boolean") -- Not documented
-
-Features
-~~~~~~~~
-
-"alt-feat"
- a feature
-
-
-If
-~~
-
-"not (IFONE or IFTWO)"
+ Features:
+ * **alt-feat** -- a feature
Another subsection
==================
+Command cmd (Since: 2.10)
-"cmd" (Command)
----------------
-
-
-Arguments
-~~~~~~~~~
-
-"arg1": "int"
- description starts on a new line, indented
-
-"arg2": "string" (optional)
- description starts on the same line remainder indented differently
-
-"arg3": "boolean"
- Not documented
-
-
-Features
-~~~~~~~~
-
-"cmd-feat1"
- a feature
+ Arguments:
+ * **arg1** ("int") -- description starts on a new line, indented
-"cmd-feat2"
- another feature
-
-Note:
-
- "arg3" is undocumented
-
-
-Returns
-~~~~~~~
-
-"Object"
-
-
-Errors
-~~~~~~
-
-some
-
-Notes:
-
-* Lorem ipsum dolor sit amet
-
-* Ut enim ad minim veniam
-
-Duis aute irure dolor
+ * **arg2** ("string", *optional*) -- description starts on the
+ same line remainder indented differently
-Example: Ideal fast-food burger situation:
+ * **arg3** ("boolean") -- Not documented
- -> "in"
- <- "out"
+ Features:
+ * **cmd-feat1** -- a feature
-Examples:
+ * **cmd-feat2** -- another feature
- - Not a QMP code block
- - Merely a preformatted code block literal
- It isn't even an rST list.
- - *verbatim*
- - {braces}
+ Note:
-Note::
- Ceci n'est pas une note
+ "arg3" is undocumented
+ Return:
+ "Object" -- "Object"
-Since
-~~~~~
+ Errors:
+ some
-2.10
+ Notes:
+ * Lorem ipsum dolor sit amet
-"cmd-boxed" (Command)
----------------------
+ * Ut enim ad minim veniam
-If you're bored enough to read this, go see a video of boxed cats
+ Duis aute irure dolor
+ Example: Ideal fast-food burger situation:
-Arguments
-~~~~~~~~~
+ -> "in"
+ <- "out"
-The members of "Object"
+ Examples:
-Features
-~~~~~~~~
+ - Not a QMP code block
+ - Merely a preformatted code block literal
+ It isn't even an rST list.
+ - *verbatim*
+ - {braces}
-"cmd-feat1"
- a feature
+ Note::
+ Ceci n'est pas une note
-"cmd-feat2"
- another feature
+Command cmd-boxed
-Example::
+ If you're bored enough to read this, go see a video of boxed cats
- -> "this example"
+ Arguments:
+ * The members of "Object".
- <- ... has no title ...
+ Features:
+ * **cmd-feat1** -- a feature
+ * **cmd-feat2** -- another feature
-"EVT_BOXED" (Event)
--------------------
+ Example::
+ -> "this example"
-Arguments
-~~~~~~~~~
+ <- ... has no title ...
-The members of "Object"
+Event EVT_BOXED
-Features
-~~~~~~~~
+ Members:
+ * The members of "Object".
-"feat3"
- a feature
+ Features:
+ * **feat3** -- a feature
diff --git a/tests/qapi-schema/meson.build b/tests/qapi-schema/meson.build
index 9577178..c47025d 100644
--- a/tests/qapi-schema/meson.build
+++ b/tests/qapi-schema/meson.build
@@ -61,7 +61,6 @@ schemas = [
'doc-bad-event-arg.json',
'doc-bad-feature.json',
'doc-bad-indent.json',
- 'doc-bad-section.json',
'doc-bad-symbol.json',
'doc-bad-union-member.json',
'doc-before-include.json',
diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out
index 34e1b45..70c6275 100644
--- a/tests/qemu-iotests/049.out
+++ b/tests/qemu-iotests/049.out
@@ -98,8 +98,7 @@ qemu-img create -f qcow2 -o size=-1024 TEST_DIR/t.qcow2
qemu-img: TEST_DIR/t.qcow2: Value '-1024' is out of range for parameter 'size'
qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- -1k
-qemu-img: Invalid image size specified. You may use k, M, G, T, P or E suffixes for
-qemu-img: kilobytes, megabytes, gigabytes, terabytes, petabytes and exabytes.
+qemu-img: Invalid image size specified: '-1k'
qemu-img create -f qcow2 -o size=-1k TEST_DIR/t.qcow2
qemu-img: TEST_DIR/t.qcow2: Parameter 'size' expects a non-negative number below 2^64
@@ -107,8 +106,7 @@ Optional suffix k, M, G, T, P or E means kilo-, mega-, giga-, tera-, peta-
and exabytes, respectively.
qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- 1kilobyte
-qemu-img: Invalid image size specified. You may use k, M, G, T, P or E suffixes for
-qemu-img: kilobytes, megabytes, gigabytes, terabytes, petabytes and exabytes.
+qemu-img: Invalid image size specified: '1kilobyte'
qemu-img create -f qcow2 -o size=1kilobyte TEST_DIR/t.qcow2
qemu-img: TEST_DIR/t.qcow2: Parameter 'size' expects a non-negative number below 2^64
@@ -116,8 +114,7 @@ Optional suffix k, M, G, T, P or E means kilo-, mega-, giga-, tera-, peta-
and exabytes, respectively.
qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- foobar
-qemu-img: Invalid image size specified. You may use k, M, G, T, P or E suffixes for
-qemu-img: kilobytes, megabytes, gigabytes, terabytes, petabytes and exabytes.
+qemu-img: Invalid image size specified: 'foobar'
qemu-img create -f qcow2 -o size=foobar TEST_DIR/t.qcow2
qemu-img: TEST_DIR/t.qcow2: Parameter 'size' expects a non-negative number below 2^64
diff --git a/tests/qemu-iotests/153 b/tests/qemu-iotests/153
index 9bc3be8..1e02f6a 100755
--- a/tests/qemu-iotests/153
+++ b/tests/qemu-iotests/153
@@ -63,7 +63,7 @@ _supported_proto file
_run_cmd()
{
echo
- (echo "$@"; "$@" 2>&1 1>/dev/null) | _filter_testdir
+ (echo "$@"; "$@" 2>&1 1>/dev/null) | _filter_testdir | _filter_qemu_img
}
_do_run_qemu()
diff --git a/tests/qemu-iotests/153.out b/tests/qemu-iotests/153.out
index ff8e558..28e1a22 100644
--- a/tests/qemu-iotests/153.out
+++ b/tests/qemu-iotests/153.out
@@ -120,16 +120,16 @@ _qemu_img_wrapper compare -U TEST_DIR/t.qcow2 TEST_DIR/t.qcow2
_qemu_img_wrapper map -U TEST_DIR/t.qcow2
_qemu_img_wrapper amend -o size=32M -U TEST_DIR/t.qcow2
-qemu-img: unrecognized option '-U'
-Try 'qemu-img --help' for more information
+qemu-img amend: invalid option -- 'U'
+Try 'qemu-img amend --help' for more information
_qemu_img_wrapper commit -U TEST_DIR/t.qcow2
-qemu-img: unrecognized option '-U'
-Try 'qemu-img --help' for more information
+qemu-img commit: invalid option -- 'U'
+Try 'qemu-img commit --help' for more information
_qemu_img_wrapper resize -U TEST_DIR/t.qcow2 32M
-qemu-img: unrecognized option '-U'
-Try 'qemu-img --help' for more information
+qemu-img resize: invalid option -- 'U'
+Try 'qemu-img resize --help' for more information
_qemu_img_wrapper rebase -U TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base -F qcow2
qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get "write" lock
@@ -244,16 +244,16 @@ _qemu_img_wrapper compare -U TEST_DIR/t.qcow2 TEST_DIR/t.qcow2
_qemu_img_wrapper map -U TEST_DIR/t.qcow2
_qemu_img_wrapper amend -o size=32M -U TEST_DIR/t.qcow2
-qemu-img: unrecognized option '-U'
-Try 'qemu-img --help' for more information
+qemu-img amend: invalid option -- 'U'
+Try 'qemu-img amend --help' for more information
_qemu_img_wrapper commit -U TEST_DIR/t.qcow2
-qemu-img: unrecognized option '-U'
-Try 'qemu-img --help' for more information
+qemu-img commit: invalid option -- 'U'
+Try 'qemu-img commit --help' for more information
_qemu_img_wrapper resize -U TEST_DIR/t.qcow2 32M
-qemu-img: unrecognized option '-U'
-Try 'qemu-img --help' for more information
+qemu-img resize: invalid option -- 'U'
+Try 'qemu-img resize --help' for more information
_qemu_img_wrapper rebase -U TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base -F qcow2
qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get "write" lock
@@ -349,16 +349,16 @@ _qemu_img_wrapper compare -U TEST_DIR/t.qcow2 TEST_DIR/t.qcow2
_qemu_img_wrapper map -U TEST_DIR/t.qcow2
_qemu_img_wrapper amend -o size=32M -U TEST_DIR/t.qcow2
-qemu-img: unrecognized option '-U'
-Try 'qemu-img --help' for more information
+qemu-img amend: invalid option -- 'U'
+Try 'qemu-img amend --help' for more information
_qemu_img_wrapper commit -U TEST_DIR/t.qcow2
-qemu-img: unrecognized option '-U'
-Try 'qemu-img --help' for more information
+qemu-img commit: invalid option -- 'U'
+Try 'qemu-img commit --help' for more information
_qemu_img_wrapper resize -U TEST_DIR/t.qcow2 32M
-qemu-img: unrecognized option '-U'
-Try 'qemu-img --help' for more information
+qemu-img resize: invalid option -- 'U'
+Try 'qemu-img resize --help' for more information
_qemu_img_wrapper rebase -U TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base -F qcow2
diff --git a/tests/qemu-iotests/178 b/tests/qemu-iotests/178
index 8df241e..463c59a 100755
--- a/tests/qemu-iotests/178
+++ b/tests/qemu-iotests/178
@@ -58,7 +58,7 @@ $QEMU_IMG measure -f qcow2 # missing filename
$QEMU_IMG measure -l snap1 # missing filename
$QEMU_IMG measure -o , # invalid option list
$QEMU_IMG measure -l snapshot.foo=bar # invalid snapshot option
-$QEMU_IMG measure --output foo # invalid output format
+$QEMU_IMG measure --output foo 2>&1 | _filter_qemu_img # invalid output format
$QEMU_IMG measure --size -1 # invalid image size
$QEMU_IMG measure -O foo "$TEST_IMG" # unknown image file format
diff --git a/tests/qemu-iotests/178.out.qcow2 b/tests/qemu-iotests/178.out.qcow2
index fe193fd..61506b5 100644
--- a/tests/qemu-iotests/178.out.qcow2
+++ b/tests/qemu-iotests/178.out.qcow2
@@ -12,7 +12,8 @@ qemu-img: --image-opts, -f, and -l require a filename argument.
qemu-img: Invalid option list: ,
qemu-img: Invalid parameter 'snapshot.foo'
qemu-img: Failed in parsing snapshot param 'snapshot.foo=bar'
-qemu-img: --output must be used with human or json as argument.
+qemu-img: --output expects 'human' or 'json', not 'foo'
+Try 'qemu-img measure --help' for more information
qemu-img: Invalid image size specified. Must be between 0 and 9223372036854775807.
qemu-img: Unknown file format 'foo'
diff --git a/tests/qemu-iotests/178.out.raw b/tests/qemu-iotests/178.out.raw
index 445e460..6d994a4 100644
--- a/tests/qemu-iotests/178.out.raw
+++ b/tests/qemu-iotests/178.out.raw
@@ -12,7 +12,8 @@ qemu-img: --image-opts, -f, and -l require a filename argument.
qemu-img: Invalid option list: ,
qemu-img: Invalid parameter 'snapshot.foo'
qemu-img: Failed in parsing snapshot param 'snapshot.foo=bar'
-qemu-img: --output must be used with human or json as argument.
+qemu-img: --output expects 'human' or 'json', not 'foo'
+Try 'qemu-img measure --help' for more information
qemu-img: Invalid image size specified. Must be between 0 and 9223372036854775807.
qemu-img: Unknown file format 'foo'
diff --git a/tests/qemu-iotests/184.out b/tests/qemu-iotests/184.out
index 52692b6..ef99bb2 100644
--- a/tests/qemu-iotests/184.out
+++ b/tests/qemu-iotests/184.out
@@ -41,6 +41,12 @@ Testing:
},
"iops_wr": 0,
"ro": false,
+ "children": [
+ {
+ "node-name": "disk0",
+ "child": "file"
+ }
+ ],
"node-name": "throttle0",
"backing_file_depth": 1,
"drv": "throttle",
@@ -69,6 +75,8 @@ Testing:
},
"iops_wr": 0,
"ro": false,
+ "children": [
+ ],
"node-name": "disk0",
"backing_file_depth": 0,
"drv": "null-co",
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
index fc3c64b..67f819d 100644
--- a/tests/qemu-iotests/common.filter
+++ b/tests/qemu-iotests/common.filter
@@ -86,6 +86,12 @@ _filter_qemu()
-e $'s#\r##' # QEMU monitor uses \r\n line endings
}
+# replace occurrences of QEMU_IMG_PROG with "qemu-img"
+_filter_qemu_img()
+{
+ sed -e "s#$QEMU_IMG_PROG#qemu-img#g"
+}
+
# replace problematic QMP output like timestamps
_filter_qmp()
{
diff --git a/tests/qemu-iotests/tests/qom-set-drive b/tests/qemu-iotests/tests/qom-set-drive
new file mode 100755
index 0000000..ec8ddac
--- /dev/null
+++ b/tests/qemu-iotests/tests/qom-set-drive
@@ -0,0 +1,75 @@
+#!/usr/bin/env python3
+# group: quick
+#
+# Test how changing the 'drive' property via 'qom-set' behaves.
+#
+# Copyright (C) Proxmox Server Solutions GmbH
+#
+# 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/>.
+#
+
+import os
+import iotests
+from iotests import imgfmt, log, qemu_img_create, QMPTestCase
+
+image_size = 1 * 1024 * 1024
+images = [os.path.join(iotests.test_dir, f'{i}.img') for i in range(0, 4)]
+
+class TestQOMSetDrive(QMPTestCase):
+ def setUp(self) -> None:
+ for image in images:
+ qemu_img_create('-f', imgfmt, image, str(image_size))
+
+ self.vm = iotests.VM()
+ for i, image in enumerate(images):
+ self.vm.add_blockdev(self.vm.qmp_to_opts({
+ 'driver': imgfmt,
+ 'node-name': f'node{i}',
+ 'file': {
+ 'driver': 'file',
+ 'filename': image,
+ }
+ }))
+ self.vm.add_object('iothread,id=iothread0')
+ self.vm.add_device('virtio-scsi,iothread=iothread0')
+ self.vm.add_device('scsi-hd,id=iot,drive=node0')
+ self.vm.add_device('virtio-scsi')
+ self.vm.add_device('scsi-hd,id=no-iot,drive=node1')
+ self.vm.launch()
+
+ def tearDown(self) -> None:
+ self.vm.shutdown()
+ for image in images:
+ os.remove(image)
+
+ def test_qom_set_drive(self) -> None:
+ log(self.vm.qmp('qom-get', path='/machine/peripheral/iot',
+ property='drive'))
+ log(self.vm.qmp('qom-set', path='/machine/peripheral/iot',
+ property='drive', value='node2'))
+ log(self.vm.qmp('qom-get', path='/machine/peripheral/iot',
+ property='drive'))
+
+ log(self.vm.qmp('qom-get', path='/machine/peripheral/no-iot',
+ property='drive'))
+ log(self.vm.qmp('qom-set', path='/machine/peripheral/no-iot',
+ property='drive', value='node3'))
+ log(self.vm.qmp('qom-get', path='/machine/peripheral/no-iot',
+ property='drive'))
+
+if __name__ == '__main__':
+ iotests.activate_logging()
+ # LUKS would require special key-secret handling in add_blockdevs()
+ iotests.main(supported_fmts=['generic'],
+ unsupported_fmts=['luks'])
diff --git a/tests/qemu-iotests/tests/qom-set-drive.out b/tests/qemu-iotests/tests/qom-set-drive.out
new file mode 100644
index 0000000..7fc243d
--- /dev/null
+++ b/tests/qemu-iotests/tests/qom-set-drive.out
@@ -0,0 +1,11 @@
+{"return": "node0"}
+{"error": {"class": "GenericError", "desc": "Different aio context is not supported for new node"}}
+{"return": "node0"}
+{"return": "node1"}
+{"return": {}}
+{"return": "node3"}
+.
+----------------------------------------------------------------------
+Ran 1 tests
+
+OK
diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c
index 4dbc07e..6aec68d 100644
--- a/tests/qtest/bios-tables-test.c
+++ b/tests/qtest/bios-tables-test.c
@@ -1643,6 +1643,54 @@ static void test_acpi_aarch64_virt_tcg_memhp(void)
}
+static void test_acpi_aarch64_virt_acpi_pci_hotplug(void)
+{
+ test_data data = {
+ .machine = "virt",
+ .arch = "aarch64",
+ .tcg_only = true,
+ .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
+ .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
+ .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2",
+ .ram_start = 0x40000000ULL,
+ .scan_len = 256ULL * MiB,
+ .variant = ".acpipcihp",
+ };
+
+ /* Use ACPI PCI Hotplug */
+ test_acpi_one(" -global acpi-ged.acpi-pci-hotplug-with-bridge-support=on"
+ " -cpu cortex-a57"
+ " -device pcie-root-port,id=pcie.1,bus=pcie.0,chassis=0,slot=1,addr=7.0"
+ " -device pci-testdev,bus=pcie.1",
+ &data);
+
+ free_test_data(&data);
+}
+
+static void test_acpi_aarch64_virt_pcie_root_port_hpoff(void)
+{
+ test_data data = {
+ .machine = "virt",
+ .arch = "aarch64",
+ .tcg_only = true,
+ .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
+ .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
+ .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2",
+ .ram_start = 0x40000000ULL,
+ .scan_len = 256ULL * MiB,
+ .variant = ".hpoffacpiindex",
+ };
+
+ /* turn hotplug off on the pcie-root-port and use static acpi-index*/
+ test_acpi_one(" -device pcie-root-port,id=pcie.1,chassis=0,"
+ "slot=1,hotplug=off,addr=7.0"
+ " -device pci-testdev,bus=pcie.1,acpi-index=12"
+ " -cpu cortex-a57",
+ &data);
+
+ free_test_data(&data);
+}
+
static void test_acpi_microvm_prepare(test_data *data)
{
data->machine = "microvm";
@@ -1789,6 +1837,44 @@ static void test_acpi_aarch64_virt_tcg_pxb(void)
free_test_data(&data);
}
+static void test_acpi_aarch64_virt_tcg_acpi_spcr(void)
+{
+ test_data data = {
+ .machine = "virt",
+ .arch = "aarch64",
+ .tcg_only = true,
+ .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
+ .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
+ .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2",
+ .ram_start = 0x40000000ULL,
+ .scan_len = 128ULL * 1024 * 1024,
+ .variant = ".acpispcr",
+ };
+
+ test_acpi_one("-cpu cortex-a57 "
+ " -machine spcr=off", &data);
+ free_test_data(&data);
+}
+
+static void test_acpi_riscv64_virt_tcg_acpi_spcr(void)
+{
+ test_data data = {
+ .machine = "virt",
+ .arch = "riscv64",
+ .tcg_only = true,
+ .uefi_fl1 = "pc-bios/edk2-riscv-code.fd",
+ .uefi_fl2 = "pc-bios/edk2-riscv-vars.fd",
+ .cd = "tests/data/uefi-boot-images/bios-tables-test.riscv64.iso.qcow2",
+ .ram_start = 0x80000000ULL,
+ .scan_len = 128ULL * 1024 * 1024,
+ .variant = ".acpispcr",
+ };
+
+ test_acpi_one("-cpu rva22s64 "
+ "-machine spcr=off", &data);
+ free_test_data(&data);
+}
+
static void test_acpi_tcg_acpi_hmat(const char *machine, const char *arch)
{
test_data data = {};
@@ -2237,6 +2323,7 @@ static void test_acpi_aarch64_virt_viot(void)
test_data data = {
.machine = "virt",
.arch = "aarch64",
+ .variant = ".viot",
.tcg_only = true,
.uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
.uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
@@ -2439,6 +2526,74 @@ static void test_acpi_aarch64_virt_oem_fields(void)
g_free(args);
}
+#define LOONGARCH64_INIT_TEST_DATA(data) \
+ test_data data = { \
+ .machine = "virt", \
+ .arch = "loongarch64", \
+ .tcg_only = true, \
+ .uefi_fl1 = "pc-bios/edk2-loongarch64-code.fd", \
+ .uefi_fl2 = "pc-bios/edk2-loongarch64-vars.fd", \
+ .cd = "tests/data/uefi-boot-images/" \
+ "bios-tables-test.loongarch64.iso.qcow2", \
+ .ram_start = 0, \
+ .scan_len = 128ULL * MiB, \
+ }
+
+static void test_acpi_loongarch64_virt(void)
+{
+ LOONGARCH64_INIT_TEST_DATA(data);
+
+ test_acpi_one("-cpu la464 ", &data);
+ free_test_data(&data);
+}
+
+static void test_acpi_loongarch64_virt_topology(void)
+{
+ LOONGARCH64_INIT_TEST_DATA(data);
+
+ data.variant = ".topology";
+ test_acpi_one("-cpu la464 -smp sockets=1,cores=2,threads=2", &data);
+ free_test_data(&data);
+}
+
+static void test_acpi_loongarch64_virt_numamem(void)
+{
+ LOONGARCH64_INIT_TEST_DATA(data);
+
+ data.variant = ".numamem";
+ test_acpi_one(" -cpu la464 -m 128"
+ " -object memory-backend-ram,id=ram0,size=64M"
+ " -object memory-backend-ram,id=ram1,size=64M"
+ " -numa node,memdev=ram0 -numa node,memdev=ram1"
+ " -numa dist,src=0,dst=1,val=21",
+ &data);
+ free_test_data(&data);
+}
+
+static void test_acpi_loongarch64_virt_memhp(void)
+{
+ LOONGARCH64_INIT_TEST_DATA(data);
+
+ data.variant = ".memhp";
+ test_acpi_one(" -cpu la464 -m 128,slots=2,maxmem=256M"
+ " -object memory-backend-ram,id=ram0,size=128M",
+ &data);
+ free_test_data(&data);
+}
+
+static void test_acpi_loongarch64_virt_oem_fields(void)
+{
+ LOONGARCH64_INIT_TEST_DATA(data);
+ char *args;
+
+ args = test_acpi_create_args(&data, "-cpu la464 "OEM_TEST_ARGS);
+ data.qts = qtest_init(args);
+ test_acpi_load_tables(&data);
+ test_oem_fields(&data);
+ qtest_quit(data.qts);
+ free_test_data(&data);
+ g_free(args);
+}
int main(int argc, char *argv[])
{
@@ -2601,9 +2756,15 @@ int main(int argc, char *argv[])
qtest_add_func("acpi/virt/numamem",
test_acpi_aarch64_virt_tcg_numamem);
qtest_add_func("acpi/virt/memhp", test_acpi_aarch64_virt_tcg_memhp);
+ qtest_add_func("acpi/virt/acpipcihp",
+ test_acpi_aarch64_virt_acpi_pci_hotplug);
+ qtest_add_func("acpi/virt/hpoffacpiindex",
+ test_acpi_aarch64_virt_pcie_root_port_hpoff);
qtest_add_func("acpi/virt/pxb", test_acpi_aarch64_virt_tcg_pxb);
qtest_add_func("acpi/virt/oem-fields",
test_acpi_aarch64_virt_oem_fields);
+ qtest_add_func("acpi/virt/acpispcr",
+ test_acpi_aarch64_virt_tcg_acpi_spcr);
if (qtest_has_device("virtio-iommu-pci")) {
qtest_add_func("acpi/virt/viot", test_acpi_aarch64_virt_viot);
}
@@ -2613,6 +2774,19 @@ int main(int argc, char *argv[])
qtest_add_func("acpi/virt", test_acpi_riscv64_virt_tcg);
qtest_add_func("acpi/virt/numamem",
test_acpi_riscv64_virt_tcg_numamem);
+ qtest_add_func("acpi/virt/acpispcr",
+ test_acpi_riscv64_virt_tcg_acpi_spcr);
+ }
+ } else if (strcmp(arch, "loongarch64") == 0) {
+ if (has_tcg) {
+ qtest_add_func("acpi/virt", test_acpi_loongarch64_virt);
+ qtest_add_func("acpi/virt/topology",
+ test_acpi_loongarch64_virt_topology);
+ qtest_add_func("acpi/virt/numamem",
+ test_acpi_loongarch64_virt_numamem);
+ qtest_add_func("acpi/virt/memhp", test_acpi_loongarch64_virt_memhp);
+ qtest_add_func("acpi/virt/oem-fields",
+ test_acpi_loongarch64_virt_oem_fields);
}
}
ret = g_test_run();
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 5ad969f..669d07c 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -148,6 +148,7 @@ qtests_hppa = \
qtests_loongarch64 = qtests_filter + \
(config_all_devices.has_key('CONFIG_LOONGARCH_VIRT') ? ['numa-test'] : []) + \
+ (unpack_edk2_blobs ? ['bios-tables-test'] : []) + \
['boot-serial-test',
'cpu-plug-test']
diff --git a/tests/tcg/mips/include/wrappers_mips64r6.h b/tests/tcg/mips/include/wrappers_mips64r6.h
index d1e5edb..33d03de 100644
--- a/tests/tcg/mips/include/wrappers_mips64r6.h
+++ b/tests/tcg/mips/include/wrappers_mips64r6.h
@@ -23,6 +23,7 @@
#ifndef WRAPPERS_MIPS64R6_H
#define WRAPPERS_MIPS64R6_H
+#include <string.h>
#define DO_MIPS64R6__RD__RS(suffix, mnemonic) \
static inline void do_mips64r6_##suffix(const void *input, \
@@ -80,4 +81,35 @@ DO_MIPS64R6__RD__RS_RT(DMULU, dmulu)
DO_MIPS64R6__RD__RS_RT(DMUHU, dmuhu)
+#define DO_MIPS64R6__RT__RS_RT(suffix, mnemonic) \
+static inline void do_mips64r6_##suffix(const void *input1, \
+ const void *input2, \
+ void *output) \
+{ \
+ if (strncmp(#mnemonic, "crc32", 5) == 0) \
+ __asm__ volatile ( \
+ ".set crc\n\t" \
+ ); \
+ \
+ __asm__ volatile ( \
+ "ld $t1, 0(%0)\n\t" \
+ "ld $t2, 0(%1)\n\t" \
+ #mnemonic " $t2, $t1, $t2\n\t" \
+ "sd $t2, 0(%2)\n\t" \
+ : \
+ : "r" (input1), "r" (input2), "r" (output) \
+ : "t0", "t1", "t2", "memory" \
+ ); \
+}
+
+DO_MIPS64R6__RT__RS_RT(CRC32B, crc32b)
+DO_MIPS64R6__RT__RS_RT(CRC32H, crc32h)
+DO_MIPS64R6__RT__RS_RT(CRC32W, crc32w)
+DO_MIPS64R6__RT__RS_RT(CRC32D, crc32d)
+
+DO_MIPS64R6__RT__RS_RT(CRC32CB, crc32cb)
+DO_MIPS64R6__RT__RS_RT(CRC32CH, crc32ch)
+DO_MIPS64R6__RT__RS_RT(CRC32CW, crc32cw)
+DO_MIPS64R6__RT__RS_RT(CRC32CD, crc32cd)
+
#endif
diff --git a/tests/tcg/mips/user/isa/mips64r6/crc/Makefile b/tests/tcg/mips/user/isa/mips64r6/crc/Makefile
new file mode 100644
index 0000000..b7f5811
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips64r6/crc/Makefile
@@ -0,0 +1,40 @@
+#
+# Test program for MIPS64R6 CRC32 instructions
+#
+# Copyright (C) 2025 Aleksandar Rakic <aleksandar.rakic@htecgroup.com>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+
+ifndef PREFIX
+ $(error "PREFIX not set, please export GNU Toolchain install directory.")
+endif
+
+ifndef SYSROOT
+ $(error "SYSROOT not set, please export GNU Toolchain system root directory.")
+endif
+
+SIM = ../../../../../../../build/qemu-mips64
+SIM_FLAGS = -L $(SYSROOT)
+
+CC = $(PREFIX)/bin/mips64-r6-linux-gnu-gcc
+
+TESTCASES = test_mips64r6_crc32b.tst
+TESTCASES += test_mips64r6_crc32h.tst
+TESTCASES += test_mips64r6_crc32w.tst
+TESTCASES += test_mips64r6_crc32d.tst
+TESTCASES += test_mips64r6_crc32cb.tst
+TESTCASES += test_mips64r6_crc32ch.tst
+TESTCASES += test_mips64r6_crc32cw.tst
+TESTCASES += test_mips64r6_crc32cd.tst
+
+all: $(TESTCASES)
+ @for case in $(TESTCASES); do \
+ echo $(SIM) $(SIM_FLAGS) ./$$case; \
+ $(SIM) $(SIM_FLAGS) ./$$case; \
+ echo $(RM) -rf ./$$case; \
+ $(RM) -rf ./$$case; \
+ done
+
+%.tst: %.c
+ $(CC) $< -o $@
diff --git a/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32b.c b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32b.c
new file mode 100644
index 0000000..bb1f3f6
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32b.c
@@ -0,0 +1,142 @@
+/*
+ * Test program for MIPS64R6 instruction CRC32B
+ *
+ * Copyright (C) 2019 Wave Computing, Inc.
+ * Copyright (C) 2019 Aleksandar Markovic <amarkovic@wavecomp.com>
+ * Copyright (C) 2025 Aleksandar Rakic <aleksandar.rakic@htecgroup.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/wrappers_mips64r6.h"
+#include "../../../../include/test_inputs_64.h"
+#include "../../../../include/test_utils_64.h"
+
+#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT)
+
+int32_t main(void)
+{
+ char *isa_ase_name = "mips64r6";
+ char *group_name = "CRC with reversed polynomial 0xEDB88320";
+ char *instruction_name = "CRC32B";
+ int32_t ret;
+ uint32_t i, j;
+ struct timeval start, end;
+ double elapsed_time;
+
+ uint64_t b64_result[TEST_COUNT_TOTAL];
+ uint64_t b64_expect[TEST_COUNT_TOTAL] = {
+ 0x0000000000ffffffULL, /* 0 */
+ 0x000000002d02ef8dULL,
+ 0x000000001bab0fd1ULL,
+ 0x0000000036561fa3ULL,
+ 0xffffffffbf1caddaULL,
+ 0xffffffff92e1bda8ULL,
+ 0x00000000278c7949ULL,
+ 0x000000000a71693bULL,
+ 0x000000002dfd1072ULL, /* 8 */
+ 0x0000000000000000ULL,
+ 0x0000000036a9e05cULL,
+ 0x000000001b54f02eULL,
+ 0xffffffff921e4257ULL,
+ 0xffffffffbfe35225ULL,
+ 0x000000000a8e96c4ULL,
+ 0x00000000277386b6ULL,
+ 0x000000001bfe5a84ULL, /* 16 */
+ 0x0000000036034af6ULL,
+ 0x0000000000aaaaaaULL,
+ 0x000000002d57bad8ULL,
+ 0xffffffffa41d08a1ULL,
+ 0xffffffff89e018d3ULL,
+ 0x000000003c8ddc32ULL,
+ 0x000000001170cc40ULL,
+ 0x0000000036fcb509ULL, /* 24 */
+ 0x000000001b01a57bULL,
+ 0x000000002da84527ULL,
+ 0x0000000000555555ULL,
+ 0xffffffff891fe72cULL,
+ 0xffffffffa4e2f75eULL,
+ 0x00000000118f33bfULL,
+ 0x000000003c7223cdULL,
+ 0xffffffffbf2f9ee9ULL, /* 32 */
+ 0xffffffff92d28e9bULL,
+ 0xffffffffa47b6ec7ULL,
+ 0xffffffff89867eb5ULL,
+ 0x0000000000ccccccULL,
+ 0x000000002d31dcbeULL,
+ 0xffffffff985c185fULL,
+ 0xffffffffb5a1082dULL,
+ 0xffffffff922d7164ULL, /* 40 */
+ 0xffffffffbfd06116ULL,
+ 0xffffffff8979814aULL,
+ 0xffffffffa4849138ULL,
+ 0x000000002dce2341ULL,
+ 0x0000000000333333ULL,
+ 0xffffffffb55ef7d2ULL,
+ 0xffffffff98a3e7a0ULL,
+ 0x0000000027fdbe55ULL, /* 48 */
+ 0x000000000a00ae27ULL,
+ 0x000000003ca94e7bULL,
+ 0x0000000011545e09ULL,
+ 0xffffffff981eec70ULL,
+ 0xffffffffb5e3fc02ULL,
+ 0x00000000008e38e3ULL,
+ 0x000000002d732891ULL,
+ 0x000000000aff51d8ULL, /* 56 */
+ 0x00000000270241aaULL,
+ 0x0000000011aba1f6ULL,
+ 0x000000003c56b184ULL,
+ 0xffffffffb51c03fdULL,
+ 0xffffffff98e1138fULL,
+ 0x000000002d8cd76eULL,
+ 0x000000000071c71cULL,
+ 0x0000000000286255ULL, /* 64 */
+ 0x00000000784a5a65ULL,
+ 0xffffffff9bdd0d3bULL,
+ 0xffffffffe7e61ce5ULL,
+ 0x00000000782fabf7ULL,
+ 0x00000000004d93c7ULL,
+ 0xffffffffe3dac499ULL,
+ 0xffffffff9fe1d547ULL,
+ 0xffffffff9b4ca0e5ULL, /* 72 */
+ 0xffffffffe32e98d5ULL,
+ 0x0000000000b9cf8bULL,
+ 0x000000007c82de55ULL,
+ 0xffffffffe7904f52ULL,
+ 0xffffffff9ff27762ULL,
+ 0x000000007c65203cULL,
+ 0x00000000005e31e2ULL,
+ };
+
+ gettimeofday(&start, NULL);
+
+ for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32B(b64_pattern + i, b64_pattern + j,
+ b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32B(b64_random + i, b64_random + j,
+ b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) *
+ (PATTERN_INPUTS_64_SHORT_COUNT)) +
+ RANDOM_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ gettimeofday(&end, NULL);
+
+ elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0;
+ elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0;
+
+ ret = check_results_64(isa_ase_name, group_name, instruction_name,
+ TEST_COUNT_TOTAL, elapsed_time, b64_result,
+ b64_expect);
+
+ return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32cb.c b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32cb.c
new file mode 100644
index 0000000..1439d44
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32cb.c
@@ -0,0 +1,142 @@
+/*
+ * Test program for MIPS64R6 instruction CRC32CB
+ *
+ * Copyright (C) 2019 Wave Computing, Inc.
+ * Copyright (C) 2019 Aleksandar Markovic <amarkovic@wavecomp.com>
+ * Copyright (C) 2025 Aleksandar Rakic <aleksandar.rakic@htecgroup.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/wrappers_mips64r6.h"
+#include "../../../../include/test_inputs_64.h"
+#include "../../../../include/test_utils_64.h"
+
+#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT)
+
+int32_t main(void)
+{
+ char *isa_ase_name = "mips64r6";
+ char *group_name = "CRC with reversed polynomial 0x82F63B78";
+ char *instruction_name = "CRC32CB";
+ int32_t ret;
+ uint32_t i, j;
+ struct timeval start, end;
+ double elapsed_time;
+
+ uint64_t b64_result[TEST_COUNT_TOTAL];
+ uint64_t b64_expect[TEST_COUNT_TOTAL] = {
+ 0x0000000000ffffffULL, /* 0 */
+ 0xffffffffad7d5351ULL,
+ 0x00000000647e6465ULL,
+ 0xffffffffc9fcc8cbULL,
+ 0x00000000237f7689ULL,
+ 0xffffffff8efdda27ULL,
+ 0xffffffff837defedULL,
+ 0x000000002eff4343ULL,
+ 0xffffffffad82acaeULL, /* 8 */
+ 0x0000000000000000ULL,
+ 0xffffffffc9033734ULL,
+ 0x0000000064819b9aULL,
+ 0xffffffff8e0225d8ULL,
+ 0x0000000023808976ULL,
+ 0x000000002e00bcbcULL,
+ 0xffffffff83821012ULL,
+ 0x00000000642b3130ULL, /* 16 */
+ 0xffffffffc9a99d9eULL,
+ 0x0000000000aaaaaaULL,
+ 0xffffffffad280604ULL,
+ 0x0000000047abb846ULL,
+ 0xffffffffea2914e8ULL,
+ 0xffffffffe7a92122ULL,
+ 0x000000004a2b8d8cULL,
+ 0xffffffffc9566261ULL, /* 24 */
+ 0x0000000064d4cecfULL,
+ 0xffffffffadd7f9fbULL,
+ 0x0000000000555555ULL,
+ 0xffffffffead6eb17ULL,
+ 0x00000000475447b9ULL,
+ 0x000000004ad47273ULL,
+ 0xffffffffe756deddULL,
+ 0x00000000234c45baULL, /* 32 */
+ 0xffffffff8ecee914ULL,
+ 0x0000000047cdde20ULL,
+ 0xffffffffea4f728eULL,
+ 0x0000000000ccccccULL,
+ 0xffffffffad4e6062ULL,
+ 0xffffffffa0ce55a8ULL,
+ 0x000000000d4cf906ULL,
+ 0xffffffff8e3116ebULL, /* 40 */
+ 0x0000000023b3ba45ULL,
+ 0xffffffffeab08d71ULL,
+ 0x00000000473221dfULL,
+ 0xffffffffadb19f9dULL,
+ 0x0000000000333333ULL,
+ 0x000000000db306f9ULL,
+ 0xffffffffa031aa57ULL,
+ 0xffffffff830c28f1ULL, /* 48 */
+ 0x000000002e8e845fULL,
+ 0xffffffffe78db36bULL,
+ 0x000000004a0f1fc5ULL,
+ 0xffffffffa08ca187ULL,
+ 0x000000000d0e0d29ULL,
+ 0x00000000008e38e3ULL,
+ 0xffffffffad0c944dULL,
+ 0x000000002e717ba0ULL, /* 56 */
+ 0xffffffff83f3d70eULL,
+ 0x000000004af0e03aULL,
+ 0xffffffffe7724c94ULL,
+ 0x000000000df1f2d6ULL,
+ 0xffffffffa0735e78ULL,
+ 0xffffffffadf36bb2ULL,
+ 0x000000000071c71cULL,
+ 0x0000000000286255ULL, /* 64 */
+ 0xffffffffcbefd6b4ULL,
+ 0xffffffffc334e94fULL,
+ 0xffffffffac268ec5ULL,
+ 0xffffffffcb8a2726ULL,
+ 0x00000000004d93c7ULL,
+ 0x000000000896ac3cULL,
+ 0x000000006784cbb6ULL,
+ 0xffffffffc3a54491ULL, /* 72 */
+ 0x000000000862f070ULL,
+ 0x0000000000b9cf8bULL,
+ 0x000000006faba801ULL,
+ 0xffffffffac50dd72ULL,
+ 0x0000000067976993ULL,
+ 0x000000006f4c5668ULL,
+ 0x00000000005e31e2ULL,
+ };
+
+ gettimeofday(&start, NULL);
+
+ for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32CB(b64_pattern + i, b64_pattern + j,
+ b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32CB(b64_random + i, b64_random + j,
+ b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) *
+ (PATTERN_INPUTS_64_SHORT_COUNT)) +
+ RANDOM_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ gettimeofday(&end, NULL);
+
+ elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0;
+ elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0;
+
+ ret = check_results_64(isa_ase_name, group_name, instruction_name,
+ TEST_COUNT_TOTAL, elapsed_time, b64_result,
+ b64_expect);
+
+ return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32cd.c b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32cd.c
new file mode 100644
index 0000000..bf258e0
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32cd.c
@@ -0,0 +1,142 @@
+/*
+ * Test program for MIPS64R6 instruction CRC32CD
+ *
+ * Copyright (C) 2019 Wave Computing, Inc.
+ * Copyright (C) 2019 Aleksandar Markovic <amarkovic@wavecomp.com>
+ * Copyright (C) 2025 Aleksandar Rakic <aleksandar.rakic@htecgroup.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/wrappers_mips64r6.h"
+#include "../../../../include/test_inputs_64.h"
+#include "../../../../include/test_utils_64.h"
+
+#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT)
+
+int32_t main(void)
+{
+ char *isa_ase_name = "mips64r6";
+ char *group_name = "CRC with reversed polynomial 0x82F63B78";
+ char *instruction_name = "CRC32CD";
+ int32_t ret;
+ uint32_t i, j;
+ struct timeval start, end;
+ double elapsed_time;
+
+ uint64_t b64_result[TEST_COUNT_TOTAL];
+ uint64_t b64_expect[TEST_COUNT_TOTAL] = {
+ 0xffffffffb798b438ULL, /* 0 */
+ 0xffffffffc44ff94dULL,
+ 0xffffffff992a70ebULL,
+ 0xffffffffeafd3d9eULL,
+ 0x000000005152da26ULL,
+ 0x0000000022859753ULL,
+ 0x0000000015cb6d32ULL,
+ 0x00000000661c2047ULL,
+ 0x0000000073d74d75ULL, /* 8 */
+ 0x0000000000000000ULL,
+ 0x000000005d6589a6ULL,
+ 0x000000002eb2c4d3ULL,
+ 0xffffffff951d236bULL,
+ 0xffffffffe6ca6e1eULL,
+ 0xffffffffd184947fULL,
+ 0xffffffffa253d90aULL,
+ 0x0000000008f9ceacULL, /* 16 */
+ 0x000000007b2e83d9ULL,
+ 0x00000000264b0a7fULL,
+ 0x00000000559c470aULL,
+ 0xffffffffee33a0b2ULL,
+ 0xffffffff9de4edc7ULL,
+ 0xffffffffaaaa17a6ULL,
+ 0xffffffffd97d5ad3ULL,
+ 0xffffffffccb637e1ULL, /* 24 */
+ 0xffffffffbf617a94ULL,
+ 0xffffffffe204f332ULL,
+ 0xffffffff91d3be47ULL,
+ 0x000000002a7c59ffULL,
+ 0x0000000059ab148aULL,
+ 0x000000006ee5eeebULL,
+ 0x000000001d32a39eULL,
+ 0x0000000021e3b01bULL, /* 32 */
+ 0x000000005234fd6eULL,
+ 0x000000000f5174c8ULL,
+ 0x000000007c8639bdULL,
+ 0xffffffffc729de05ULL,
+ 0xffffffffb4fe9370ULL,
+ 0xffffffff83b06911ULL,
+ 0xfffffffff0672464ULL,
+ 0xffffffffe5ac4956ULL, /* 40 */
+ 0xffffffff967b0423ULL,
+ 0xffffffffcb1e8d85ULL,
+ 0xffffffffb8c9c0f0ULL,
+ 0x0000000003662748ULL,
+ 0x0000000070b16a3dULL,
+ 0x0000000047ff905cULL,
+ 0x000000003428dd29ULL,
+ 0xffffffffb89d59a6ULL, /* 48 */
+ 0xffffffffcb4a14d3ULL,
+ 0xffffffff962f9d75ULL,
+ 0xffffffffe5f8d000ULL,
+ 0x000000005e5737b8ULL,
+ 0x000000002d807acdULL,
+ 0x000000001ace80acULL,
+ 0x000000006919cdd9ULL,
+ 0x000000007cd2a0ebULL, /* 56 */
+ 0x000000000f05ed9eULL,
+ 0x0000000052606438ULL,
+ 0x0000000021b7294dULL,
+ 0xffffffff9a18cef5ULL,
+ 0xffffffffe9cf8380ULL,
+ 0xffffffffde8179e1ULL,
+ 0xffffffffad563494ULL,
+ 0x000000003a358bb3ULL, /* 64 */
+ 0xffffffff975446ebULL,
+ 0x0000000041d37ad6ULL,
+ 0x000000004be84fe1ULL,
+ 0xffffffff9671b1b3ULL,
+ 0x000000003b107cebULL,
+ 0xffffffffed9740d6ULL,
+ 0xffffffffe7ac75e1ULL,
+ 0xffffffffa1489696ULL, /* 72 */
+ 0x000000000c295bceULL,
+ 0xffffffffdaae67f3ULL,
+ 0xffffffffd09552c4ULL,
+ 0x0000000042bd7071ULL,
+ 0xffffffffefdcbd29ULL,
+ 0x00000000395b8114ULL,
+ 0x000000003360b423ULL,
+ };
+
+ gettimeofday(&start, NULL);
+
+ for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32CD(b64_pattern + i, b64_pattern + j,
+ b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32CD(b64_random + i, b64_random + j,
+ b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) *
+ (PATTERN_INPUTS_64_SHORT_COUNT)) +
+ RANDOM_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ gettimeofday(&end, NULL);
+
+ elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0;
+ elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0;
+
+ ret = check_results_64(isa_ase_name, group_name, instruction_name,
+ TEST_COUNT_TOTAL, elapsed_time, b64_result,
+ b64_expect);
+
+ return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32ch.c b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32ch.c
new file mode 100644
index 0000000..0e7b677
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32ch.c
@@ -0,0 +1,142 @@
+/*
+ * Test program for MIPS64R6 instruction CRC32CH
+ *
+ * Copyright (C) 2019 Wave Computing, Inc.
+ * Copyright (C) 2019 Aleksandar Markovic <amarkovic@wavecomp.com>
+ * Copyright (C) 2025 Aleksandar Rakic <aleksandar.rakic@htecgroup.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/wrappers_mips64r6.h"
+#include "../../../../include/test_inputs_64.h"
+#include "../../../../include/test_utils_64.h"
+
+#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT)
+
+int32_t main(void)
+{
+ char *isa_ase_name = "mips64r6";
+ char *group_name = "CRC with reversed polynomial 0x82F63B78";
+ char *instruction_name = "CRC32CH";
+ int32_t ret;
+ uint32_t i, j;
+ struct timeval start, end;
+ double elapsed_time;
+
+ uint64_t b64_result[TEST_COUNT_TOTAL];
+ uint64_t b64_expect[TEST_COUNT_TOTAL] = {
+ 0x000000000000ffffULL, /* 0 */
+ 0x000000000e9e77d2ULL,
+ 0xfffffffff92eaa4bULL,
+ 0xfffffffff7b02266ULL,
+ 0x00000000571acc93ULL,
+ 0x00000000598444beULL,
+ 0xfffffffff1e6ca77ULL,
+ 0xffffffffff78425aULL,
+ 0x000000000e9e882dULL, /* 8 */
+ 0x0000000000000000ULL,
+ 0xfffffffff7b0dd99ULL,
+ 0xfffffffff92e55b4ULL,
+ 0x000000005984bb41ULL,
+ 0x00000000571a336cULL,
+ 0xffffffffff78bda5ULL,
+ 0xfffffffff1e63588ULL,
+ 0xfffffffff92eff1eULL, /* 16 */
+ 0xfffffffff7b07733ULL,
+ 0x000000000000aaaaULL,
+ 0x000000000e9e2287ULL,
+ 0xffffffffae34cc72ULL,
+ 0xffffffffa0aa445fULL,
+ 0x0000000008c8ca96ULL,
+ 0x00000000065642bbULL,
+ 0xfffffffff7b088ccULL, /* 24 */
+ 0xfffffffff92e00e1ULL,
+ 0x000000000e9edd78ULL,
+ 0x0000000000005555ULL,
+ 0xffffffffa0aabba0ULL,
+ 0xffffffffae34338dULL,
+ 0x000000000656bd44ULL,
+ 0x0000000008c83569ULL,
+ 0x00000000571affa0ULL, /* 32 */
+ 0x000000005984778dULL,
+ 0xffffffffae34aa14ULL,
+ 0xffffffffa0aa2239ULL,
+ 0x000000000000ccccULL,
+ 0x000000000e9e44e1ULL,
+ 0xffffffffa6fcca28ULL,
+ 0xffffffffa8624205ULL,
+ 0x0000000059848872ULL, /* 40 */
+ 0x00000000571a005fULL,
+ 0xffffffffa0aaddc6ULL,
+ 0xffffffffae3455ebULL,
+ 0x000000000e9ebb1eULL,
+ 0x0000000000003333ULL,
+ 0xffffffffa862bdfaULL,
+ 0xffffffffa6fc35d7ULL,
+ 0xfffffffff1e6bbb0ULL, /* 48 */
+ 0xffffffffff78339dULL,
+ 0x0000000008c8ee04ULL,
+ 0x0000000006566629ULL,
+ 0xffffffffa6fc88dcULL,
+ 0xffffffffa86200f1ULL,
+ 0x0000000000008e38ULL,
+ 0x000000000e9e0615ULL,
+ 0xffffffffff78cc62ULL, /* 56 */
+ 0xfffffffff1e6444fULL,
+ 0x00000000065699d6ULL,
+ 0x0000000008c811fbULL,
+ 0xffffffffa862ff0eULL,
+ 0xffffffffa6fc7723ULL,
+ 0x000000000e9ef9eaULL,
+ 0x00000000000071c7ULL,
+ 0x0000000000002862ULL, /* 64 */
+ 0x000000001190c4cfULL,
+ 0x000000007b7fdbbeULL,
+ 0xffffffff9204da99ULL,
+ 0x000000001190a13eULL,
+ 0x0000000000004d93ULL,
+ 0x000000006aef52e2ULL,
+ 0xffffffff839453c5ULL,
+ 0x000000007b7f4a13ULL, /* 72 */
+ 0x000000006aefa6beULL,
+ 0x000000000000b9cfULL,
+ 0xffffffffe97bb8e8ULL,
+ 0xffffffff9204accaULL,
+ 0xffffffff83944067ULL,
+ 0xffffffffe97b5f16ULL,
+ 0x0000000000005e31ULL,
+ };
+
+ gettimeofday(&start, NULL);
+
+ for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32CH(b64_pattern + i, b64_pattern + j,
+ b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32CH(b64_random + i, b64_random + j,
+ b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) *
+ (PATTERN_INPUTS_64_SHORT_COUNT)) +
+ RANDOM_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ gettimeofday(&end, NULL);
+
+ elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0;
+ elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0;
+
+ ret = check_results_64(isa_ase_name, group_name, instruction_name,
+ TEST_COUNT_TOTAL, elapsed_time, b64_result,
+ b64_expect);
+
+ return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32cw.c b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32cw.c
new file mode 100644
index 0000000..f7110b3
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32cw.c
@@ -0,0 +1,142 @@
+/*
+ * Test program for MIPS64R6 instruction CRC32CW
+ *
+ * Copyright (C) 2019 Wave Computing, Inc.
+ * Copyright (C) 2019 Aleksandar Markovic <amarkovic@wavecomp.com>
+ * Copyright (C) 2025 Aleksandar Rakic <aleksandar.rakic@htecgroup.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/wrappers_mips64r6.h"
+#include "../../../../include/test_inputs_64.h"
+#include "../../../../include/test_utils_64.h"
+
+#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT)
+
+int32_t main(void)
+{
+ char *isa_ase_name = "mips64r6";
+ char *group_name = "CRC with reversed polynomial 0x82F63B78";
+ char *instruction_name = "CRC32CW";
+ int32_t ret;
+ uint32_t i, j;
+ struct timeval start, end;
+ double elapsed_time;
+
+ uint64_t b64_result[TEST_COUNT_TOTAL];
+ uint64_t b64_expect[TEST_COUNT_TOTAL] = {
+ 0x0000000000000000ULL, /* 0 */
+ 0xffffffffb798b438ULL,
+ 0xffffffff91d3be47ULL,
+ 0x00000000264b0a7fULL,
+ 0x0000000070b16a3dULL,
+ 0xffffffffc729de05ULL,
+ 0x0000000063c5950aULL,
+ 0xffffffffd45d2132ULL,
+ 0xffffffffb798b438ULL, /* 8 */
+ 0x0000000000000000ULL,
+ 0x00000000264b0a7fULL,
+ 0xffffffff91d3be47ULL,
+ 0xffffffffc729de05ULL,
+ 0x0000000070b16a3dULL,
+ 0xffffffffd45d2132ULL,
+ 0x0000000063c5950aULL,
+ 0xffffffff91d3be47ULL, /* 16 */
+ 0x00000000264b0a7fULL,
+ 0x0000000000000000ULL,
+ 0xffffffffb798b438ULL,
+ 0xffffffffe162d47aULL,
+ 0x0000000056fa6042ULL,
+ 0xfffffffff2162b4dULL,
+ 0x00000000458e9f75ULL,
+ 0x00000000264b0a7fULL, /* 24 */
+ 0xffffffff91d3be47ULL,
+ 0xffffffffb798b438ULL,
+ 0x0000000000000000ULL,
+ 0x0000000056fa6042ULL,
+ 0xffffffffe162d47aULL,
+ 0x00000000458e9f75ULL,
+ 0xfffffffff2162b4dULL,
+ 0x0000000070b16a3dULL, /* 32 */
+ 0xffffffffc729de05ULL,
+ 0xffffffffe162d47aULL,
+ 0x0000000056fa6042ULL,
+ 0x0000000000000000ULL,
+ 0xffffffffb798b438ULL,
+ 0x000000001374ff37ULL,
+ 0xffffffffa4ec4b0fULL,
+ 0xffffffffc729de05ULL, /* 40 */
+ 0x0000000070b16a3dULL,
+ 0x0000000056fa6042ULL,
+ 0xffffffffe162d47aULL,
+ 0xffffffffb798b438ULL,
+ 0x0000000000000000ULL,
+ 0xffffffffa4ec4b0fULL,
+ 0x000000001374ff37ULL,
+ 0x0000000063c5950aULL, /* 48 */
+ 0xffffffffd45d2132ULL,
+ 0xfffffffff2162b4dULL,
+ 0x00000000458e9f75ULL,
+ 0x000000001374ff37ULL,
+ 0xffffffffa4ec4b0fULL,
+ 0x0000000000000000ULL,
+ 0xffffffffb798b438ULL,
+ 0xffffffffd45d2132ULL, /* 56 */
+ 0x0000000063c5950aULL,
+ 0x00000000458e9f75ULL,
+ 0xfffffffff2162b4dULL,
+ 0xffffffffa4ec4b0fULL,
+ 0x000000001374ff37ULL,
+ 0xffffffffb798b438ULL,
+ 0x0000000000000000ULL,
+ 0x0000000000000000ULL, /* 64 */
+ 0xffffffffea0755b2ULL,
+ 0x0000000008b188e6ULL,
+ 0xffffffffff3cc8d9ULL,
+ 0xffffffffea0755b2ULL,
+ 0x0000000000000000ULL,
+ 0xffffffffe2b6dd54ULL,
+ 0x00000000153b9d6bULL,
+ 0x0000000008b188e6ULL, /* 72 */
+ 0xffffffffe2b6dd54ULL,
+ 0x0000000000000000ULL,
+ 0xfffffffff78d403fULL,
+ 0xffffffffff3cc8d9ULL,
+ 0x00000000153b9d6bULL,
+ 0xfffffffff78d403fULL,
+ 0x0000000000000000ULL,
+ };
+
+ gettimeofday(&start, NULL);
+
+ for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32CW(b64_pattern + i, b64_pattern + j,
+ b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32CW(b64_random + i, b64_random + j,
+ b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) *
+ (PATTERN_INPUTS_64_SHORT_COUNT)) +
+ RANDOM_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ gettimeofday(&end, NULL);
+
+ elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0;
+ elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0;
+
+ ret = check_results_64(isa_ase_name, group_name, instruction_name,
+ TEST_COUNT_TOTAL, elapsed_time, b64_result,
+ b64_expect);
+
+ return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32d.c b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32d.c
new file mode 100644
index 0000000..e391be8
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32d.c
@@ -0,0 +1,142 @@
+/*
+ * Test program for MIPS64R6 instruction CRC32D
+ *
+ * Copyright (C) 2019 Wave Computing, Inc.
+ * Copyright (C) 2019 Aleksandar Markovic <amarkovic@wavecomp.com>
+ * Copyright (C) 2025 Aleksandar Rakic <aleksandar.rakic@htecgroup.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/wrappers_mips64r6.h"
+#include "../../../../include/test_inputs_64.h"
+#include "../../../../include/test_utils_64.h"
+
+#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT)
+
+int32_t main(void)
+{
+ char *isa_ase_name = "mips64r6";
+ char *group_name = "CRC with reversed polynomial 0xEDB88320";
+ char *instruction_name = "CRC32D";
+ int32_t ret;
+ uint32_t i, j;
+ struct timeval start, end;
+ double elapsed_time;
+
+ uint64_t b64_result[TEST_COUNT_TOTAL];
+ uint64_t b64_expect[TEST_COUNT_TOTAL] = {
+ 0xffffffffdebb20e3ULL, /* 0 */
+ 0x0000000044660075ULL,
+ 0x000000001e20c2aeULL,
+ 0xffffffff84fde238ULL,
+ 0x00000000281d7ce7ULL,
+ 0xffffffffb2c05c71ULL,
+ 0xffffffffd660a024ULL,
+ 0x000000004cbd80b2ULL,
+ 0xffffffff9add2096ULL, /* 8 */
+ 0x0000000000000000ULL,
+ 0x000000005a46c2dbULL,
+ 0xffffffffc09be24dULL,
+ 0x000000006c7b7c92ULL,
+ 0xfffffffff6a65c04ULL,
+ 0xffffffff9206a051ULL,
+ 0x0000000008db80c7ULL,
+ 0x000000005449dd0fULL, /* 16 */
+ 0xffffffffce94fd99ULL,
+ 0xffffffff94d23f42ULL,
+ 0x000000000e0f1fd4ULL,
+ 0xffffffffa2ef810bULL,
+ 0x000000003832a19dULL,
+ 0x000000005c925dc8ULL,
+ 0xffffffffc64f7d5eULL,
+ 0x00000000102fdd7aULL, /* 24 */
+ 0xffffffff8af2fdecULL,
+ 0xffffffffd0b43f37ULL,
+ 0x000000004a691fa1ULL,
+ 0xffffffffe689817eULL,
+ 0x000000007c54a1e8ULL,
+ 0x0000000018f45dbdULL,
+ 0xffffffff82297d2bULL,
+ 0xffffffffa7157447ULL, /* 32 */
+ 0x000000003dc854d1ULL,
+ 0x00000000678e960aULL,
+ 0xfffffffffd53b69cULL,
+ 0x0000000051b32843ULL,
+ 0xffffffffcb6e08d5ULL,
+ 0xffffffffafcef480ULL,
+ 0x000000003513d416ULL,
+ 0xffffffffe3737432ULL, /* 40 */
+ 0x0000000079ae54a4ULL,
+ 0x0000000023e8967fULL,
+ 0xffffffffb935b6e9ULL,
+ 0x0000000015d52836ULL,
+ 0xffffffff8f0808a0ULL,
+ 0xffffffffeba8f4f5ULL,
+ 0x000000007175d463ULL,
+ 0x000000007a6adc3eULL, /* 48 */
+ 0xffffffffe0b7fca8ULL,
+ 0xffffffffbaf13e73ULL,
+ 0x00000000202c1ee5ULL,
+ 0xffffffff8ccc803aULL,
+ 0x000000001611a0acULL,
+ 0x0000000072b15cf9ULL,
+ 0xffffffffe86c7c6fULL,
+ 0x000000003e0cdc4bULL, /* 56 */
+ 0xffffffffa4d1fcddULL,
+ 0xfffffffffe973e06ULL,
+ 0x00000000644a1e90ULL,
+ 0xffffffffc8aa804fULL,
+ 0x000000005277a0d9ULL,
+ 0x0000000036d75c8cULL,
+ 0xffffffffac0a7c1aULL,
+ 0xffffffffed857593ULL, /* 64 */
+ 0xffffffffe0b6f95fULL,
+ 0x00000000253b462cULL,
+ 0xffffffffe15579b9ULL,
+ 0x0000000074897c83ULL,
+ 0x0000000079baf04fULL,
+ 0xffffffffbc374f3cULL,
+ 0x00000000785970a9ULL,
+ 0xffffffffa6bae0a9ULL, /* 72 */
+ 0xffffffffab896c65ULL,
+ 0x000000006e04d316ULL,
+ 0xffffffffaa6aec83ULL,
+ 0x000000005ae171feULL,
+ 0x0000000057d2fd32ULL,
+ 0xffffffff925f4241ULL,
+ 0x0000000056317dd4ULL,
+ };
+
+ gettimeofday(&start, NULL);
+
+ for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32D(b64_pattern + i, b64_pattern + j,
+ b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32D(b64_random + i, b64_random + j,
+ b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) *
+ (PATTERN_INPUTS_64_SHORT_COUNT)) +
+ RANDOM_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ gettimeofday(&end, NULL);
+
+ elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0;
+ elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0;
+
+ ret = check_results_64(isa_ase_name, group_name, instruction_name,
+ TEST_COUNT_TOTAL, elapsed_time, b64_result,
+ b64_expect);
+
+ return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32h.c b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32h.c
new file mode 100644
index 0000000..100f02c
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32h.c
@@ -0,0 +1,142 @@
+/*
+ * Test program for MIPS64R6 instruction CRC32H
+ *
+ * Copyright (C) 2019 Wave Computing, Inc.
+ * Copyright (C) 2019 Aleksandar Markovic <amarkovic@wavecomp.com>
+ * Copyright (C) 2025 Aleksandar Rakic <aleksandar.rakic@htecgroup.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/wrappers_mips64r6.h"
+#include "../../../../include/test_inputs_64.h"
+#include "../../../../include/test_utils_64.h"
+
+#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT)
+
+int32_t main(void)
+{
+ char *isa_ase_name = "mips64r6";
+ char *group_name = "CRC with reversed polynomial 0xEDB88320";
+ char *instruction_name = "CRC32H";
+ int32_t ret;
+ uint32_t i, j;
+ struct timeval start, end;
+ double elapsed_time;
+
+ uint64_t b64_result[TEST_COUNT_TOTAL];
+ uint64_t b64_expect[TEST_COUNT_TOTAL] = {
+ 0x000000000000ffffULL, /* 0 */
+ 0xffffffffbe2612ffULL,
+ 0xffffffffdccda6c0ULL,
+ 0x0000000062eb4bc0ULL,
+ 0x000000004bbbc8eaULL,
+ 0xfffffffff59d25eaULL,
+ 0x0000000022259ac0ULL,
+ 0xffffffff9c0377c0ULL,
+ 0xffffffffbe26ed00ULL, /* 8 */
+ 0x0000000000000000ULL,
+ 0x0000000062ebb43fULL,
+ 0xffffffffdccd593fULL,
+ 0xfffffffff59dda15ULL,
+ 0x000000004bbb3715ULL,
+ 0xffffffff9c03883fULL,
+ 0x000000002225653fULL,
+ 0xffffffffdccdf395ULL, /* 16 */
+ 0x0000000062eb1e95ULL,
+ 0x000000000000aaaaULL,
+ 0xffffffffbe2647aaULL,
+ 0xffffffff9776c480ULL,
+ 0x0000000029502980ULL,
+ 0xfffffffffee896aaULL,
+ 0x0000000040ce7baaULL,
+ 0x0000000062ebe16aULL, /* 24 */
+ 0xffffffffdccd0c6aULL,
+ 0xffffffffbe26b855ULL,
+ 0x0000000000005555ULL,
+ 0x000000002950d67fULL,
+ 0xffffffff97763b7fULL,
+ 0x0000000040ce8455ULL,
+ 0xfffffffffee86955ULL,
+ 0x000000004bbbfbd9ULL, /* 32 */
+ 0xfffffffff59d16d9ULL,
+ 0xffffffff9776a2e6ULL,
+ 0x0000000029504fe6ULL,
+ 0x000000000000ccccULL,
+ 0xffffffffbe2621ccULL,
+ 0x00000000699e9ee6ULL,
+ 0xffffffffd7b873e6ULL,
+ 0xfffffffff59de926ULL, /* 40 */
+ 0x000000004bbb0426ULL,
+ 0x000000002950b019ULL,
+ 0xffffffff97765d19ULL,
+ 0xffffffffbe26de33ULL,
+ 0x0000000000003333ULL,
+ 0xffffffffd7b88c19ULL,
+ 0x00000000699e6119ULL,
+ 0x000000002225eb07ULL, /* 48 */
+ 0xffffffff9c030607ULL,
+ 0xfffffffffee8b238ULL,
+ 0x0000000040ce5f38ULL,
+ 0x00000000699edc12ULL,
+ 0xffffffffd7b83112ULL,
+ 0x0000000000008e38ULL,
+ 0xffffffffbe266338ULL,
+ 0xffffffff9c03f9f8ULL, /* 56 */
+ 0x00000000222514f8ULL,
+ 0x0000000040cea0c7ULL,
+ 0xfffffffffee84dc7ULL,
+ 0xffffffffd7b8ceedULL,
+ 0x00000000699e23edULL,
+ 0xffffffffbe269cc7ULL,
+ 0x00000000000071c7ULL,
+ 0x0000000000002862ULL, /* 64 */
+ 0x0000000026a17af6ULL,
+ 0xffffffffaa919152ULL,
+ 0xffffffffcb865590ULL,
+ 0x0000000026a11f07ULL,
+ 0x0000000000004d93ULL,
+ 0xffffffff8c30a637ULL,
+ 0xffffffffed2762f5ULL,
+ 0xffffffffaa9100ffULL, /* 72 */
+ 0xffffffff8c30526bULL,
+ 0x000000000000b9cfULL,
+ 0x0000000061177d0dULL,
+ 0xffffffffcb8623c3ULL,
+ 0xffffffffed277157ULL,
+ 0x0000000061179af3ULL,
+ 0x0000000000005e31ULL
+ };
+
+ gettimeofday(&start, NULL);
+
+ for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32H(b64_pattern + i, b64_pattern + j,
+ b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32H(b64_random + i, b64_random + j,
+ b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) *
+ (PATTERN_INPUTS_64_SHORT_COUNT)) +
+ RANDOM_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ gettimeofday(&end, NULL);
+
+ elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0;
+ elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0;
+
+ ret = check_results_64(isa_ase_name, group_name, instruction_name,
+ TEST_COUNT_TOTAL, elapsed_time, b64_result,
+ b64_expect);
+
+ return ret;
+}
diff --git a/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32w.c b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32w.c
new file mode 100644
index 0000000..b4f5f4b
--- /dev/null
+++ b/tests/tcg/mips/user/isa/mips64r6/crc/test_mips64r6_crc32w.c
@@ -0,0 +1,142 @@
+/*
+ * Test program for MIPS64R6 instruction CRC32W
+ *
+ * Copyright (C) 2019 Wave Computing, Inc.
+ * Copyright (C) 2019 Aleksandar Markovic <amarkovic@wavecomp.com>
+ * Copyright (C) 2025 Aleksandar Rakic <aleksandar.rakic@htecgroup.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "../../../../include/wrappers_mips64r6.h"
+#include "../../../../include/test_inputs_64.h"
+#include "../../../../include/test_utils_64.h"
+
+#define TEST_COUNT_TOTAL (PATTERN_INPUTS_64_COUNT + RANDOM_INPUTS_64_COUNT)
+
+int32_t main(void)
+{
+ char *isa_ase_name = "mips64r6";
+ char *group_name = "CRC with reversed polynomial 0xEDB88320";
+ char *instruction_name = "CRC32W";
+ int32_t ret;
+ uint32_t i, j;
+ struct timeval start, end;
+ double elapsed_time;
+
+ uint64_t b64_result[TEST_COUNT_TOTAL];
+ uint64_t b64_expect[TEST_COUNT_TOTAL] = {
+ 0x0000000000000000ULL, /* 0 */
+ 0xffffffffdebb20e3ULL,
+ 0x000000004a691fa1ULL,
+ 0xffffffff94d23f42ULL,
+ 0xffffffff8f0808a0ULL,
+ 0x0000000051b32843ULL,
+ 0x0000000065069dceULL,
+ 0xffffffffbbbdbd2dULL,
+ 0xffffffffdebb20e3ULL, /* 8 */
+ 0x0000000000000000ULL,
+ 0xffffffff94d23f42ULL,
+ 0x000000004a691fa1ULL,
+ 0x0000000051b32843ULL,
+ 0xffffffff8f0808a0ULL,
+ 0xffffffffbbbdbd2dULL,
+ 0x0000000065069dceULL,
+ 0x000000004a691fa1ULL, /* 16 */
+ 0xffffffff94d23f42ULL,
+ 0x0000000000000000ULL,
+ 0xffffffffdebb20e3ULL,
+ 0xffffffffc5611701ULL,
+ 0x000000001bda37e2ULL,
+ 0x000000002f6f826fULL,
+ 0xfffffffff1d4a28cULL,
+ 0xffffffff94d23f42ULL, /* 24 */
+ 0x000000004a691fa1ULL,
+ 0xffffffffdebb20e3ULL,
+ 0x0000000000000000ULL,
+ 0x000000001bda37e2ULL,
+ 0xffffffffc5611701ULL,
+ 0xfffffffff1d4a28cULL,
+ 0x000000002f6f826fULL,
+ 0xffffffff8f0808a0ULL, /* 32 */
+ 0x0000000051b32843ULL,
+ 0xffffffffc5611701ULL,
+ 0x000000001bda37e2ULL,
+ 0x0000000000000000ULL,
+ 0xffffffffdebb20e3ULL,
+ 0xffffffffea0e956eULL,
+ 0x0000000034b5b58dULL,
+ 0x0000000051b32843ULL, /* 40 */
+ 0xffffffff8f0808a0ULL,
+ 0x000000001bda37e2ULL,
+ 0xffffffffc5611701ULL,
+ 0xffffffffdebb20e3ULL,
+ 0x0000000000000000ULL,
+ 0x0000000034b5b58dULL,
+ 0xffffffffea0e956eULL,
+ 0x0000000065069dceULL, /* 48 */
+ 0xffffffffbbbdbd2dULL,
+ 0x000000002f6f826fULL,
+ 0xfffffffff1d4a28cULL,
+ 0xffffffffea0e956eULL,
+ 0x0000000034b5b58dULL,
+ 0x0000000000000000ULL,
+ 0xffffffffdebb20e3ULL,
+ 0xffffffffbbbdbd2dULL, /* 56 */
+ 0x0000000065069dceULL,
+ 0xfffffffff1d4a28cULL,
+ 0x000000002f6f826fULL,
+ 0x0000000034b5b58dULL,
+ 0xffffffffea0e956eULL,
+ 0xffffffffdebb20e3ULL,
+ 0x0000000000000000ULL,
+ 0x0000000000000000ULL, /* 64 */
+ 0xffffffff90485967ULL,
+ 0x000000006dfb974aULL,
+ 0x00000000083e4538ULL,
+ 0xffffffff90485967ULL,
+ 0x0000000000000000ULL,
+ 0xfffffffffdb3ce2dULL,
+ 0xffffffff98761c5fULL,
+ 0x000000006dfb974aULL, /* 72 */
+ 0xfffffffffdb3ce2dULL,
+ 0x0000000000000000ULL,
+ 0x0000000065c5d272ULL,
+ 0x00000000083e4538ULL,
+ 0xffffffff98761c5fULL,
+ 0x0000000065c5d272ULL,
+ 0x0000000000000000ULL,
+ };
+
+ gettimeofday(&start, NULL);
+
+ for (i = 0; i < PATTERN_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < PATTERN_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32W(b64_pattern + i, b64_pattern + j,
+ b64_result + (PATTERN_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ for (i = 0; i < RANDOM_INPUTS_64_SHORT_COUNT; i++) {
+ for (j = 0; j < RANDOM_INPUTS_64_SHORT_COUNT; j++) {
+ do_mips64r6_CRC32W(b64_random + i, b64_random + j,
+ b64_result + (((PATTERN_INPUTS_64_SHORT_COUNT) *
+ (PATTERN_INPUTS_64_SHORT_COUNT)) +
+ RANDOM_INPUTS_64_SHORT_COUNT * i + j));
+ }
+ }
+
+ gettimeofday(&end, NULL);
+
+ elapsed_time = (end.tv_sec - start.tv_sec) * 1000.0;
+ elapsed_time += (end.tv_usec - start.tv_usec) / 1000.0;
+
+ ret = check_results_64(isa_ase_name, group_name, instruction_name,
+ TEST_COUNT_TOTAL, elapsed_time, b64_result,
+ b64_expect);
+
+ return ret;
+}
diff --git a/tests/tcg/plugins/mem.c b/tests/tcg/plugins/mem.c
index ca4e888..9649bce 100644
--- a/tests/tcg/plugins/mem.c
+++ b/tests/tcg/plugins/mem.c
@@ -20,6 +20,7 @@
* few things provided by compiler.h.
*/
#include <compiler.h>
+#include <stdbool.h>
#include <bswap.h>
#include <qemu-plugin.h>
diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
index 59c2793..43b0ba8 100644
--- a/tests/unit/test-bdrv-drain.c
+++ b/tests/unit/test-bdrv-drain.c
@@ -193,7 +193,9 @@ static BlockBackend * no_coroutine_fn test_setup(void)
blk_insert_bs(blk, bs, &error_abort);
backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
+ bdrv_graph_wrlock_drained();
bdrv_set_backing_hd(bs, backing, &error_abort);
+ bdrv_graph_wrunlock();
bdrv_unref(backing);
bdrv_unref(bs);
@@ -386,7 +388,9 @@ static void test_nested(void)
backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
backing_s = backing->opaque;
+ bdrv_graph_wrlock_drained();
bdrv_set_backing_hd(bs, backing, &error_abort);
+ bdrv_graph_wrunlock();
for (outer = 0; outer < DRAIN_TYPE_MAX; outer++) {
for (inner = 0; inner < DRAIN_TYPE_MAX; inner++) {
@@ -733,10 +737,12 @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
src_overlay = bdrv_new_open_driver(&bdrv_test, "source-overlay",
BDRV_O_RDWR, &error_abort);
+ bdrv_graph_wrlock_drained();
bdrv_set_backing_hd(src_overlay, src, &error_abort);
bdrv_unref(src);
bdrv_set_backing_hd(src, src_backing, &error_abort);
bdrv_unref(src_backing);
+ bdrv_graph_wrunlock();
blk_src = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
blk_insert_bs(blk_src, src_overlay, &error_abort);
@@ -772,11 +778,9 @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
tjob->bs = src;
job = &tjob->common;
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
block_job_add_bdrv(job, "target", target, 0, BLK_PERM_ALL, &error_abort);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
switch (result) {
case TEST_JOB_SUCCESS:
@@ -955,13 +959,11 @@ static void bdrv_test_top_close(BlockDriverState *bs)
{
BdrvChild *c, *next_c;
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
QLIST_FOREACH_SAFE(c, &bs->children, next, next_c) {
bdrv_unref_child(bs, c);
}
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
}
static int coroutine_fn GRAPH_RDLOCK
@@ -1053,12 +1055,10 @@ static void do_test_delete_by_drain(bool detach_instead_of_delete,
null_bs = bdrv_open("null-co://", NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
&error_abort);
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
bdrv_attach_child(bs, null_bs, "null-child", &child_of_bds,
BDRV_CHILD_DATA, &error_abort);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
/* This child will be the one to pass to requests through to, and
* it will stall until a drain occurs */
@@ -1066,25 +1066,21 @@ static void do_test_delete_by_drain(bool detach_instead_of_delete,
&error_abort);
child_bs->total_sectors = 65536 >> BDRV_SECTOR_BITS;
/* Takes our reference to child_bs */
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
tts->wait_child = bdrv_attach_child(bs, child_bs, "wait-child",
&child_of_bds,
BDRV_CHILD_DATA | BDRV_CHILD_PRIMARY,
&error_abort);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
/* This child is just there to be deleted
* (for detach_instead_of_delete == true) */
null_bs = bdrv_open("null-co://", NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
&error_abort);
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
bdrv_attach_child(bs, null_bs, "null-child", &child_of_bds, BDRV_CHILD_DATA,
&error_abort);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
blk_insert_bs(blk, bs, &error_abort);
@@ -1167,8 +1163,7 @@ static void no_coroutine_fn detach_indirect_bh(void *opaque)
bdrv_dec_in_flight(data->child_b->bs);
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
bdrv_unref_child(data->parent_b, data->child_b);
bdrv_ref(data->c);
@@ -1176,7 +1171,6 @@ static void no_coroutine_fn detach_indirect_bh(void *opaque)
&child_of_bds, BDRV_CHILD_DATA,
&error_abort);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
}
static void coroutine_mixed_fn detach_by_parent_aio_cb(void *opaque, int ret)
@@ -1274,8 +1268,7 @@ static void TSA_NO_TSA test_detach_indirect(bool by_parent_cb)
/* Set child relationships */
bdrv_ref(b);
bdrv_ref(a);
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
child_b = bdrv_attach_child(parent_b, b, "PB-B", &child_of_bds,
BDRV_CHILD_DATA, &error_abort);
child_a = bdrv_attach_child(parent_b, a, "PB-A", &child_of_bds,
@@ -1286,7 +1279,6 @@ static void TSA_NO_TSA test_detach_indirect(bool by_parent_cb)
by_parent_cb ? &child_of_bds : &detach_by_driver_cb_class,
BDRV_CHILD_DATA, &error_abort);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
g_assert_cmpint(parent_a->refcnt, ==, 1);
g_assert_cmpint(parent_b->refcnt, ==, 1);
@@ -1450,8 +1442,10 @@ static void test_drop_backing_job_commit(Job *job)
TestDropBackingBlockJob *s =
container_of(job, TestDropBackingBlockJob, common.job);
+ bdrv_graph_wrlock_drained();
bdrv_set_backing_hd(s->bs, NULL, &error_abort);
bdrv_set_backing_hd(s->detach_also, NULL, &error_abort);
+ bdrv_graph_wrunlock();
*s->did_complete = true;
}
@@ -1544,7 +1538,9 @@ static void test_blockjob_commit_by_drained_end(void)
snprintf(name, sizeof(name), "parent-node-%i", i);
bs_parents[i] = bdrv_new_open_driver(&bdrv_test, name, BDRV_O_RDWR,
&error_abort);
+ bdrv_graph_wrlock_drained();
bdrv_set_backing_hd(bs_parents[i], bs_child, &error_abort);
+ bdrv_graph_wrunlock();
}
job = block_job_create("job", &test_drop_backing_job_driver, NULL,
@@ -1693,14 +1689,13 @@ static void test_drop_intermediate_poll(void)
job_node = bdrv_new_open_driver(&bdrv_test, "job-node", BDRV_O_RDWR,
&error_abort);
+ bdrv_graph_wrlock_drained();
bdrv_set_backing_hd(job_node, chain[1], &error_abort);
/*
* Establish the chain last, so the chain links are the first
* elements in the BDS.parents lists
*/
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
for (i = 0; i < 3; i++) {
if (i) {
/* Takes the reference to chain[i - 1] */
@@ -1709,7 +1704,6 @@ static void test_drop_intermediate_poll(void)
}
}
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
job = block_job_create("job", &test_simple_job_driver, NULL, job_node,
0, BLK_PERM_ALL, 0, 0, NULL, NULL, &error_abort);
@@ -1956,12 +1950,10 @@ static void do_test_replace_child_mid_drain(int old_drain_count,
new_child_bs->total_sectors = 1;
bdrv_ref(old_child_bs);
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
bdrv_attach_child(parent_bs, old_child_bs, "child", &child_of_bds,
BDRV_CHILD_COW, &error_abort);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
parent_s->setup_completed = true;
for (i = 0; i < old_drain_count; i++) {
diff --git a/tests/unit/test-bdrv-graph-mod.c b/tests/unit/test-bdrv-graph-mod.c
index 7b03ebe..567db99 100644
--- a/tests/unit/test-bdrv-graph-mod.c
+++ b/tests/unit/test-bdrv-graph-mod.c
@@ -137,12 +137,10 @@ static void test_update_perm_tree(void)
blk_insert_bs(root, bs, &error_abort);
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
bdrv_attach_child(filter, bs, "child", &child_of_bds,
BDRV_CHILD_DATA, &error_abort);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
ret = bdrv_append(filter, bs, NULL);
g_assert_cmpint(ret, <, 0);
@@ -204,15 +202,13 @@ static void test_should_update_child(void)
blk_insert_bs(root, bs, &error_abort);
+ bdrv_graph_wrlock_drained();
bdrv_set_backing_hd(target, bs, &error_abort);
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
g_assert(target->backing->bs == bs);
bdrv_attach_child(filter, target, "target", &child_of_bds,
BDRV_CHILD_DATA, &error_abort);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
bdrv_append(filter, bs, &error_abort);
bdrv_graph_rdlock_main_loop();
@@ -248,8 +244,7 @@ static void test_parallel_exclusive_write(void)
bdrv_ref(base);
bdrv_ref(fl1);
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
bdrv_attach_child(top, fl1, "backing", &child_of_bds,
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
&error_abort);
@@ -262,7 +257,6 @@ static void test_parallel_exclusive_write(void)
bdrv_replace_node(fl1, fl2, &error_abort);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
bdrv_drained_end(fl2);
bdrv_drained_end(fl1);
@@ -369,8 +363,7 @@ static void test_parallel_perm_update(void)
*/
bdrv_ref(base);
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
bdrv_attach_child(top, ws, "file", &child_of_bds, BDRV_CHILD_DATA,
&error_abort);
c_fl1 = bdrv_attach_child(ws, fl1, "first", &child_of_bds,
@@ -384,7 +377,6 @@ static void test_parallel_perm_update(void)
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
&error_abort);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
/* Select fl1 as first child to be active */
s->selected = c_fl1;
@@ -438,13 +430,11 @@ static void test_append_greedy_filter(void)
BlockDriverState *base = no_perm_node("base");
BlockDriverState *fl = exclusive_writer_node("fl1");
- bdrv_drain_all_begin();
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock_drained();
bdrv_attach_child(top, base, "backing", &child_of_bds,
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
&error_abort);
bdrv_graph_wrunlock();
- bdrv_drain_all_end();
bdrv_append(fl, base, &error_abort);
bdrv_unref(fl);
diff --git a/ui/console-gl.c b/ui/console-gl.c
index 103b954..403fc36 100644
--- a/ui/console-gl.c
+++ b/ui/console-gl.c
@@ -25,6 +25,7 @@
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
+#include "qemu/error-report.h"
#include "ui/console.h"
#include "ui/shader.h"
@@ -96,6 +97,53 @@ void surface_gl_create_texture(QemuGLShader *gls,
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
+bool surface_gl_create_texture_from_fd(DisplaySurface *surface,
+ int fd, GLuint *texture,
+ GLuint *mem_obj)
+{
+ unsigned long size = surface_stride(surface) * surface_height(surface);
+ GLenum err = glGetError();
+ *texture = 0;
+ *mem_obj = 0;
+
+ if (!epoxy_has_gl_extension("GL_EXT_memory_object") ||
+ !epoxy_has_gl_extension("GL_EXT_memory_object_fd")) {
+ error_report("spice: required OpenGL extensions not supported: "
+ "GL_EXT_memory_object and GL_EXT_memory_object_fd");
+ return false;
+ }
+
+#ifdef GL_EXT_memory_object_fd
+ glCreateMemoryObjectsEXT(1, mem_obj);
+ glImportMemoryFdEXT(*mem_obj, size, GL_HANDLE_TYPE_OPAQUE_FD_EXT, fd);
+
+ err = glGetError();
+ if (err != GL_NO_ERROR) {
+ error_report("spice: cannot import memory object from fd");
+ goto cleanup_mem;
+ }
+
+ glGenTextures(1, texture);
+ glBindTexture(GL_TEXTURE_2D, *texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_TILING_EXT, GL_LINEAR_TILING_EXT);
+ glTexStorageMem2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, surface_width(surface),
+ surface_height(surface), *mem_obj, 0);
+ err = glGetError();
+ if (err != GL_NO_ERROR) {
+ error_report("spice: cannot create texture from memory object");
+ goto cleanup_tex_and_mem;
+ }
+ return true;
+
+cleanup_tex_and_mem:
+ glDeleteTextures(1, texture);
+cleanup_mem:
+ glDeleteMemoryObjectsEXT(1, mem_obj);
+
+#endif
+ return false;
+}
+
void surface_gl_update_texture(QemuGLShader *gls,
DisplaySurface *surface,
int x, int y, int w, int h)
@@ -136,6 +184,12 @@ void surface_gl_destroy_texture(QemuGLShader *gls,
}
glDeleteTextures(1, &surface->texture);
surface->texture = 0;
+#ifdef GL_EXT_memory_object_fd
+ if (surface->mem_obj) {
+ glDeleteMemoryObjectsEXT(1, &surface->mem_obj);
+ surface->mem_obj = 0;
+ }
+#endif
}
void surface_gl_setup_viewport(QemuGLShader *gls,
diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c
index 5503a79..e3f2872 100644
--- a/ui/egl-helpers.c
+++ b/ui/egl-helpers.c
@@ -295,6 +295,7 @@ bool egl_dmabuf_export_texture(uint32_t tex_id, int *fd, EGLint *offset,
{
EGLImageKHR image;
EGLuint64KHR modifiers[DMABUF_MAX_PLANES];
+ int i;
image = eglCreateImageKHR(qemu_egl_display, eglGetCurrentContext(),
EGL_GL_TEXTURE_2D_KHR,
@@ -314,6 +315,11 @@ bool egl_dmabuf_export_texture(uint32_t tex_id, int *fd, EGLint *offset,
*modifier = modifiers[0];
}
+ for (i = 0; i < *num_planes; i++) {
+ if (fd[i] < 0) {
+ return false;
+ }
+ }
return true;
}
diff --git a/ui/gtk.c b/ui/gtk.c
index 8c4a94c..e91d093 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -67,6 +67,7 @@
#define VC_TERM_X_MIN 80
#define VC_TERM_Y_MIN 25
#define VC_SCALE_MIN 0.25
+#define VC_SCALE_MAX 4
#define VC_SCALE_STEP 0.25
#ifdef GDK_WINDOWING_X11
@@ -272,15 +273,11 @@ static void gd_update_geometry_hints(VirtualConsole *vc)
if (!vc->gfx.ds) {
return;
}
- if (s->free_scale) {
- geo.min_width = surface_width(vc->gfx.ds) * VC_SCALE_MIN;
- geo.min_height = surface_height(vc->gfx.ds) * VC_SCALE_MIN;
- mask |= GDK_HINT_MIN_SIZE;
- } else {
- geo.min_width = surface_width(vc->gfx.ds) * vc->gfx.scale_x;
- geo.min_height = surface_height(vc->gfx.ds) * vc->gfx.scale_y;
- mask |= GDK_HINT_MIN_SIZE;
- }
+ double scale_x = s->free_scale ? VC_SCALE_MIN : vc->gfx.scale_x;
+ double scale_y = s->free_scale ? VC_SCALE_MIN : vc->gfx.scale_y;
+ geo.min_width = surface_width(vc->gfx.ds) * scale_x;
+ geo.min_height = surface_height(vc->gfx.ds) * scale_y;
+ mask |= GDK_HINT_MIN_SIZE;
geo_widget = vc->gfx.drawing_area;
gtk_widget_set_size_request(geo_widget, geo.min_width, geo.min_height);
@@ -828,8 +825,12 @@ void gd_update_scale(VirtualConsole *vc, int ww, int wh, int fbw, int fbh)
sx = (double)ww / fbw;
sy = (double)wh / fbh;
-
- vc->gfx.scale_x = vc->gfx.scale_y = MIN(sx, sy);
+ if (vc->s->keep_aspect_ratio) {
+ vc->gfx.scale_x = vc->gfx.scale_y = MIN(sx, sy);
+ } else {
+ vc->gfx.scale_x = sx;
+ vc->gfx.scale_y = sy;
+ }
}
}
/**
@@ -1575,8 +1576,8 @@ static void gd_menu_full_screen(GtkMenuItem *item, void *opaque)
}
s->full_screen = FALSE;
if (vc->type == GD_VC_GFX) {
- vc->gfx.scale_x = 1.0;
- vc->gfx.scale_y = 1.0;
+ vc->gfx.scale_x = vc->gfx.preferred_scale;
+ vc->gfx.scale_y = vc->gfx.preferred_scale;
gd_update_windowsize(vc);
}
}
@@ -1632,8 +1633,8 @@ static void gd_menu_zoom_fixed(GtkMenuItem *item, void *opaque)
GtkDisplayState *s = opaque;
VirtualConsole *vc = gd_vc_find_current(s);
- vc->gfx.scale_x = 1.0;
- vc->gfx.scale_y = 1.0;
+ vc->gfx.scale_x = vc->gfx.preferred_scale;
+ vc->gfx.scale_y = vc->gfx.preferred_scale;
gd_update_windowsize(vc);
}
@@ -1647,8 +1648,8 @@ static void gd_menu_zoom_fit(GtkMenuItem *item, void *opaque)
s->free_scale = TRUE;
} else {
s->free_scale = FALSE;
- vc->gfx.scale_x = 1.0;
- vc->gfx.scale_y = 1.0;
+ vc->gfx.scale_x = vc->gfx.preferred_scale;
+ vc->gfx.scale_y = vc->gfx.preferred_scale;
}
gd_update_windowsize(vc);
@@ -2239,6 +2240,11 @@ static void gl_area_realize(GtkGLArea *area, VirtualConsole *vc)
}
#endif
+static bool gd_scale_valid(double scale)
+{
+ return scale >= VC_SCALE_MIN && scale <= VC_SCALE_MAX;
+}
+
static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,
QemuConsole *con, int idx,
GSList *group, GtkWidget *view_menu)
@@ -2248,8 +2254,18 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,
vc->label = qemu_console_get_label(con);
vc->s = s;
- vc->gfx.scale_x = 1.0;
- vc->gfx.scale_y = 1.0;
+ vc->gfx.preferred_scale = 1.0;
+ if (s->opts->u.gtk.has_scale) {
+ if (gd_scale_valid(s->opts->u.gtk.scale)) {
+ vc->gfx.preferred_scale = s->opts->u.gtk.scale;
+ } else {
+ error_report("Invalid scale value %lf given, being ignored",
+ s->opts->u.gtk.scale);
+ s->opts->u.gtk.has_scale = false;
+ }
+ }
+ vc->gfx.scale_x = vc->gfx.preferred_scale;
+ vc->gfx.scale_y = vc->gfx.preferred_scale;
#if defined(CONFIG_OPENGL)
if (display_opengl) {
@@ -2328,6 +2344,10 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,
s->free_scale = true;
}
+ s->keep_aspect_ratio = true;
+ if (s->opts->u.gtk.has_keep_aspect_ratio)
+ s->keep_aspect_ratio = s->opts->u.gtk.keep_aspect_ratio;
+
for (i = 0; i < INPUT_EVENT_SLOTS_MAX; i++) {
struct touch_slot *slot = &touch_slots[i];
slot->tracking_id = -1;
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 0326c63..5992f9d 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -56,6 +56,8 @@ struct SpiceTimer {
QEMUTimer *timer;
};
+#define DEFAULT_MAX_REFRESH_RATE 30
+
static SpiceTimer *timer_add(SpiceTimerFunc func, void *opaque)
{
SpiceTimer *timer;
@@ -489,6 +491,12 @@ static QemuOptsList qemu_spice_opts = {
.name = "streaming-video",
.type = QEMU_OPT_STRING,
},{
+ .name = "video-codec",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "max-refresh-rate",
+ .type = QEMU_OPT_NUMBER,
+ },{
.name = "agent-mouse",
.type = QEMU_OPT_BOOL,
},{
@@ -801,6 +809,13 @@ static void qemu_spice_init(void)
spice_server_set_streaming_video(spice_server, SPICE_STREAM_VIDEO_OFF);
}
+ spice_max_refresh_rate = qemu_opt_get_number(opts, "max-refresh-rate",
+ DEFAULT_MAX_REFRESH_RATE);
+ if (spice_max_refresh_rate <= 0) {
+ error_report("max refresh rate/fps is invalid");
+ exit(1);
+ }
+
spice_server_set_agent_mouse
(spice_server, qemu_opt_get_bool(opts, "agent-mouse", 1));
spice_server_set_playback_compression
@@ -836,9 +851,26 @@ static void qemu_spice_init(void)
#ifdef HAVE_SPICE_GL
if (qemu_opt_get_bool(opts, "gl", 0)) {
if ((port != 0) || (tls_port != 0)) {
+#if SPICE_SERVER_VERSION >= 0x000f03 /* release 0.15.3 */
+ const char *video_codec = NULL;
+ g_autofree char *enc_codec = NULL;
+
+ spice_remote_client = 1;
+
+ video_codec = qemu_opt_get(opts, "video-codec");
+ if (video_codec) {
+ enc_codec = g_strconcat("gstreamer:", video_codec, NULL);
+ }
+ if (spice_server_set_video_codecs(spice_server,
+ enc_codec ?: "gstreamer:h264")) {
+ error_report("invalid video codec");
+ exit(1);
+ }
+#else
error_report("SPICE GL support is local-only for now and "
"incompatible with -spice port/tls-port");
exit(1);
+#endif
}
egl_init(qemu_opt_get(opts, "rendernode"), DISPLAY_GL_MODE_ON, &error_fatal);
spice_opengl = 1;
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 9c39d2c..9ce622c 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -31,6 +31,8 @@
#include "standard-headers/drm/drm_fourcc.h"
bool spice_opengl;
+bool spice_remote_client;
+int spice_max_refresh_rate;
int qemu_spice_rect_is_empty(const QXLRect* r)
{
@@ -843,12 +845,32 @@ static void qemu_spice_gl_block_timer(void *opaque)
warn_report("spice: no gl-draw-done within one second");
}
+static void spice_gl_draw(SimpleSpiceDisplay *ssd,
+ uint32_t x, uint32_t y, uint32_t w, uint32_t h)
+{
+ uint64_t cookie;
+
+ cookie = (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_GL_DRAW_DONE, 0);
+ spice_qxl_gl_draw_async(&ssd->qxl, x, y, w, h, cookie);
+}
+
static void spice_gl_refresh(DisplayChangeListener *dcl)
{
SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
- uint64_t cookie;
- if (!ssd->ds || qemu_console_is_gl_blocked(ssd->dcl.con)) {
+ if (!ssd->ds) {
+ return;
+ }
+
+ if (qemu_console_is_gl_blocked(ssd->dcl.con)) {
+ if (spice_remote_client && ssd->gl_updates && ssd->have_scanout) {
+ glFlush();
+ spice_gl_draw(ssd, 0, 0,
+ surface_width(ssd->ds), surface_height(ssd->ds));
+ ssd->gl_updates = 0;
+ /* E.g, to achieve 60 FPS, update_interval needs to be ~16.66 ms */
+ dcl->update_interval = 1000 / spice_max_refresh_rate;
+ }
return;
}
@@ -856,11 +878,8 @@ static void spice_gl_refresh(DisplayChangeListener *dcl)
if (ssd->gl_updates && ssd->have_surface) {
qemu_spice_gl_block(ssd, true);
glFlush();
- cookie = (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_GL_DRAW_DONE, 0);
- spice_qxl_gl_draw_async(&ssd->qxl, 0, 0,
- surface_width(ssd->ds),
- surface_height(ssd->ds),
- cookie);
+ spice_gl_draw(ssd, 0, 0,
+ surface_width(ssd->ds), surface_height(ssd->ds));
ssd->gl_updates = 0;
}
}
@@ -874,6 +893,81 @@ static void spice_gl_update(DisplayChangeListener *dcl,
ssd->gl_updates++;
}
+static bool spice_gl_replace_fd_texture(SimpleSpiceDisplay *ssd,
+ int *fds, uint64_t *modifier,
+ int *num_planes)
+{
+ uint32_t offsets[DMABUF_MAX_PLANES], strides[DMABUF_MAX_PLANES];
+ GLuint texture;
+ GLuint mem_obj;
+ int fourcc;
+ bool ret;
+
+ if (!spice_remote_client) {
+ return true;
+ }
+
+ if (*modifier == DRM_FORMAT_MOD_LINEAR) {
+ return true;
+ }
+
+ if (*num_planes > 1) {
+ error_report("spice: cannot replace texture with multiple planes");
+ return false;
+ }
+
+ /*
+ * We really want to ensure that the memory layout of the texture
+ * is linear; otherwise, the encoder's output may show corruption.
+ */
+ if (!surface_gl_create_texture_from_fd(ssd->ds, fds[0], &texture,
+ &mem_obj)) {
+ error_report("spice: cannot create new texture from fd");
+ return false;
+ }
+
+ /*
+ * A successful return after glImportMemoryFdEXT() means that
+ * the ownership of fd has been passed to GL. In other words,
+ * the fd we got above should not be used anymore.
+ */
+ ret = egl_dmabuf_export_texture(texture,
+ fds,
+ (EGLint *)offsets,
+ (EGLint *)strides,
+ &fourcc,
+ num_planes,
+ modifier);
+ if (!ret) {
+ glDeleteTextures(1, &texture);
+#ifdef GL_EXT_memory_object_fd
+ glDeleteMemoryObjectsEXT(1, &mem_obj);
+#endif
+
+ /*
+ * Since we couldn't export our newly create texture (or create,
+ * an fd associated with it) we need to backtrack and try to
+ * recreate the fd associated with the original texture.
+ */
+ ret = egl_dmabuf_export_texture(ssd->ds->texture,
+ fds,
+ (EGLint *)offsets,
+ (EGLint *)strides,
+ &fourcc,
+ num_planes,
+ modifier);
+ if (!ret) {
+ surface_gl_destroy_texture(ssd->gls, ssd->ds);
+ warn_report("spice: no texture available to display");
+ }
+ } else {
+ surface_gl_destroy_texture(ssd->gls, ssd->ds);
+ ssd->ds->texture = texture;
+ ssd->ds->mem_obj = mem_obj;
+ }
+ return ret;
+}
+
static void spice_server_gl_scanout(QXLInstance *qxl,
const int *fd,
uint32_t width, uint32_t height,
@@ -898,6 +992,7 @@ static void spice_gl_switch(DisplayChangeListener *dcl,
struct DisplaySurface *new_surface)
{
SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
+ bool ret;
if (ssd->ds) {
surface_gl_destroy_texture(ssd->gls, ssd->ds);
@@ -920,6 +1015,12 @@ static void spice_gl_switch(DisplayChangeListener *dcl,
return;
}
+ ret = spice_gl_replace_fd_texture(ssd, fd, &modifier, &num_planes);
+ if (!ret) {
+ surface_gl_destroy_texture(ssd->gls, ssd->ds);
+ return;
+ }
+
trace_qemu_spice_gl_surface(ssd->qxl.id,
surface_width(ssd->ds),
surface_height(ssd->ds),
@@ -953,6 +1054,20 @@ static void qemu_spice_gl_scanout_disable(DisplayChangeListener *dcl)
SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
trace_qemu_spice_gl_scanout_disable(ssd->qxl.id);
+
+ /*
+ * We need to check for the case of "lost" updates, where a gl_draw
+ * was not submitted because the timer did not get a chance to run.
+ * One case where this happens is when the Guest VM is getting
+ * rebooted. If the console is blocked in this situation, we need
+ * to unblock it. Otherwise, newer updates would not take effect.
+ */
+ if (qemu_console_is_gl_blocked(ssd->dcl.con)) {
+ if (spice_remote_client && ssd->gl_updates && ssd->have_scanout) {
+ ssd->gl_updates = 0;
+ qemu_spice_gl_block(ssd, false);
+ }
+ }
spice_server_gl_scanout(&ssd->qxl, NULL, 0, 0, NULL, NULL, 0, DRM_FORMAT_INVALID,
DRM_FORMAT_MOD_INVALID, false);
qemu_spice_gl_monitor_config(ssd, 0, 0, 0, 0);
@@ -971,7 +1086,7 @@ static void qemu_spice_gl_scanout_texture(DisplayChangeListener *dcl,
{
SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
EGLint offset[DMABUF_MAX_PLANES], stride[DMABUF_MAX_PLANES], fourcc = 0;
- int fd[DMABUF_MAX_PLANES], num_planes;
+ int fd[DMABUF_MAX_PLANES], num_planes, i;
uint64_t modifier;
assert(tex_id);
@@ -983,11 +1098,26 @@ static void qemu_spice_gl_scanout_texture(DisplayChangeListener *dcl,
trace_qemu_spice_gl_scanout_texture(ssd->qxl.id, w, h, fourcc);
- /* note: spice server will close the fd */
- spice_server_gl_scanout(&ssd->qxl, fd, backing_width, backing_height,
- (uint32_t *)offset, (uint32_t *)stride, num_planes,
- fourcc, modifier, y_0_top);
- qemu_spice_gl_monitor_config(ssd, x, y, w, h);
+ if (spice_remote_client && modifier != DRM_FORMAT_MOD_LINEAR) {
+ egl_fb_destroy(&ssd->guest_fb);
+ egl_fb_setup_for_tex(&ssd->guest_fb,
+ backing_width, backing_height,
+ tex_id, false);
+ ssd->backing_y_0_top = y_0_top;
+ ssd->blit_scanout_texture = true;
+ ssd->new_scanout_texture = true;
+
+ for (i = 0; i < num_planes; i++) {
+ close(fd[i]);
+ }
+ } else {
+ /* note: spice server will close the fd */
+ spice_server_gl_scanout(&ssd->qxl, fd, backing_width, backing_height,
+ (uint32_t *)offset, (uint32_t *)stride,
+ num_planes, fourcc, modifier, y_0_top);
+ qemu_spice_gl_monitor_config(ssd, x, y, w, h);
+ }
+
ssd->have_surface = false;
ssd->have_scanout = true;
}
@@ -1053,6 +1183,50 @@ static void qemu_spice_gl_release_dmabuf(DisplayChangeListener *dcl,
egl_dmabuf_release_texture(dmabuf);
}
+static bool spice_gl_blit_scanout_texture(SimpleSpiceDisplay *ssd,
+ egl_fb *scanout_tex_fb)
+{
+ uint32_t offsets[DMABUF_MAX_PLANES], strides[DMABUF_MAX_PLANES];
+ int fds[DMABUF_MAX_PLANES], num_planes, fourcc;
+ uint64_t modifier;
+ bool ret;
+
+ egl_fb_destroy(scanout_tex_fb);
+ egl_fb_setup_for_tex(scanout_tex_fb,
+ surface_width(ssd->ds), surface_height(ssd->ds),
+ ssd->ds->texture, false);
+ egl_fb_blit(scanout_tex_fb, &ssd->guest_fb, false);
+ glFlush();
+
+ if (!ssd->new_scanout_texture) {
+ return true;
+ }
+
+ ret = egl_dmabuf_export_texture(ssd->ds->texture,
+ fds,
+ (EGLint *)offsets,
+ (EGLint *)strides,
+ &fourcc,
+ &num_planes,
+ &modifier);
+ if (!ret) {
+ error_report("spice: failed to get fd for texture");
+ return false;
+ }
+
+ spice_server_gl_scanout(&ssd->qxl, fds,
+ surface_width(ssd->ds),
+ surface_height(ssd->ds),
+ (uint32_t *)offsets, (uint32_t *)strides,
+ num_planes, fourcc, modifier,
+ ssd->backing_y_0_top);
+ qemu_spice_gl_monitor_config(ssd, 0, 0,
+ surface_width(ssd->ds),
+ surface_height(ssd->ds));
+ ssd->new_scanout_texture = false;
+ return true;
+}
+
static void qemu_spice_gl_update(DisplayChangeListener *dcl,
uint32_t x, uint32_t y, uint32_t w, uint32_t h)
{
@@ -1060,7 +1234,7 @@ static void qemu_spice_gl_update(DisplayChangeListener *dcl,
EGLint fourcc = 0;
bool render_cursor = false;
bool y_0_top = false; /* FIXME */
- uint64_t cookie;
+ bool ret;
uint32_t width, height, texture;
if (!ssd->have_scanout) {
@@ -1155,11 +1329,31 @@ static void qemu_spice_gl_update(DisplayChangeListener *dcl,
glFlush();
}
+ if (spice_remote_client && ssd->blit_scanout_texture) {
+ egl_fb scanout_tex_fb;
+
+ ret = spice_gl_blit_scanout_texture(ssd, &scanout_tex_fb);
+ if (!ret) {
+ return;
+ }
+ }
+
trace_qemu_spice_gl_update(ssd->qxl.id, w, h, x, y);
qemu_spice_gl_block(ssd, true);
glFlush();
- cookie = (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_GL_DRAW_DONE, 0);
- spice_qxl_gl_draw_async(&ssd->qxl, x, y, w, h, cookie);
+
+ /*
+ * In the case of remote clients, the submission of gl_draw request is
+ * deferred here, so that it can be submitted later (to spice server)
+ * from spice_gl_refresh() timer callback. This is done to ensure that
+ * Guest updates are submitted at a steady rate (e.g. 60 FPS) instead
+ * of submitting them arbitrarily.
+ */
+ if (spice_remote_client) {
+ ssd->gl_updates++;
+ } else {
+ spice_gl_draw(ssd, x, y, w, h);
+ }
}
static const DisplayChangeListenerOps display_listener_gl_ops = {
diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c
index 25c7b2c..9dfe6ae 100644
--- a/ui/vnc-enc-tight.c
+++ b/ui/vnc-enc-tight.c
@@ -72,8 +72,8 @@ static const struct {
};
-static int tight_send_framebuffer_update(VncState *vs, int x, int y,
- int w, int h);
+static int tight_send_framebuffer_update(VncState *vs, VncWorker *worker,
+ int x, int y, int w, int h);
#ifdef CONFIG_VNC_JPEG
static const struct {
@@ -111,12 +111,12 @@ static const struct {
{ 9, PNG_ALL_FILTERS },
};
-static int send_png_rect(VncState *vs, int x, int y, int w, int h,
- VncPalette *palette);
+static int send_png_rect(VncState *vs, VncWorker *worker,
+ int x, int y, int w, int h, VncPalette *palette);
-static bool tight_can_send_png_rect(VncState *vs, int w, int h)
+static bool tight_can_send_png_rect(VncState *vs, VncTight *tight, int w, int h)
{
- if (vs->tight->type != VNC_ENCODING_TIGHT_PNG) {
+ if (tight->type != VNC_ENCODING_TIGHT_PNG) {
return false;
}
@@ -135,7 +135,7 @@ static bool tight_can_send_png_rect(VncState *vs, int w, int h)
*/
static unsigned int
-tight_detect_smooth_image24(VncState *vs, int w, int h)
+tight_detect_smooth_image24(VncState *vs, VncTight *tight, int w, int h)
{
int off;
int x, y, d, dx;
@@ -144,7 +144,7 @@ tight_detect_smooth_image24(VncState *vs, int w, int h)
int pixels = 0;
int pix, left[3];
unsigned int errors;
- unsigned char *buf = vs->tight->tight.buffer;
+ unsigned char *buf = tight->tight.buffer;
/*
* If client is big-endian, color samples begin from the second
@@ -205,7 +205,8 @@ tight_detect_smooth_image24(VncState *vs, int w, int h)
#define DEFINE_DETECT_FUNCTION(bpp) \
\
static unsigned int \
- tight_detect_smooth_image##bpp(VncState *vs, int w, int h) { \
+ tight_detect_smooth_image##bpp(VncState *vs, VncTight *tight, \
+ int w, int h) { \
bool endian; \
uint##bpp##_t pix; \
int max[3], shift[3]; \
@@ -215,7 +216,7 @@ tight_detect_smooth_image24(VncState *vs, int w, int h)
int pixels = 0; \
int sample, sum, left[3]; \
unsigned int errors; \
- unsigned char *buf = vs->tight->tight.buffer; \
+ unsigned char *buf = tight->tight.buffer; \
\
endian = 0; /* FIXME */ \
\
@@ -293,11 +294,11 @@ DEFINE_DETECT_FUNCTION(16)
DEFINE_DETECT_FUNCTION(32)
static int
-tight_detect_smooth_image(VncState *vs, int w, int h)
+tight_detect_smooth_image(VncState *vs, VncTight *tight, int w, int h)
{
unsigned int errors;
- int compression = vs->tight->compression;
- int quality = vs->tight->quality;
+ int compression = tight->compression;
+ int quality = tight->quality;
if (!vs->vd->lossy) {
return 0;
@@ -309,7 +310,7 @@ tight_detect_smooth_image(VncState *vs, int w, int h)
return 0;
}
- if (vs->tight->quality != (uint8_t)-1) {
+ if (tight->quality != (uint8_t)-1) {
if (w * h < VNC_TIGHT_JPEG_MIN_RECT_SIZE) {
return 0;
}
@@ -320,17 +321,17 @@ tight_detect_smooth_image(VncState *vs, int w, int h)
}
if (vs->client_pf.bytes_per_pixel == 4) {
- if (vs->tight->pixel24) {
- errors = tight_detect_smooth_image24(vs, w, h);
- if (vs->tight->quality != (uint8_t)-1) {
+ if (tight->pixel24) {
+ errors = tight_detect_smooth_image24(vs, tight, w, h);
+ if (tight->quality != (uint8_t)-1) {
return (errors < tight_conf[quality].jpeg_threshold24);
}
return (errors < tight_conf[compression].gradient_threshold24);
} else {
- errors = tight_detect_smooth_image32(vs, w, h);
+ errors = tight_detect_smooth_image32(vs, tight, w, h);
}
} else {
- errors = tight_detect_smooth_image16(vs, w, h);
+ errors = tight_detect_smooth_image16(vs, tight, w, h);
}
if (quality != (uint8_t)-1) {
return (errors < tight_conf[quality].jpeg_threshold);
@@ -344,15 +345,15 @@ tight_detect_smooth_image(VncState *vs, int w, int h)
#define DEFINE_FILL_PALETTE_FUNCTION(bpp) \
\
static int \
- tight_fill_palette##bpp(VncState *vs, int x, int y, \
- int max, size_t count, \
+ tight_fill_palette##bpp(VncState *vs, VncTight *tight, \
+ int x, int y, int max, size_t count, \
uint32_t *bg, uint32_t *fg, \
VncPalette *palette) { \
uint##bpp##_t *data; \
uint##bpp##_t c0, c1, ci; \
int i, n0, n1; \
\
- data = (uint##bpp##_t *)vs->tight->tight.buffer; \
+ data = (uint##bpp##_t *)tight->tight.buffer; \
\
c0 = data[0]; \
i = 1; \
@@ -417,15 +418,15 @@ DEFINE_FILL_PALETTE_FUNCTION(8)
DEFINE_FILL_PALETTE_FUNCTION(16)
DEFINE_FILL_PALETTE_FUNCTION(32)
-static int tight_fill_palette(VncState *vs, int x, int y,
+static int tight_fill_palette(VncState *vs, VncTight *tight, int x, int y,
size_t count, uint32_t *bg, uint32_t *fg,
VncPalette *palette)
{
int max;
- max = count / tight_conf[vs->tight->compression].idx_max_colors_divisor;
+ max = count / tight_conf[tight->compression].idx_max_colors_divisor;
if (max < 2 &&
- count >= tight_conf[vs->tight->compression].mono_min_rect_size) {
+ count >= tight_conf[tight->compression].mono_min_rect_size) {
max = 2;
}
if (max >= 256) {
@@ -434,12 +435,15 @@ static int tight_fill_palette(VncState *vs, int x, int y,
switch (vs->client_pf.bytes_per_pixel) {
case 4:
- return tight_fill_palette32(vs, x, y, max, count, bg, fg, palette);
+ return tight_fill_palette32(vs, tight, x, y, max, count, bg, fg,
+ palette);
case 2:
- return tight_fill_palette16(vs, x, y, max, count, bg, fg, palette);
+ return tight_fill_palette16(vs, tight, x, y, max, count, bg, fg,
+ palette);
default:
max = 2;
- return tight_fill_palette8(vs, x, y, max, count, bg, fg, palette);
+ return tight_fill_palette8(vs, tight, x, y, max, count, bg, fg,
+ palette);
}
return 0;
}
@@ -547,7 +551,8 @@ DEFINE_MONO_ENCODE_FUNCTION(32)
*/
static void
-tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
+tight_filter_gradient24(VncState *vs, VncTight *tight, uint8_t *buf,
+ int w, int h)
{
uint32_t *buf32;
uint32_t pix32;
@@ -558,7 +563,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
int x, y, c;
buf32 = (uint32_t *)buf;
- memset(vs->tight->gradient.buffer, 0, w * 3 * sizeof(int));
+ memset(tight->gradient.buffer, 0, w * 3 * sizeof(int));
if (1 /* FIXME */) {
shift[0] = vs->client_pf.rshift;
@@ -575,7 +580,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
upper[c] = 0;
here[c] = 0;
}
- prev = (int *)vs->tight->gradient.buffer;
+ prev = (int *)tight->gradient.buffer;
for (x = 0; x < w; x++) {
pix32 = *buf32++;
for (c = 0; c < 3; c++) {
@@ -605,8 +610,8 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
#define DEFINE_GRADIENT_FILTER_FUNCTION(bpp) \
\
static void \
- tight_filter_gradient##bpp(VncState *vs, uint##bpp##_t *buf, \
- int w, int h) { \
+ tight_filter_gradient##bpp(VncState *vs, VncTight *tight, \
+ uint##bpp##_t *buf, int w, int h) { \
uint##bpp##_t pix, diff; \
bool endian; \
int *prev; \
@@ -615,7 +620,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
int prediction; \
int x, y, c; \
\
- memset(vs->tight->gradient.buffer, 0, w * 3 * sizeof(int)); \
+ memset(tight->gradient.buffer, 0, w * 3 * sizeof(int)); \
\
endian = 0; /* FIXME */ \
\
@@ -631,7 +636,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
upper[c] = 0; \
here[c] = 0; \
} \
- prev = (int *)vs->tight->gradient.buffer; \
+ prev = (int *)tight->gradient.buffer; \
for (x = 0; x < w; x++) { \
pix = *buf; \
if (endian) { \
@@ -782,10 +787,10 @@ static void extend_solid_area(VncState *vs, int x, int y, int w, int h,
*w_ptr += cx - (*x_ptr + *w_ptr);
}
-static int tight_init_stream(VncState *vs, int stream_id,
+static int tight_init_stream(VncState *vs, VncTight *tight, int stream_id,
int level, int strategy)
{
- z_streamp zstream = &vs->tight->stream[stream_id];
+ z_streamp zstream = &tight->stream[stream_id];
if (zstream->opaque == NULL) {
int err;
@@ -803,15 +808,15 @@ static int tight_init_stream(VncState *vs, int stream_id,
return -1;
}
- vs->tight->levels[stream_id] = level;
+ tight->levels[stream_id] = level;
zstream->opaque = vs;
}
- if (vs->tight->levels[stream_id] != level) {
+ if (tight->levels[stream_id] != level) {
if (deflateParams(zstream, level, strategy) != Z_OK) {
return -1;
}
- vs->tight->levels[stream_id] = level;
+ tight->levels[stream_id] = level;
}
return 0;
}
@@ -836,29 +841,29 @@ static void tight_send_compact_size(VncState *vs, size_t len)
}
}
-static int tight_compress_data(VncState *vs, int stream_id, size_t bytes,
- int level, int strategy)
+static int tight_compress_data(VncState *vs, VncTight *tight, int stream_id,
+ size_t bytes, int level, int strategy)
{
- z_streamp zstream = &vs->tight->stream[stream_id];
+ z_streamp zstream = &tight->stream[stream_id];
int previous_out;
if (bytes < VNC_TIGHT_MIN_TO_COMPRESS) {
- vnc_write(vs, vs->tight->tight.buffer, vs->tight->tight.offset);
+ vnc_write(vs, tight->tight.buffer, tight->tight.offset);
return bytes;
}
- if (tight_init_stream(vs, stream_id, level, strategy)) {
+ if (tight_init_stream(vs, tight, stream_id, level, strategy)) {
return -1;
}
/* reserve memory in output buffer */
- buffer_reserve(&vs->tight->zlib, bytes + 64);
+ buffer_reserve(&tight->zlib, bytes + 64);
/* set pointers */
- zstream->next_in = vs->tight->tight.buffer;
- zstream->avail_in = vs->tight->tight.offset;
- zstream->next_out = vs->tight->zlib.buffer + vs->tight->zlib.offset;
- zstream->avail_out = vs->tight->zlib.capacity - vs->tight->zlib.offset;
+ zstream->next_in = tight->tight.buffer;
+ zstream->avail_in = tight->tight.offset;
+ zstream->next_out = tight->zlib.buffer + tight->zlib.offset;
+ zstream->avail_out = tight->zlib.capacity - tight->zlib.offset;
previous_out = zstream->avail_out;
zstream->data_type = Z_BINARY;
@@ -868,14 +873,14 @@ static int tight_compress_data(VncState *vs, int stream_id, size_t bytes,
return -1;
}
- vs->tight->zlib.offset = vs->tight->zlib.capacity - zstream->avail_out;
+ tight->zlib.offset = tight->zlib.capacity - zstream->avail_out;
/* ...how much data has actually been produced by deflate() */
bytes = previous_out - zstream->avail_out;
tight_send_compact_size(vs, bytes);
- vnc_write(vs, vs->tight->zlib.buffer, bytes);
+ vnc_write(vs, tight->zlib.buffer, bytes);
- buffer_reset(&vs->tight->zlib);
+ buffer_reset(&tight->zlib);
return bytes;
}
@@ -914,67 +919,69 @@ static void tight_pack24(VncState *vs, uint8_t *buf, size_t count, size_t *ret)
}
}
-static int send_full_color_rect(VncState *vs, int x, int y, int w, int h)
+static int send_full_color_rect(VncState *vs, VncWorker *worker,
+ int x, int y, int w, int h)
{
+ VncTight *tight = &worker->tight;
+ int level = tight_conf[tight->compression].raw_zlib_level;
int stream = 0;
ssize_t bytes;
#ifdef CONFIG_PNG
- if (tight_can_send_png_rect(vs, w, h)) {
- return send_png_rect(vs, x, y, w, h, NULL);
+ if (tight_can_send_png_rect(vs, tight, w, h)) {
+ return send_png_rect(vs, worker, x, y, w, h, NULL);
}
#endif
vnc_write_u8(vs, stream << 4); /* no flushing, no filter */
- if (vs->tight->pixel24) {
- tight_pack24(vs, vs->tight->tight.buffer, w * h,
- &vs->tight->tight.offset);
+ if (tight->pixel24) {
+ tight_pack24(vs, tight->tight.buffer, w * h, &tight->tight.offset);
bytes = 3;
} else {
bytes = vs->client_pf.bytes_per_pixel;
}
- bytes = tight_compress_data(vs, stream, w * h * bytes,
- tight_conf[vs->tight->compression].raw_zlib_level,
+ bytes = tight_compress_data(vs, tight, stream, w * h * bytes, level,
Z_DEFAULT_STRATEGY);
return (bytes >= 0);
}
-static int send_solid_rect(VncState *vs)
+static int send_solid_rect(VncState *vs, VncWorker *worker)
{
+ VncTight *tight = &worker->tight;
size_t bytes;
vnc_write_u8(vs, VNC_TIGHT_FILL << 4); /* no flushing, no filter */
- if (vs->tight->pixel24) {
- tight_pack24(vs, vs->tight->tight.buffer, 1, &vs->tight->tight.offset);
+ if (tight->pixel24) {
+ tight_pack24(vs, tight->tight.buffer, 1, &tight->tight.offset);
bytes = 3;
} else {
bytes = vs->client_pf.bytes_per_pixel;
}
- vnc_write(vs, vs->tight->tight.buffer, bytes);
+ vnc_write(vs, tight->tight.buffer, bytes);
return 1;
}
-static int send_mono_rect(VncState *vs, int x, int y,
+static int send_mono_rect(VncState *vs, VncWorker *worker, int x, int y,
int w, int h, uint32_t bg, uint32_t fg)
{
ssize_t bytes;
int stream = 1;
- int level = tight_conf[vs->tight->compression].mono_zlib_level;
+ int level = tight_conf[worker->tight.compression].mono_zlib_level;
#ifdef CONFIG_PNG
- if (tight_can_send_png_rect(vs, w, h)) {
+ if (tight_can_send_png_rect(vs, &worker->tight, w, h)) {
int ret;
int bpp = vs->client_pf.bytes_per_pixel * 8;
VncPalette *palette = palette_new(2, bpp);
palette_put(palette, bg);
palette_put(palette, fg);
- ret = send_png_rect(vs, x, y, w, h, palette);
+ ret = send_png_rect(vs, worker, x, y, w, h, palette);
palette_destroy(palette);
return ret;
}
@@ -992,12 +999,12 @@ static int send_mono_rect(VncState *vs, int x, int y,
uint32_t buf[2] = {bg, fg};
size_t ret = sizeof (buf);
- if (vs->tight->pixel24) {
+ if (worker->tight.pixel24) {
tight_pack24(vs, (unsigned char*)buf, 2, &ret);
}
vnc_write(vs, buf, ret);
- tight_encode_mono_rect32(vs->tight->tight.buffer, w, h, bg, fg);
+ tight_encode_mono_rect32(worker->tight.tight.buffer, w, h, bg, fg);
break;
}
case 2:
@@ -1006,7 +1013,7 @@ static int send_mono_rect(VncState *vs, int x, int y,
uint16_t fg16 = fg;
vnc_write(vs, &bg16, 2);
vnc_write(vs, &fg16, 2);
- tight_encode_mono_rect16(vs->tight->tight.buffer, w, h, bg, fg);
+ tight_encode_mono_rect16(worker->tight.tight.buffer, w, h, bg, fg);
break;
}
default:
@@ -1015,18 +1022,20 @@ static int send_mono_rect(VncState *vs, int x, int y,
uint8_t fg8 = fg;
vnc_write_u8(vs, bg8);
vnc_write_u8(vs, fg8);
- tight_encode_mono_rect8(vs->tight->tight.buffer, w, h, bg, fg);
+ tight_encode_mono_rect8(worker->tight.tight.buffer, w, h, bg, fg);
break;
}
}
- vs->tight->tight.offset = bytes;
+ worker->tight.tight.offset = bytes;
- bytes = tight_compress_data(vs, stream, bytes, level, Z_DEFAULT_STRATEGY);
+ bytes = tight_compress_data(vs, &worker->tight, stream, bytes, level,
+ Z_DEFAULT_STRATEGY);
return (bytes >= 0);
}
struct palette_cb_priv {
VncState *vs;
+ VncTight *tight;
uint8_t *header;
#ifdef CONFIG_PNG
png_colorp png_palette;
@@ -1046,53 +1055,58 @@ static void write_palette(int idx, uint32_t color, void *opaque)
}
}
-static bool send_gradient_rect(VncState *vs, int x, int y, int w, int h)
+static bool send_gradient_rect(VncState *vs, VncWorker *worker,
+ int x, int y, int w, int h)
{
+ VncTight *tight = &worker->tight;
int stream = 3;
- int level = tight_conf[vs->tight->compression].gradient_zlib_level;
+ int level = tight_conf[tight->compression].gradient_zlib_level;
ssize_t bytes;
if (vs->client_pf.bytes_per_pixel == 1) {
- return send_full_color_rect(vs, x, y, w, h);
+ return send_full_color_rect(vs, worker, x, y, w, h);
}
vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
vnc_write_u8(vs, VNC_TIGHT_FILTER_GRADIENT);
- buffer_reserve(&vs->tight->gradient, w * 3 * sizeof(int));
+ buffer_reserve(&tight->gradient, w * 3 * sizeof(int));
- if (vs->tight->pixel24) {
- tight_filter_gradient24(vs, vs->tight->tight.buffer, w, h);
+ if (tight->pixel24) {
+ tight_filter_gradient24(vs, tight, tight->tight.buffer, w, h);
bytes = 3;
} else if (vs->client_pf.bytes_per_pixel == 4) {
- tight_filter_gradient32(vs, (uint32_t *)vs->tight->tight.buffer, w, h);
+ tight_filter_gradient32(vs, tight, (uint32_t *)tight->tight.buffer,
+ w, h);
bytes = 4;
} else {
- tight_filter_gradient16(vs, (uint16_t *)vs->tight->tight.buffer, w, h);
+ tight_filter_gradient16(vs, tight, (uint16_t *)tight->tight.buffer,
+ w, h);
bytes = 2;
}
- buffer_reset(&vs->tight->gradient);
+ buffer_reset(&tight->gradient);
bytes = w * h * bytes;
- vs->tight->tight.offset = bytes;
+ tight->tight.offset = bytes;
- bytes = tight_compress_data(vs, stream, bytes,
+ bytes = tight_compress_data(vs, tight, stream, bytes,
level, Z_FILTERED);
return (bytes >= 0);
}
-static int send_palette_rect(VncState *vs, int x, int y,
+static int send_palette_rect(VncState *vs, VncWorker *worker, int x, int y,
int w, int h, VncPalette *palette)
{
+ VncTight *tight = &worker->tight;
int stream = 2;
- int level = tight_conf[vs->tight->compression].idx_zlib_level;
+ int level = tight_conf[tight->compression].idx_zlib_level;
int colors;
ssize_t bytes;
#ifdef CONFIG_PNG
- if (tight_can_send_png_rect(vs, w, h)) {
- return send_png_rect(vs, x, y, w, h, palette);
+ if (tight_can_send_png_rect(vs, tight, w, h)) {
+ return send_png_rect(vs, worker, x, y, w, h, palette);
}
#endif
@@ -1107,38 +1121,38 @@ static int send_palette_rect(VncState *vs, int x, int y,
{
size_t old_offset, offset, palette_sz = palette_size(palette);
g_autofree uint32_t *header = g_new(uint32_t, palette_sz);
- struct palette_cb_priv priv = { vs, (uint8_t *)header };
+ struct palette_cb_priv priv = { vs, tight, (uint8_t *)header };
old_offset = vs->output.offset;
palette_iter(palette, write_palette, &priv);
vnc_write(vs, header, palette_sz * sizeof(uint32_t));
- if (vs->tight->pixel24) {
+ if (tight->pixel24) {
tight_pack24(vs, vs->output.buffer + old_offset, colors, &offset);
vs->output.offset = old_offset + offset;
}
- tight_encode_indexed_rect32(vs->tight->tight.buffer, w * h, palette);
+ tight_encode_indexed_rect32(tight->tight.buffer, w * h, palette);
break;
}
case 2:
{
size_t palette_sz = palette_size(palette);
g_autofree uint16_t *header = g_new(uint16_t, palette_sz);
- struct palette_cb_priv priv = { vs, (uint8_t *)header };
+ struct palette_cb_priv priv = { vs, tight, (uint8_t *)header };
palette_iter(palette, write_palette, &priv);
vnc_write(vs, header, palette_sz * sizeof(uint16_t));
- tight_encode_indexed_rect16(vs->tight->tight.buffer, w * h, palette);
+ tight_encode_indexed_rect16(tight->tight.buffer, w * h, palette);
break;
}
default:
return -1; /* No palette for 8bits colors */
}
bytes = w * h;
- vs->tight->tight.offset = bytes;
+ tight->tight.offset = bytes;
- bytes = tight_compress_data(vs, stream, bytes,
+ bytes = tight_compress_data(vs, tight, stream, bytes,
level, Z_DEFAULT_STRATEGY);
return (bytes >= 0);
}
@@ -1154,8 +1168,8 @@ static int send_palette_rect(VncState *vs, int x, int y,
/* This is called once per encoding */
static void jpeg_init_destination(j_compress_ptr cinfo)
{
- VncState *vs = cinfo->client_data;
- Buffer *buffer = &vs->tight->jpeg;
+ VncTight *tight = cinfo->client_data;
+ Buffer *buffer = &tight->jpeg;
cinfo->dest->next_output_byte = (JOCTET *)buffer->buffer + buffer->offset;
cinfo->dest->free_in_buffer = (size_t)(buffer->capacity - buffer->offset);
@@ -1164,8 +1178,8 @@ static void jpeg_init_destination(j_compress_ptr cinfo)
/* This is called when we ran out of buffer (shouldn't happen!) */
static boolean jpeg_empty_output_buffer(j_compress_ptr cinfo)
{
- VncState *vs = cinfo->client_data;
- Buffer *buffer = &vs->tight->jpeg;
+ VncTight *tight = cinfo->client_data;
+ Buffer *buffer = &tight->jpeg;
buffer->offset = buffer->capacity;
buffer_reserve(buffer, 2048);
@@ -1176,13 +1190,14 @@ static boolean jpeg_empty_output_buffer(j_compress_ptr cinfo)
/* This is called when we are done processing data */
static void jpeg_term_destination(j_compress_ptr cinfo)
{
- VncState *vs = cinfo->client_data;
- Buffer *buffer = &vs->tight->jpeg;
+ VncTight *tight = cinfo->client_data;
+ Buffer *buffer = &tight->jpeg;
buffer->offset = buffer->capacity - cinfo->dest->free_in_buffer;
}
-static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
+static int send_jpeg_rect(VncState *vs, VncWorker *worker,
+ int x, int y, int w, int h, int quality)
{
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
@@ -1193,15 +1208,15 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
int dy;
if (surface_bytes_per_pixel(vs->vd->ds) == 1) {
- return send_full_color_rect(vs, x, y, w, h);
+ return send_full_color_rect(vs, worker, x, y, w, h);
}
- buffer_reserve(&vs->tight->jpeg, 2048);
+ buffer_reserve(&worker->tight.jpeg, 2048);
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
- cinfo.client_data = vs;
+ cinfo.client_data = &worker->tight;
cinfo.image_width = w;
cinfo.image_height = h;
cinfo.input_components = 3;
@@ -1231,9 +1246,9 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
vnc_write_u8(vs, VNC_TIGHT_JPEG << 4);
- tight_send_compact_size(vs, vs->tight->jpeg.offset);
- vnc_write(vs, vs->tight->jpeg.buffer, vs->tight->jpeg.offset);
- buffer_reset(&vs->tight->jpeg);
+ tight_send_compact_size(vs, worker->tight.jpeg.offset);
+ vnc_write(vs, worker->tight.jpeg.buffer, worker->tight.jpeg.offset);
+ buffer_reset(&worker->tight.jpeg);
return 1;
}
@@ -1249,7 +1264,7 @@ static void write_png_palette(int idx, uint32_t pix, void *opaque)
VncState *vs = priv->vs;
png_colorp color = &priv->png_palette[idx];
- if (vs->tight->pixel24)
+ if (priv->tight->pixel24)
{
color->red = (pix >> vs->client_pf.rshift) & vs->client_pf.rmax;
color->green = (pix >> vs->client_pf.gshift) & vs->client_pf.gmax;
@@ -1274,12 +1289,12 @@ static void write_png_palette(int idx, uint32_t pix, void *opaque)
static void png_write_data(png_structp png_ptr, png_bytep data,
png_size_t length)
{
- VncState *vs = png_get_io_ptr(png_ptr);
+ VncWorker *worker = png_get_io_ptr(png_ptr);
- buffer_reserve(&vs->tight->png, vs->tight->png.offset + length);
- memcpy(vs->tight->png.buffer + vs->tight->png.offset, data, length);
+ buffer_reserve(&worker->tight.png, worker->tight.png.offset + length);
+ memcpy(worker->tight.png.buffer + worker->tight.png.offset, data, length);
- vs->tight->png.offset += length;
+ worker->tight.png.offset += length;
}
static void png_flush_data(png_structp png_ptr)
@@ -1296,16 +1311,16 @@ static void vnc_png_free(png_structp png_ptr, png_voidp ptr)
g_free(ptr);
}
-static int send_png_rect(VncState *vs, int x, int y, int w, int h,
- VncPalette *palette)
+static int send_png_rect(VncState *vs, VncWorker *worker,
+ int x, int y, int w, int h, VncPalette *palette)
{
png_byte color_type;
png_structp png_ptr;
png_infop info_ptr;
png_colorp png_palette = NULL;
pixman_image_t *linebuf;
- int level = tight_png_conf[vs->tight->compression].png_zlib_level;
- int filters = tight_png_conf[vs->tight->compression].png_filters;
+ int level = tight_png_conf[worker->tight.compression].png_zlib_level;
+ int filters = tight_png_conf[worker->tight.compression].png_filters;
uint8_t *buf;
int dy;
@@ -1322,7 +1337,7 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h,
return -1;
}
- png_set_write_fn(png_ptr, (void *) vs, png_write_data, png_flush_data);
+ png_set_write_fn(png_ptr, worker, png_write_data, png_flush_data);
png_set_compression_level(png_ptr, level);
png_set_filter(png_ptr, PNG_FILTER_TYPE_DEFAULT, filters);
@@ -1343,29 +1358,30 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h,
palette_size(palette));
priv.vs = vs;
+ priv.tight = &worker->tight;
priv.png_palette = png_palette;
palette_iter(palette, write_png_palette, &priv);
png_set_PLTE(png_ptr, info_ptr, png_palette, palette_size(palette));
if (vs->client_pf.bytes_per_pixel == 4) {
- tight_encode_indexed_rect32(vs->tight->tight.buffer, w * h,
+ tight_encode_indexed_rect32(worker->tight.tight.buffer, w * h,
palette);
} else {
- tight_encode_indexed_rect16(vs->tight->tight.buffer, w * h,
+ tight_encode_indexed_rect16(worker->tight.tight.buffer, w * h,
palette);
}
}
png_write_info(png_ptr, info_ptr);
- buffer_reserve(&vs->tight->png, 2048);
+ buffer_reserve(&worker->tight.png, 2048);
linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, w);
buf = (uint8_t *)pixman_image_get_data(linebuf);
for (dy = 0; dy < h; dy++)
{
if (color_type == PNG_COLOR_TYPE_PALETTE) {
- memcpy(buf, vs->tight->tight.buffer + (dy * w), w);
+ memcpy(buf, worker->tight.tight.buffer + (dy * w), w);
} else {
qemu_pixman_linebuf_fill(linebuf, vs->vd->server, w, x, y + dy);
}
@@ -1383,46 +1399,47 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h,
vnc_write_u8(vs, VNC_TIGHT_PNG << 4);
- tight_send_compact_size(vs, vs->tight->png.offset);
- vnc_write(vs, vs->tight->png.buffer, vs->tight->png.offset);
- buffer_reset(&vs->tight->png);
+ tight_send_compact_size(vs, worker->tight.png.offset);
+ vnc_write(vs, worker->tight.png.buffer, worker->tight.png.offset);
+ buffer_reset(&worker->tight.png);
return 1;
}
#endif /* CONFIG_PNG */
-static void vnc_tight_start(VncState *vs)
+static void vnc_tight_start(VncState *vs, VncTight *tight)
{
- buffer_reset(&vs->tight->tight);
+ buffer_reset(&tight->tight);
// make the output buffer be the zlib buffer, so we can compress it later
- vs->tight->tmp = vs->output;
- vs->output = vs->tight->tight;
+ tight->tmp = vs->output;
+ vs->output = tight->tight;
}
-static void vnc_tight_stop(VncState *vs)
+static void vnc_tight_stop(VncState *vs, VncTight *tight)
{
// switch back to normal output/zlib buffers
- vs->tight->tight = vs->output;
- vs->output = vs->tight->tmp;
+ tight->tight = vs->output;
+ vs->output = tight->tmp;
}
-static int send_sub_rect_nojpeg(VncState *vs, int x, int y, int w, int h,
+static int send_sub_rect_nojpeg(VncState *vs, VncWorker *worker,
+ int x, int y, int w, int h,
int bg, int fg, int colors, VncPalette *palette)
{
int ret;
if (colors == 0) {
- if (tight_detect_smooth_image(vs, w, h)) {
- ret = send_gradient_rect(vs, x, y, w, h);
+ if (tight_detect_smooth_image(vs, &worker->tight, w, h)) {
+ ret = send_gradient_rect(vs, worker, x, y, w, h);
} else {
- ret = send_full_color_rect(vs, x, y, w, h);
+ ret = send_full_color_rect(vs, worker, x, y, w, h);
}
} else if (colors == 1) {
- ret = send_solid_rect(vs);
+ ret = send_solid_rect(vs, worker);
} else if (colors == 2) {
- ret = send_mono_rect(vs, x, y, w, h, bg, fg);
+ ret = send_mono_rect(vs, worker, x, y, w, h, bg, fg);
} else if (colors <= 256) {
- ret = send_palette_rect(vs, x, y, w, h, palette);
+ ret = send_palette_rect(vs, worker, x, y, w, h, palette);
} else {
ret = 0;
}
@@ -1430,34 +1447,35 @@ static int send_sub_rect_nojpeg(VncState *vs, int x, int y, int w, int h,
}
#ifdef CONFIG_VNC_JPEG
-static int send_sub_rect_jpeg(VncState *vs, int x, int y, int w, int h,
+static int send_sub_rect_jpeg(VncState *vs, VncWorker *worker,
+ int x, int y, int w, int h,
int bg, int fg, int colors,
VncPalette *palette, bool force)
{
int ret;
if (colors == 0) {
- if (force || (tight_jpeg_conf[vs->tight->quality].jpeg_full &&
- tight_detect_smooth_image(vs, w, h))) {
- int quality = tight_conf[vs->tight->quality].jpeg_quality;
+ if (force || (tight_jpeg_conf[worker->tight.quality].jpeg_full &&
+ tight_detect_smooth_image(vs, &worker->tight, w, h))) {
+ int quality = tight_conf[worker->tight.quality].jpeg_quality;
- ret = send_jpeg_rect(vs, x, y, w, h, quality);
+ ret = send_jpeg_rect(vs, worker, x, y, w, h, quality);
} else {
- ret = send_full_color_rect(vs, x, y, w, h);
+ ret = send_full_color_rect(vs, worker, x, y, w, h);
}
} else if (colors == 1) {
- ret = send_solid_rect(vs);
+ ret = send_solid_rect(vs, worker);
} else if (colors == 2) {
- ret = send_mono_rect(vs, x, y, w, h, bg, fg);
+ ret = send_mono_rect(vs, worker, x, y, w, h, bg, fg);
} else if (colors <= 256) {
if (force || (colors > 96 &&
- tight_jpeg_conf[vs->tight->quality].jpeg_idx &&
- tight_detect_smooth_image(vs, w, h))) {
- int quality = tight_conf[vs->tight->quality].jpeg_quality;
+ tight_jpeg_conf[worker->tight.quality].jpeg_idx &&
+ tight_detect_smooth_image(vs, &worker->tight, w, h))) {
+ int quality = tight_conf[worker->tight.quality].jpeg_quality;
- ret = send_jpeg_rect(vs, x, y, w, h, quality);
+ ret = send_jpeg_rect(vs, worker, x, y, w, h, quality);
} else {
- ret = send_palette_rect(vs, x, y, w, h, palette);
+ ret = send_palette_rect(vs, worker, x, y, w, h, palette);
}
} else {
ret = 0;
@@ -1475,8 +1493,10 @@ static void vnc_tight_cleanup(Notifier *n, void *value)
color_count_palette = NULL;
}
-static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
+static int send_sub_rect(VncState *vs, VncWorker *worker,
+ int x, int y, int w, int h)
{
+ VncTight *tight = &worker->tight;
uint32_t bg = 0, fg = 0;
int colors;
int ret = 0;
@@ -1491,57 +1511,59 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
qemu_thread_atexit_add(&vnc_tight_cleanup_notifier);
}
- vnc_framebuffer_update(vs, x, y, w, h, vs->tight->type);
+ vnc_framebuffer_update(vs, x, y, w, h, tight->type);
- vnc_tight_start(vs);
+ vnc_tight_start(vs, tight);
vnc_raw_send_framebuffer_update(vs, x, y, w, h);
- vnc_tight_stop(vs);
+ vnc_tight_stop(vs, tight);
#ifdef CONFIG_VNC_JPEG
- if (!vs->vd->non_adaptive && vs->tight->quality != (uint8_t)-1) {
+ if (!vs->vd->non_adaptive && tight->quality != (uint8_t)-1) {
double freq = vnc_update_freq(vs, x, y, w, h);
- if (freq < tight_jpeg_conf[vs->tight->quality].jpeg_freq_min) {
+ if (freq < tight_jpeg_conf[tight->quality].jpeg_freq_min) {
allow_jpeg = false;
}
- if (freq >= tight_jpeg_conf[vs->tight->quality].jpeg_freq_threshold) {
+ if (freq >= tight_jpeg_conf[tight->quality].jpeg_freq_threshold) {
force_jpeg = true;
- vnc_sent_lossy_rect(vs, x, y, w, h);
+ vnc_sent_lossy_rect(worker, x, y, w, h);
}
}
#endif
- colors = tight_fill_palette(vs, x, y, w * h, &bg, &fg, color_count_palette);
+ colors = tight_fill_palette(vs, tight, x, y, w * h, &bg, &fg,
+ color_count_palette);
#ifdef CONFIG_VNC_JPEG
- if (allow_jpeg && vs->tight->quality != (uint8_t)-1) {
- ret = send_sub_rect_jpeg(vs, x, y, w, h, bg, fg, colors,
+ if (allow_jpeg && tight->quality != (uint8_t)-1) {
+ ret = send_sub_rect_jpeg(vs, worker, x, y, w, h, bg, fg, colors,
color_count_palette, force_jpeg);
} else {
- ret = send_sub_rect_nojpeg(vs, x, y, w, h, bg, fg, colors,
- color_count_palette);
+ ret = send_sub_rect_nojpeg(vs, worker, x, y, w, h, bg, fg,
+ colors, color_count_palette);
}
#else
- ret = send_sub_rect_nojpeg(vs, x, y, w, h, bg, fg, colors,
+ ret = send_sub_rect_nojpeg(vs, worker, x, y, w, h, bg, fg, colors,
color_count_palette);
#endif
return ret;
}
-static int send_sub_rect_solid(VncState *vs, int x, int y, int w, int h)
+static int send_sub_rect_solid(VncState *vs, VncWorker *worker,
+ int x, int y, int w, int h)
{
- vnc_framebuffer_update(vs, x, y, w, h, vs->tight->type);
+ vnc_framebuffer_update(vs, x, y, w, h, worker->tight.type);
- vnc_tight_start(vs);
+ vnc_tight_start(vs, &worker->tight);
vnc_raw_send_framebuffer_update(vs, x, y, w, h);
- vnc_tight_stop(vs);
+ vnc_tight_stop(vs, &worker->tight);
- return send_solid_rect(vs);
+ return send_solid_rect(vs, worker);
}
-static int send_rect_simple(VncState *vs, int x, int y, int w, int h,
- bool split)
+static int send_rect_simple(VncState *vs, VncWorker *worker,
+ int x, int y, int w, int h, bool split)
{
int max_size, max_width;
int max_sub_width, max_sub_height;
@@ -1549,8 +1571,8 @@ static int send_rect_simple(VncState *vs, int x, int y, int w, int h,
int rw, rh;
int n = 0;
- max_size = tight_conf[vs->tight->compression].max_rect_size;
- max_width = tight_conf[vs->tight->compression].max_rect_width;
+ max_size = tight_conf[worker->tight.compression].max_rect_size;
+ max_width = tight_conf[worker->tight.compression].max_rect_width;
if (split && (w > max_width || w * h > max_size)) {
max_sub_width = (w > max_width) ? max_width : w;
@@ -1560,18 +1582,18 @@ static int send_rect_simple(VncState *vs, int x, int y, int w, int h,
for (dx = 0; dx < w; dx += max_width) {
rw = MIN(max_sub_width, w - dx);
rh = MIN(max_sub_height, h - dy);
- n += send_sub_rect(vs, x+dx, y+dy, rw, rh);
+ n += send_sub_rect(vs, worker, x + dx, y + dy, rw, rh);
}
}
} else {
- n += send_sub_rect(vs, x, y, w, h);
+ n += send_sub_rect(vs, worker, x, y, w, h);
}
return n;
}
-static int find_large_solid_color_rect(VncState *vs, int x, int y,
- int w, int h, int max_rows)
+static int find_large_solid_color_rect(VncState *vs, VncWorker *worker,
+ int x, int y, int w, int h, int max_rows)
{
int dx, dy, dw, dh;
int n = 0;
@@ -1583,7 +1605,7 @@ static int find_large_solid_color_rect(VncState *vs, int x, int y,
/* If a rectangle becomes too large, send its upper part now. */
if (dy - y >= max_rows) {
- n += send_rect_simple(vs, x, y, w, max_rows, true);
+ n += send_rect_simple(vs, worker, x, y, w, max_rows, true);
y += max_rows;
h -= max_rows;
}
@@ -1622,26 +1644,28 @@ static int find_large_solid_color_rect(VncState *vs, int x, int y,
/* Send rectangles at top and left to solid-color area. */
if (y_best != y) {
- n += send_rect_simple(vs, x, y, w, y_best-y, true);
+ n += send_rect_simple(vs, worker, x, y, w, y_best - y, true);
}
if (x_best != x) {
- n += tight_send_framebuffer_update(vs, x, y_best,
+ n += tight_send_framebuffer_update(vs, worker, x, y_best,
x_best-x, h_best);
}
/* Send solid-color rectangle. */
- n += send_sub_rect_solid(vs, x_best, y_best, w_best, h_best);
+ n += send_sub_rect_solid(vs, worker,
+ x_best, y_best, w_best, h_best);
/* Send remaining rectangles (at right and bottom). */
if (x_best + w_best != x + w) {
- n += tight_send_framebuffer_update(vs, x_best+w_best,
+ n += tight_send_framebuffer_update(vs, worker, x_best + w_best,
y_best,
w-(x_best-x)-w_best,
h_best);
}
if (y_best + h_best != y + h) {
- n += tight_send_framebuffer_update(vs, x, y_best+h_best,
+ n += tight_send_framebuffer_update(vs, worker,
+ x, y_best + h_best,
w, h-(y_best-y)-h_best);
}
@@ -1649,73 +1673,73 @@ static int find_large_solid_color_rect(VncState *vs, int x, int y,
return n;
}
}
- return n + send_rect_simple(vs, x, y, w, h, true);
+ return n + send_rect_simple(vs, worker, x, y, w, h, true);
}
-static int tight_send_framebuffer_update(VncState *vs, int x, int y,
- int w, int h)
+static int tight_send_framebuffer_update(VncState *vs, VncWorker *worker,
+ int x, int y, int w, int h)
{
int max_rows;
if (vs->client_pf.bytes_per_pixel == 4 && vs->client_pf.rmax == 0xFF &&
vs->client_pf.bmax == 0xFF && vs->client_pf.gmax == 0xFF) {
- vs->tight->pixel24 = true;
+ worker->tight.pixel24 = true;
} else {
- vs->tight->pixel24 = false;
+ worker->tight.pixel24 = false;
}
#ifdef CONFIG_VNC_JPEG
- if (vs->tight->quality != (uint8_t)-1) {
+ if (worker->tight.quality != (uint8_t)-1) {
double freq = vnc_update_freq(vs, x, y, w, h);
- if (freq > tight_jpeg_conf[vs->tight->quality].jpeg_freq_threshold) {
- return send_rect_simple(vs, x, y, w, h, false);
+ if (freq > tight_jpeg_conf[worker->tight.quality].jpeg_freq_threshold) {
+ return send_rect_simple(vs, worker, x, y, w, h, false);
}
}
#endif
if (w * h < VNC_TIGHT_MIN_SPLIT_RECT_SIZE) {
- return send_rect_simple(vs, x, y, w, h, true);
+ return send_rect_simple(vs, worker, x, y, w, h, true);
}
/* Calculate maximum number of rows in one non-solid rectangle. */
- max_rows = tight_conf[vs->tight->compression].max_rect_size;
- max_rows /= MIN(tight_conf[vs->tight->compression].max_rect_width, w);
+ max_rows = tight_conf[worker->tight.compression].max_rect_size;
+ max_rows /= MIN(tight_conf[worker->tight.compression].max_rect_width, w);
- return find_large_solid_color_rect(vs, x, y, w, h, max_rows);
+ return find_large_solid_color_rect(vs, worker, x, y, w, h, max_rows);
}
-int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y,
- int w, int h)
+int vnc_tight_send_framebuffer_update(VncState *vs, VncWorker *worker,
+ int x, int y, int w, int h)
{
- vs->tight->type = VNC_ENCODING_TIGHT;
- return tight_send_framebuffer_update(vs, x, y, w, h);
+ worker->tight.type = VNC_ENCODING_TIGHT;
+ return tight_send_framebuffer_update(vs, worker, x, y, w, h);
}
-int vnc_tight_png_send_framebuffer_update(VncState *vs, int x, int y,
- int w, int h)
+int vnc_tight_png_send_framebuffer_update(VncState *vs, VncWorker *worker,
+ int x, int y, int w, int h)
{
- vs->tight->type = VNC_ENCODING_TIGHT_PNG;
- return tight_send_framebuffer_update(vs, x, y, w, h);
+ worker->tight.type = VNC_ENCODING_TIGHT_PNG;
+ return tight_send_framebuffer_update(vs, worker, x, y, w, h);
}
-void vnc_tight_clear(VncState *vs)
+void vnc_tight_clear(VncWorker *worker)
{
int i;
- for (i = 0; i < ARRAY_SIZE(vs->tight->stream); i++) {
- if (vs->tight->stream[i].opaque) {
- deflateEnd(&vs->tight->stream[i]);
+ for (i = 0; i < ARRAY_SIZE(worker->tight.stream); i++) {
+ if (worker->tight.stream[i].opaque) {
+ deflateEnd(&worker->tight.stream[i]);
}
}
- buffer_free(&vs->tight->tight);
- buffer_free(&vs->tight->zlib);
- buffer_free(&vs->tight->gradient);
+ buffer_free(&worker->tight.tight);
+ buffer_free(&worker->tight.zlib);
+ buffer_free(&worker->tight.gradient);
#ifdef CONFIG_VNC_JPEG
- buffer_free(&vs->tight->jpeg);
+ buffer_free(&worker->tight.jpeg);
#endif
#ifdef CONFIG_PNG
- buffer_free(&vs->tight->png);
+ buffer_free(&worker->tight.png);
#endif
}
diff --git a/ui/vnc-enc-zlib.c b/ui/vnc-enc-zlib.c
index 900ae5b..a6d2871 100644
--- a/ui/vnc-enc-zlib.c
+++ b/ui/vnc-enc-zlib.c
@@ -46,23 +46,23 @@ void vnc_zlib_zfree(void *x, void *addr)
g_free(addr);
}
-static void vnc_zlib_start(VncState *vs)
+static void vnc_zlib_start(VncState *vs, VncWorker *worker)
{
- buffer_reset(&vs->zlib.zlib);
+ buffer_reset(&worker->zlib.zlib);
// make the output buffer be the zlib buffer, so we can compress it later
- vs->zlib.tmp = vs->output;
- vs->output = vs->zlib.zlib;
+ worker->zlib.tmp = vs->output;
+ vs->output = worker->zlib.zlib;
}
-static int vnc_zlib_stop(VncState *vs)
+static int vnc_zlib_stop(VncState *vs, VncWorker *worker)
{
- z_streamp zstream = &vs->zlib.stream;
+ z_streamp zstream = &worker->zlib.stream;
int previous_out;
// switch back to normal output/zlib buffers
- vs->zlib.zlib = vs->output;
- vs->output = vs->zlib.tmp;
+ worker->zlib.zlib = vs->output;
+ vs->output = worker->zlib.tmp;
// compress the zlib buffer
@@ -76,7 +76,7 @@ static int vnc_zlib_stop(VncState *vs)
zstream->zalloc = vnc_zlib_zalloc;
zstream->zfree = vnc_zlib_zfree;
- err = deflateInit2(zstream, vs->tight->compression, Z_DEFLATED,
+ err = deflateInit2(zstream, worker->tight.compression, Z_DEFLATED,
MAX_WBITS,
MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
@@ -85,24 +85,24 @@ static int vnc_zlib_stop(VncState *vs)
return -1;
}
- vs->zlib.level = vs->tight->compression;
+ worker->zlib.level = worker->tight.compression;
zstream->opaque = vs;
}
- if (vs->tight->compression != vs->zlib.level) {
- if (deflateParams(zstream, vs->tight->compression,
+ if (worker->tight.compression != worker->zlib.level) {
+ if (deflateParams(zstream, worker->tight.compression,
Z_DEFAULT_STRATEGY) != Z_OK) {
return -1;
}
- vs->zlib.level = vs->tight->compression;
+ worker->zlib.level = worker->tight.compression;
}
// reserve memory in output buffer
- buffer_reserve(&vs->output, vs->zlib.zlib.offset + 64);
+ buffer_reserve(&vs->output, worker->zlib.zlib.offset + 64);
// set pointers
- zstream->next_in = vs->zlib.zlib.buffer;
- zstream->avail_in = vs->zlib.zlib.offset;
+ zstream->next_in = worker->zlib.zlib.buffer;
+ zstream->avail_in = worker->zlib.zlib.offset;
zstream->next_out = vs->output.buffer + vs->output.offset;
zstream->avail_out = vs->output.capacity - vs->output.offset;
previous_out = zstream->avail_out;
@@ -118,7 +118,8 @@ static int vnc_zlib_stop(VncState *vs)
return previous_out - zstream->avail_out;
}
-int vnc_zlib_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
+int vnc_zlib_send_framebuffer_update(VncState *vs, VncWorker *worker,
+ int x, int y, int w, int h)
{
int old_offset, new_offset, bytes_written;
@@ -129,9 +130,9 @@ int vnc_zlib_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
vnc_write_s32(vs, 0);
// compress the stream
- vnc_zlib_start(vs);
+ vnc_zlib_start(vs, worker);
vnc_raw_send_framebuffer_update(vs, x, y, w, h);
- bytes_written = vnc_zlib_stop(vs);
+ bytes_written = vnc_zlib_stop(vs, worker);
if (bytes_written == -1)
return 0;
@@ -145,10 +146,10 @@ int vnc_zlib_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
return 1;
}
-void vnc_zlib_clear(VncState *vs)
+void vnc_zlib_clear(VncWorker *worker)
{
- if (vs->zlib.stream.opaque) {
- deflateEnd(&vs->zlib.stream);
+ if (worker->zlib.stream.opaque) {
+ deflateEnd(&worker->zlib.stream);
}
- buffer_free(&vs->zlib.zlib);
+ buffer_free(&worker->zlib.zlib);
}
diff --git a/ui/vnc-enc-zrle.c b/ui/vnc-enc-zrle.c
index 97ec6c7..7679014 100644
--- a/ui/vnc-enc-zrle.c
+++ b/ui/vnc-enc-zrle.c
@@ -35,45 +35,45 @@ static const int bits_per_packed_pixel[] = {
};
-static void vnc_zrle_start(VncState *vs)
+static void vnc_zrle_start(VncState *vs, VncZrle *zrle)
{
- buffer_reset(&vs->zrle->zrle);
+ buffer_reset(&zrle->zrle);
/* make the output buffer be the zlib buffer, so we can compress it later */
- vs->zrle->tmp = vs->output;
- vs->output = vs->zrle->zrle;
+ zrle->tmp = vs->output;
+ vs->output = zrle->zrle;
}
-static void vnc_zrle_stop(VncState *vs)
+static void vnc_zrle_stop(VncState *vs, VncZrle *zrle)
{
/* switch back to normal output/zlib buffers */
- vs->zrle->zrle = vs->output;
- vs->output = vs->zrle->tmp;
+ zrle->zrle = vs->output;
+ vs->output = zrle->tmp;
}
-static void *zrle_convert_fb(VncState *vs, int x, int y, int w, int h,
- int bpp)
+static void *zrle_convert_fb(VncState *vs, VncZrle *zrle,
+ int x, int y, int w, int h, int bpp)
{
Buffer tmp;
- buffer_reset(&vs->zrle->fb);
- buffer_reserve(&vs->zrle->fb, w * h * bpp + bpp);
+ buffer_reset(&zrle->fb);
+ buffer_reserve(&zrle->fb, w * h * bpp + bpp);
tmp = vs->output;
- vs->output = vs->zrle->fb;
+ vs->output = zrle->fb;
vnc_raw_send_framebuffer_update(vs, x, y, w, h);
- vs->zrle->fb = vs->output;
+ zrle->fb = vs->output;
vs->output = tmp;
- return vs->zrle->fb.buffer;
+ return zrle->fb.buffer;
}
-static int zrle_compress_data(VncState *vs, int level)
+static int zrle_compress_data(VncState *vs, VncZrle *zrle, int level)
{
- z_streamp zstream = &vs->zrle->stream;
+ z_streamp zstream = &zrle->stream;
- buffer_reset(&vs->zrle->zlib);
+ buffer_reset(&zrle->zlib);
if (zstream->opaque != vs) {
int err;
@@ -93,13 +93,13 @@ static int zrle_compress_data(VncState *vs, int level)
}
/* reserve memory in output buffer */
- buffer_reserve(&vs->zrle->zlib, vs->zrle->zrle.offset + 64);
+ buffer_reserve(&zrle->zlib, zrle->zrle.offset + 64);
/* set pointers */
- zstream->next_in = vs->zrle->zrle.buffer;
- zstream->avail_in = vs->zrle->zrle.offset;
- zstream->next_out = vs->zrle->zlib.buffer;
- zstream->avail_out = vs->zrle->zlib.capacity;
+ zstream->next_in = zrle->zrle.buffer;
+ zstream->avail_in = zrle->zrle.offset;
+ zstream->next_out = zrle->zlib.buffer;
+ zstream->avail_out = zrle->zlib.capacity;
zstream->data_type = Z_BINARY;
/* start encoding */
@@ -108,8 +108,8 @@ static int zrle_compress_data(VncState *vs, int level)
return -1;
}
- vs->zrle->zlib.offset = vs->zrle->zlib.capacity - zstream->avail_out;
- return vs->zrle->zlib.offset;
+ zrle->zlib.offset = zrle->zlib.capacity - zstream->avail_out;
+ return zrle->zlib.offset;
}
/* Try to work out whether to use RLE and/or a palette. We do this by
@@ -252,21 +252,21 @@ static void zrle_write_u8(VncState *vs, uint8_t value)
#undef ZRLE_COMPACT_PIXEL
#undef ZRLE_BPP
-static int zrle_send_framebuffer_update(VncState *vs, int x, int y,
- int w, int h)
+static int zrle_send_framebuffer_update(VncState *vs, VncWorker *worker,
+ int x, int y, int w, int h)
{
bool be = vs->client_endian == G_BIG_ENDIAN;
size_t bytes;
int zywrle_level;
- if (vs->zrle->type == VNC_ENCODING_ZYWRLE) {
- if (!vs->vd->lossy || vs->tight->quality == (uint8_t)-1
- || vs->tight->quality == 9) {
+ if (worker->zrle.type == VNC_ENCODING_ZYWRLE) {
+ if (!vs->vd->lossy || worker->tight.quality == (uint8_t)-1
+ || worker->tight.quality == 9) {
zywrle_level = 0;
- vs->zrle->type = VNC_ENCODING_ZRLE;
- } else if (vs->tight->quality < 3) {
+ worker->zrle.type = VNC_ENCODING_ZRLE;
+ } else if (worker->tight.quality < 3) {
zywrle_level = 3;
- } else if (vs->tight->quality < 6) {
+ } else if (worker->tight.quality < 6) {
zywrle_level = 2;
} else {
zywrle_level = 1;
@@ -275,25 +275,25 @@ static int zrle_send_framebuffer_update(VncState *vs, int x, int y,
zywrle_level = 0;
}
- vnc_zrle_start(vs);
+ vnc_zrle_start(vs, &worker->zrle);
switch (vs->client_pf.bytes_per_pixel) {
case 1:
- zrle_encode_8ne(vs, x, y, w, h, zywrle_level);
+ zrle_encode_8ne(vs, &worker->zrle, x, y, w, h, zywrle_level);
break;
case 2:
if (vs->client_pf.gmax > 0x1F) {
if (be) {
- zrle_encode_16be(vs, x, y, w, h, zywrle_level);
+ zrle_encode_16be(vs, &worker->zrle, x, y, w, h, zywrle_level);
} else {
- zrle_encode_16le(vs, x, y, w, h, zywrle_level);
+ zrle_encode_16le(vs, &worker->zrle, x, y, w, h, zywrle_level);
}
} else {
if (be) {
- zrle_encode_15be(vs, x, y, w, h, zywrle_level);
+ zrle_encode_15be(vs, &worker->zrle, x, y, w, h, zywrle_level);
} else {
- zrle_encode_15le(vs, x, y, w, h, zywrle_level);
+ zrle_encode_15le(vs, &worker->zrle, x, y, w, h, zywrle_level);
}
}
break;
@@ -314,53 +314,55 @@ static int zrle_send_framebuffer_update(VncState *vs, int x, int y,
if ((fits_in_ls3bytes && !be) || (fits_in_ms3bytes && be)) {
if (be) {
- zrle_encode_24abe(vs, x, y, w, h, zywrle_level);
+ zrle_encode_24abe(vs, &worker->zrle, x, y, w, h, zywrle_level);
} else {
- zrle_encode_24ale(vs, x, y, w, h, zywrle_level);
+ zrle_encode_24ale(vs, &worker->zrle, x, y, w, h, zywrle_level);
}
} else if ((fits_in_ls3bytes && be) || (fits_in_ms3bytes && !be)) {
if (be) {
- zrle_encode_24bbe(vs, x, y, w, h, zywrle_level);
+ zrle_encode_24bbe(vs, &worker->zrle, x, y, w, h, zywrle_level);
} else {
- zrle_encode_24ble(vs, x, y, w, h, zywrle_level);
+ zrle_encode_24ble(vs, &worker->zrle, x, y, w, h, zywrle_level);
}
} else {
if (be) {
- zrle_encode_32be(vs, x, y, w, h, zywrle_level);
+ zrle_encode_32be(vs, &worker->zrle, x, y, w, h, zywrle_level);
} else {
- zrle_encode_32le(vs, x, y, w, h, zywrle_level);
+ zrle_encode_32le(vs, &worker->zrle, x, y, w, h, zywrle_level);
}
}
}
break;
}
- vnc_zrle_stop(vs);
- bytes = zrle_compress_data(vs, Z_DEFAULT_COMPRESSION);
- vnc_framebuffer_update(vs, x, y, w, h, vs->zrle->type);
+ vnc_zrle_stop(vs, &worker->zrle);
+ bytes = zrle_compress_data(vs, &worker->zrle, Z_DEFAULT_COMPRESSION);
+ vnc_framebuffer_update(vs, x, y, w, h, worker->zrle.type);
vnc_write_u32(vs, bytes);
- vnc_write(vs, vs->zrle->zlib.buffer, vs->zrle->zlib.offset);
+ vnc_write(vs, worker->zrle.zlib.buffer, worker->zrle.zlib.offset);
return 1;
}
-int vnc_zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
+int vnc_zrle_send_framebuffer_update(VncState *vs, VncWorker *worker,
+ int x, int y, int w, int h)
{
- vs->zrle->type = VNC_ENCODING_ZRLE;
- return zrle_send_framebuffer_update(vs, x, y, w, h);
+ worker->zrle.type = VNC_ENCODING_ZRLE;
+ return zrle_send_framebuffer_update(vs, worker, x, y, w, h);
}
-int vnc_zywrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
+int vnc_zywrle_send_framebuffer_update(VncState *vs, VncWorker *worker,
+ int x, int y, int w, int h)
{
- vs->zrle->type = VNC_ENCODING_ZYWRLE;
- return zrle_send_framebuffer_update(vs, x, y, w, h);
+ worker->zrle.type = VNC_ENCODING_ZYWRLE;
+ return zrle_send_framebuffer_update(vs, worker, x, y, w, h);
}
-void vnc_zrle_clear(VncState *vs)
+void vnc_zrle_clear(VncWorker *worker)
{
- if (vs->zrle->stream.opaque) {
- deflateEnd(&vs->zrle->stream);
+ if (worker->zrle.stream.opaque) {
+ deflateEnd(&worker->zrle.stream);
}
- buffer_free(&vs->zrle->zrle);
- buffer_free(&vs->zrle->fb);
- buffer_free(&vs->zrle->zlib);
+ buffer_free(&worker->zrle.zrle);
+ buffer_free(&worker->zrle.fb);
+ buffer_free(&worker->zrle.zlib);
}
diff --git a/ui/vnc-enc-zrle.c.inc b/ui/vnc-enc-zrle.c.inc
index 2ef7501..68d28f5 100644
--- a/ui/vnc-enc-zrle.c.inc
+++ b/ui/vnc-enc-zrle.c.inc
@@ -62,16 +62,16 @@
#define ZRLE_ENCODE_TILE ZRLE_CONCAT2(zrle_encode_tile, ZRLE_ENCODE_SUFFIX)
#define ZRLE_WRITE_PALETTE ZRLE_CONCAT2(zrle_write_palette,ZRLE_ENCODE_SUFFIX)
-static void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h,
- int zywrle_level);
+static void ZRLE_ENCODE_TILE(VncState *vs, VncZrle *zrle, ZRLE_PIXEL *data,
+ int w, int h, int zywrle_level);
#if ZRLE_BPP != 8
#include "vnc-enc-zywrle-template.c"
#endif
-static void ZRLE_ENCODE(VncState *vs, int x, int y, int w, int h,
- int zywrle_level)
+static void ZRLE_ENCODE(VncState *vs, VncZrle *zrle,
+ int x, int y, int w, int h, int zywrle_level)
{
int ty;
@@ -87,16 +87,16 @@ static void ZRLE_ENCODE(VncState *vs, int x, int y, int w, int h,
tw = MIN(VNC_ZRLE_TILE_WIDTH, x + w - tx);
- buf = zrle_convert_fb(vs, tx, ty, tw, th, ZRLE_BPP);
- ZRLE_ENCODE_TILE(vs, buf, tw, th, zywrle_level);
+ buf = zrle_convert_fb(vs, zrle, tx, ty, tw, th, ZRLE_BPP);
+ ZRLE_ENCODE_TILE(vs, zrle, buf, tw, th, zywrle_level);
}
}
}
-static void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h,
- int zywrle_level)
+static void ZRLE_ENCODE_TILE(VncState *vs, VncZrle *zrle, ZRLE_PIXEL *data,
+ int w, int h, int zywrle_level)
{
- VncPalette *palette = &vs->zrle->palette;
+ VncPalette *palette = &zrle->palette;
int runs = 0;
int single_pixels = 0;
@@ -236,7 +236,7 @@ static void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h,
#if ZRLE_BPP != 8
if (zywrle_level > 0 && !(zywrle_level & 0x80)) {
ZYWRLE_ANALYZE(data, data, w, h, w, zywrle_level, vs->zywrle.buf);
- ZRLE_ENCODE_TILE(vs, data, w, h, zywrle_level | 0x80);
+ ZRLE_ENCODE_TILE(vs, zrle, data, w, h, zywrle_level | 0x80);
}
else
#endif
diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c
index d3486af..bed3395 100644
--- a/ui/vnc-jobs.c
+++ b/ui/vnc-jobs.c
@@ -185,14 +185,10 @@ static void vnc_async_encoding_start(VncState *orig, VncState *local)
local->vnc_encoding = orig->vnc_encoding;
local->features = orig->features;
local->vd = orig->vd;
- local->lossy_rect = orig->lossy_rect;
local->write_pixels = orig->write_pixels;
local->client_pf = orig->client_pf;
local->client_endian = orig->client_endian;
- local->tight = orig->tight;
- local->zlib = orig->zlib;
local->hextile = orig->hextile;
- local->zrle = orig->zrle;
local->client_width = orig->client_width;
local->client_height = orig->client_height;
}
@@ -200,11 +196,7 @@ static void vnc_async_encoding_start(VncState *orig, VncState *local)
static void vnc_async_encoding_end(VncState *orig, VncState *local)
{
buffer_free(&local->output);
- orig->tight = local->tight;
- orig->zlib = local->zlib;
orig->hextile = local->hextile;
- orig->zrle = local->zrle;
- orig->lossy_rect = local->lossy_rect;
}
static bool vnc_worker_clamp_rect(VncState *vs, VncJob *job, VncRect *rect)
@@ -237,6 +229,7 @@ static bool vnc_worker_clamp_rect(VncState *vs, VncJob *job, VncRect *rect)
static int vnc_worker_thread_loop(VncJobQueue *queue)
{
+ VncConnection *vc;
VncJob *job;
VncRectEntry *entry, *tmp;
VncState vs = {};
@@ -256,6 +249,7 @@ static int vnc_worker_thread_loop(VncJobQueue *queue)
}
assert(job->vs->magic == VNC_MAGIC);
+ vc = container_of(job->vs, VncConnection, vs);
vnc_lock_output(job->vs);
if (job->vs->ioc == NULL || job->vs->abort == true) {
@@ -295,7 +289,8 @@ static int vnc_worker_thread_loop(VncJobQueue *queue)
}
if (vnc_worker_clamp_rect(&vs, job, &entry->rect)) {
- n = vnc_send_framebuffer_update(&vs, entry->rect.x, entry->rect.y,
+ n = vnc_send_framebuffer_update(&vs, &vc->worker,
+ entry->rect.x, entry->rect.y,
entry->rect.w, entry->rect.h);
if (n >= 0) {
diff --git a/ui/vnc.c b/ui/vnc.c
index e9c30aa..1df3583 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -946,29 +946,30 @@ int vnc_raw_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
return 1;
}
-int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
+int vnc_send_framebuffer_update(VncState *vs, VncWorker *worker,
+ int x, int y, int w, int h)
{
int n = 0;
switch(vs->vnc_encoding) {
case VNC_ENCODING_ZLIB:
- n = vnc_zlib_send_framebuffer_update(vs, x, y, w, h);
+ n = vnc_zlib_send_framebuffer_update(vs, worker, x, y, w, h);
break;
case VNC_ENCODING_HEXTILE:
vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_HEXTILE);
n = vnc_hextile_send_framebuffer_update(vs, x, y, w, h);
break;
case VNC_ENCODING_TIGHT:
- n = vnc_tight_send_framebuffer_update(vs, x, y, w, h);
+ n = vnc_tight_send_framebuffer_update(vs, worker, x, y, w, h);
break;
case VNC_ENCODING_TIGHT_PNG:
- n = vnc_tight_png_send_framebuffer_update(vs, x, y, w, h);
+ n = vnc_tight_png_send_framebuffer_update(vs, worker, x, y, w, h);
break;
case VNC_ENCODING_ZRLE:
- n = vnc_zrle_send_framebuffer_update(vs, x, y, w, h);
+ n = vnc_zrle_send_framebuffer_update(vs, worker, x, y, w, h);
break;
case VNC_ENCODING_ZYWRLE:
- n = vnc_zywrle_send_framebuffer_update(vs, x, y, w, h);
+ n = vnc_zywrle_send_framebuffer_update(vs, worker, x, y, w, h);
break;
default:
vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW);
@@ -1306,7 +1307,7 @@ static void vnc_disconnect_start(VncState *vs)
void vnc_disconnect_finish(VncState *vs)
{
- int i;
+ VncConnection *vc = container_of(vs, VncConnection, vs);
trace_vnc_client_disconnect_finish(vs, vs->ioc);
@@ -1320,9 +1321,9 @@ void vnc_disconnect_finish(VncState *vs)
qapi_free_VncClientInfo(vs->info);
- vnc_zlib_clear(vs);
- vnc_tight_clear(vs);
- vnc_zrle_clear(vs);
+ vnc_zlib_clear(&vc->worker);
+ vnc_tight_clear(&vc->worker);
+ vnc_zrle_clear(&vc->worker);
#ifdef CONFIG_VNC_SASL
vnc_sasl_client_cleanup(vs);
@@ -1350,19 +1351,12 @@ void vnc_disconnect_finish(VncState *vs)
}
buffer_free(&vs->jobs_buffer);
- for (i = 0; i < VNC_STAT_ROWS; ++i) {
- g_free(vs->lossy_rect[i]);
- }
- g_free(vs->lossy_rect);
-
object_unref(OBJECT(vs->ioc));
vs->ioc = NULL;
object_unref(OBJECT(vs->sioc));
vs->sioc = NULL;
vs->magic = 0;
- g_free(vs->zrle);
- g_free(vs->tight);
- g_free(vs);
+ g_free(vc);
}
size_t vnc_client_io_error(VncState *vs, ssize_t ret, Error *err)
@@ -2126,13 +2120,14 @@ static void send_xvp_message(VncState *vs, int code)
static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
{
+ VncConnection *vc = container_of(vs, VncConnection, vs);
int i;
unsigned int enc = 0;
vs->features = 0;
vs->vnc_encoding = 0;
- vs->tight->compression = 9;
- vs->tight->quality = -1; /* Lossless by default */
+ vc->worker.tight.compression = 9;
+ vc->worker.tight.quality = -1; /* Lossless by default */
vs->absolute = -1;
/*
@@ -2220,11 +2215,11 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
vnc_server_cut_text_caps(vs);
break;
case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9:
- vs->tight->compression = (enc & 0x0F);
+ vc->worker.tight.compression = (enc & 0x0F);
break;
case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9:
if (vs->vd->lossy) {
- vs->tight->quality = (enc & 0x0F);
+ vc->worker.tight.quality = (enc & 0x0F);
}
break;
default:
@@ -2953,7 +2948,7 @@ static VncRectStat *vnc_stat_rect(VncDisplay *vd, int x, int y)
return &vs->stats[y / VNC_STAT_RECT][x / VNC_STAT_RECT];
}
-void vnc_sent_lossy_rect(VncState *vs, int x, int y, int w, int h)
+void vnc_sent_lossy_rect(VncWorker *worker, int x, int y, int w, int h)
{
int i, j;
@@ -2964,7 +2959,7 @@ void vnc_sent_lossy_rect(VncState *vs, int x, int y, int w, int h)
for (j = y; j <= h; j++) {
for (i = x; i <= w; i++) {
- vs->lossy_rect[j][i] = 1;
+ worker->lossy_rect[j][i] = 1;
}
}
}
@@ -2980,6 +2975,7 @@ static int vnc_refresh_lossy_rect(VncDisplay *vd, int x, int y)
x = QEMU_ALIGN_DOWN(x, VNC_STAT_RECT);
QTAILQ_FOREACH(vs, &vd->clients, next) {
+ VncConnection *vc = container_of(vs, VncConnection, vs);
int j;
/* kernel send buffers are full -> refresh later */
@@ -2987,11 +2983,11 @@ static int vnc_refresh_lossy_rect(VncDisplay *vd, int x, int y)
continue;
}
- if (!vs->lossy_rect[sty][stx]) {
+ if (!vc->worker.lossy_rect[sty][stx]) {
continue;
}
- vs->lossy_rect[sty][stx] = 0;
+ vc->worker.lossy_rect[sty][stx] = 0;
for (j = 0; j < VNC_STAT_RECT; ++j) {
bitmap_set(vs->dirty[y + j],
x / VNC_DIRTY_PIXELS_PER_BIT,
@@ -3241,13 +3237,11 @@ static void vnc_refresh(DisplayChangeListener *dcl)
static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
bool skipauth, bool websocket)
{
- VncState *vs = g_new0(VncState, 1);
+ VncConnection *vc = g_new0(VncConnection, 1);
+ VncState *vs = &vc->vs;
bool first_client = QTAILQ_EMPTY(&vd->clients);
- int i;
trace_vnc_client_connect(vs, sioc);
- vs->zrle = g_new0(VncZrle, 1);
- vs->tight = g_new0(VncTight, 1);
vs->magic = VNC_MAGIC;
vs->sioc = sioc;
object_ref(OBJECT(vs->sioc));
@@ -3255,23 +3249,23 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
object_ref(OBJECT(vs->ioc));
vs->vd = vd;
- buffer_init(&vs->input, "vnc-input/%p", sioc);
- buffer_init(&vs->output, "vnc-output/%p", sioc);
- buffer_init(&vs->jobs_buffer, "vnc-jobs_buffer/%p", sioc);
+ buffer_init(&vs->input, "vnc-input/%p", sioc);
+ buffer_init(&vs->output, "vnc-output/%p", sioc);
+ buffer_init(&vs->jobs_buffer, "vnc-jobs_buffer/%p", sioc);
- buffer_init(&vs->tight->tight, "vnc-tight/%p", sioc);
- buffer_init(&vs->tight->zlib, "vnc-tight-zlib/%p", sioc);
- buffer_init(&vs->tight->gradient, "vnc-tight-gradient/%p", sioc);
+ buffer_init(&vc->worker.tight.tight, "vnc-tight/%p", sioc);
+ buffer_init(&vc->worker.tight.zlib, "vnc-tight-zlib/%p", sioc);
+ buffer_init(&vc->worker.tight.gradient, "vnc-tight-gradient/%p", sioc);
#ifdef CONFIG_VNC_JPEG
- buffer_init(&vs->tight->jpeg, "vnc-tight-jpeg/%p", sioc);
+ buffer_init(&vc->worker.tight.jpeg, "vnc-tight-jpeg/%p", sioc);
#endif
#ifdef CONFIG_PNG
- buffer_init(&vs->tight->png, "vnc-tight-png/%p", sioc);
+ buffer_init(&vc->worker.tight.png, "vnc-tight-png/%p", sioc);
#endif
- buffer_init(&vs->zlib.zlib, "vnc-zlib/%p", sioc);
- buffer_init(&vs->zrle->zrle, "vnc-zrle/%p", sioc);
- buffer_init(&vs->zrle->fb, "vnc-zrle-fb/%p", sioc);
- buffer_init(&vs->zrle->zlib, "vnc-zrle-zlib/%p", sioc);
+ buffer_init(&vc->worker.zlib.zlib, "vnc-zlib/%p", sioc);
+ buffer_init(&vc->worker.zrle.zrle, "vnc-zrle/%p", sioc);
+ buffer_init(&vc->worker.zrle.fb, "vnc-zrle-fb/%p", sioc);
+ buffer_init(&vc->worker.zrle.zlib, "vnc-zrle-zlib/%p", sioc);
if (skipauth) {
vs->auth = VNC_AUTH_NONE;
@@ -3288,11 +3282,6 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
VNC_DEBUG("Client sioc=%p ws=%d auth=%d subauth=%d\n",
sioc, websocket, vs->auth, vs->subauth);
- vs->lossy_rect = g_malloc0(VNC_STAT_ROWS * sizeof (*vs->lossy_rect));
- for (i = 0; i < VNC_STAT_ROWS; ++i) {
- vs->lossy_rect[i] = g_new0(uint8_t, VNC_STAT_COLS);
- }
-
VNC_DEBUG("New client on socket %p\n", vs->sioc);
update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
qio_channel_set_blocking(vs->ioc, false, NULL);
diff --git a/ui/vnc.h b/ui/vnc.h
index b3e0726..f2dab2f 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -272,8 +272,6 @@ struct VncState
gboolean disconnecting;
DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT], VNC_DIRTY_BITS);
- uint8_t **lossy_rect; /* Not an Array to avoid costly memcpy in
- * vnc-jobs-async.c */
VncDisplay *vd;
VncStateUpdate update; /* Most recent pending request from client */
@@ -341,10 +339,7 @@ struct VncState
/* Encoding specific, if you add something here, don't forget to
* update vnc_async_encoding_start()
*/
- VncTight *tight;
- VncZlib zlib;
VncHextile hextile;
- VncZrle *zrle;
VncZywrle zywrle;
Notifier mouse_mode_notifier;
@@ -356,6 +351,19 @@ struct VncState
QTAILQ_ENTRY(VncState) next;
};
+typedef struct VncWorker {
+ uint8_t lossy_rect[VNC_STAT_ROWS][VNC_STAT_COLS];
+
+ VncTight tight;
+ VncZlib zlib;
+ VncZrle zrle;
+} VncWorker;
+
+typedef struct VncConnection {
+ VncState vs;
+ VncWorker worker;
+} VncConnection;
+
/*****************************************************************************
*
@@ -602,10 +610,11 @@ int vnc_server_fb_stride(VncDisplay *vd);
void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v);
double vnc_update_freq(VncState *vs, int x, int y, int w, int h);
-void vnc_sent_lossy_rect(VncState *vs, int x, int y, int w, int h);
+void vnc_sent_lossy_rect(VncWorker *worker, int x, int y, int w, int h);
/* Encodings */
-int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
+int vnc_send_framebuffer_update(VncState *vs, VncWorker *worker,
+ int x, int y, int w, int h);
int vnc_raw_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
@@ -615,17 +624,21 @@ void vnc_hextile_set_pixel_conversion(VncState *vs, int generic);
void *vnc_zlib_zalloc(void *x, unsigned items, unsigned size);
void vnc_zlib_zfree(void *x, void *addr);
-int vnc_zlib_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
-void vnc_zlib_clear(VncState *vs);
-
-int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
-int vnc_tight_png_send_framebuffer_update(VncState *vs, int x, int y,
- int w, int h);
-void vnc_tight_clear(VncState *vs);
-
-int vnc_zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
-int vnc_zywrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
-void vnc_zrle_clear(VncState *vs);
+int vnc_zlib_send_framebuffer_update(VncState *vs, VncWorker *worker,
+ int x, int y, int w, int h);
+void vnc_zlib_clear(VncWorker *worker);
+
+int vnc_tight_send_framebuffer_update(VncState *vs, VncWorker *worker,
+ int x, int y, int w, int h);
+int vnc_tight_png_send_framebuffer_update(VncState *vs, VncWorker *worker,
+ int x, int y, int w, int h);
+void vnc_tight_clear(VncWorker *worker);
+
+int vnc_zrle_send_framebuffer_update(VncState *vs, VncWorker *worker,
+ int x, int y, int w, int h);
+int vnc_zywrle_send_framebuffer_update(VncState *vs, VncWorker *worker,
+ int x, int y, int w, int h);
+void vnc_zrle_clear(VncWorker *worker);
/* vnc-clipboard.c */
void vnc_server_cut_text_caps(VncState *vs);